1 /* $NetBSD: privsep.c,v 1.28 2025/03/08 16:39:08 christos Exp $ */
2
3 /* Id: privsep.c,v 1.15 2005/08/08 11:23:44 vanhu Exp */
4
5 /*
6 * Copyright (C) 2004 Emmanuel Dreyfus
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "config.h"
35
36 #include <unistd.h>
37 #include <string.h>
38 #ifdef __NetBSD__
39 #include <stdlib.h> /* for setproctitle */
40 #endif
41 #include <errno.h>
42 #include <signal.h>
43 #include <pwd.h>
44
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <sys/param.h>
48
49 #include <netinet/in.h>
50
51 #include "gcmalloc.h"
52 #include "vmbuf.h"
53 #include "misc.h"
54 #include "plog.h"
55 #include "var.h"
56
57 #include "crypto_openssl.h"
58 #include "isakmp_var.h"
59 #include "isakmp.h"
60 #ifdef ENABLE_HYBRID
61 #include "resolv.h"
62 #include "isakmp_xauth.h"
63 #include "isakmp_cfg.h"
64 #endif
65 #include "localconf.h"
66 #include "remoteconf.h"
67 #include "admin.h"
68 #include "sockmisc.h"
69 #include "privsep.h"
70 #include "session.h"
71
72 static int privsep_sock[2] = { -1, -1 };
73
74 static int privsep_recv(int, struct privsep_com_msg **, size_t *);
75 static int privsep_send(int, struct privsep_com_msg *, size_t);
76 static int safety_check(struct privsep_com_msg *, int);
77 static int port_check(int);
78 static int unsafe_env(char *const *);
79 static int unknown_name(int);
80 static int unsafe_path(char *, int);
81 static int rec_fd(int);
82 static int send_fd(int, int);
83
84 struct socket_args {
85 int domain;
86 int type;
87 int protocol;
88 };
89
90 struct sockopt_args {
91 int s;
92 int level;
93 int optname;
94 const void *optval;
95 socklen_t optlen;
96 };
97
98 struct bind_args {
99 int s;
100 const struct sockaddr *addr;
101 socklen_t addrlen;
102 };
103
104 static int
privsep_send(int sock,struct privsep_com_msg * buf,size_t len)105 privsep_send(int sock, struct privsep_com_msg *buf, size_t len)
106 {
107 if (buf == NULL)
108 return 0;
109
110 if (sendto(sock, (char *)buf, len, 0, NULL, 0) == -1) {
111 plog(LLV_ERROR, LOCATION, NULL,
112 "privsep_send failed: %s\n",
113 strerror(errno));
114 return -1;
115 }
116
117 racoon_free((char *)buf);
118
119 return 0;
120 }
121
122
123 static int
privsep_recv(int sock,struct privsep_com_msg ** bufp,size_t * lenp)124 privsep_recv(int sock, struct privsep_com_msg **bufp, size_t *lenp)
125 {
126 struct admin_com com;
127 struct admin_com *combuf;
128 ssize_t len;
129
130 *bufp = NULL;
131 *lenp = 0;
132
133 /* Get the header */
134 while ((len = recvfrom(sock, (char *)&com,
135 sizeof(com), MSG_PEEK, NULL, NULL)) == -1) {
136 if (errno == EINTR)
137 continue;
138 if (errno == ECONNRESET)
139 return -1;
140
141 plog(LLV_ERROR, LOCATION, NULL,
142 "privsep_recv failed: %s\n",
143 strerror(errno));
144 return -1;
145 }
146
147 /* EOF, other side has closed. */
148 if (len == 0)
149 return -1;
150
151 /* Check for short packets */
152 if (len < sizeof(com)) {
153 plog(LLV_ERROR, LOCATION, NULL,
154 "corrupted privsep message (short header)\n");
155 return -1;
156 }
157
158 /* Allocate buffer for the whole message */
159 if ((combuf = (struct admin_com *)racoon_malloc(com.ac_len)) == NULL) {
160 plog(LLV_ERROR, LOCATION, NULL,
161 "failed to allocate memory: %s\n", strerror(errno));
162 return -1;
163 }
164
165 /* Get the whole buffer */
166 while ((len = recvfrom(sock, (char *)combuf,
167 com.ac_len, 0, NULL, NULL)) == -1) {
168 if (errno == EINTR)
169 continue;
170 if (errno == ECONNRESET)
171 return -1;
172 plog(LLV_ERROR, LOCATION, NULL,
173 "failed to recv privsep command: %s\n",
174 strerror(errno));
175 return -1;
176 }
177
178 /* We expect len to match */
179 if (len != com.ac_len) {
180 plog(LLV_ERROR, LOCATION, NULL,
181 "corrupted privsep message (short packet)\n");
182 return -1;
183 }
184
185 *bufp = (struct privsep_com_msg *)combuf;
186 *lenp = len;
187
188 return 0;
189 }
190
191 /*ARGSUSED*/
192 static int
privsep_do_exit(void * ctx __unused,int fd __unused)193 privsep_do_exit(void *ctx __unused, int fd __unused)
194 {
195 kill(getpid(), SIGTERM);
196 return 0;
197 }
198
199 int
privsep_init(void)200 privsep_init(void)
201 {
202 long sc;
203 pid_t child_pid;
204
205 /* If running as root, we don't use the privsep code path */
206 if (lcconf->uid == 0)
207 return 0;
208
209 /*
210 * When running privsep, certificate and script paths
211 * are mandatory, as they enable us to check path safety
212 * in the privileged instance
213 */
214 if ((lcconf->pathinfo[LC_PATHTYPE_CERT] == NULL) ||
215 (lcconf->pathinfo[LC_PATHTYPE_SCRIPT] == NULL)) {
216 plog(LLV_ERROR, LOCATION, NULL, "privilege separation "
217 "require path cert and path script in the config file\n");
218 return -1;
219 }
220
221 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, privsep_sock) != 0) {
222 plog(LLV_ERROR, LOCATION, NULL,
223 "Cannot allocate privsep_sock: %s\n", strerror(errno));
224 return -1;
225 }
226
227 switch (child_pid = fork()) {
228 case -1:
229 plog(LLV_ERROR, LOCATION, NULL, "Cannot fork privsep: %s\n",
230 strerror(errno));
231 return -1;
232
233 case 0: /* Child: drop privileges */
234 (void)close(privsep_sock[0]);
235
236 if (lcconf->chroot != NULL) {
237 if (chdir(lcconf->chroot) != 0) {
238 plog(LLV_ERROR, LOCATION, NULL,
239 "Cannot chdir(%s): %s\n", lcconf->chroot,
240 strerror(errno));
241 return -1;
242 }
243 if (chroot(lcconf->chroot) != 0) {
244 plog(LLV_ERROR, LOCATION, NULL,
245 "Cannot chroot(%s): %s\n", lcconf->chroot,
246 strerror(errno));
247 return -1;
248 }
249 }
250
251 if (setgid(lcconf->gid) != 0) {
252 plog(LLV_ERROR, LOCATION, NULL,
253 "Cannot setgid(%d): %s\n", lcconf->gid,
254 strerror(errno));
255 return -1;
256 }
257
258 if (setegid(lcconf->gid) != 0) {
259 plog(LLV_ERROR, LOCATION, NULL,
260 "Cannot setegid(%d): %s\n", lcconf->gid,
261 strerror(errno));
262 return -1;
263 }
264
265 if (setuid(lcconf->uid) != 0) {
266 plog(LLV_ERROR, LOCATION, NULL,
267 "Cannot setuid(%d): %s\n", lcconf->uid,
268 strerror(errno));
269 return -1;
270 }
271
272 if (seteuid(lcconf->uid) != 0) {
273 plog(LLV_ERROR, LOCATION, NULL,
274 "Cannot seteuid(%d): %s\n", lcconf->uid,
275 strerror(errno));
276 return -1;
277 }
278 monitor_fd(privsep_sock[1], privsep_do_exit, NULL, 0);
279
280 return 0;
281
282 default: /* Parent: privileged process */
283 break;
284 }
285
286 /*
287 * Close everything except the socketpair,
288 * and stdout if running in the forground.
289 */
290 for (sc = sysconf(_SC_OPEN_MAX); sc > 0; sc--) {
291 if (sc == privsep_sock[0])
292 continue;
293 if ((f_foreground) && (sc == 1))
294 continue;
295 (void)close((int)sc);
296 }
297
298 /* Above trickery closed the log file, reopen it */
299 ploginit();
300
301 plog(LLV_INFO, LOCATION, NULL,
302 "racoon privileged process running with PID %d\n", getpid());
303
304 plog(LLV_INFO, LOCATION, NULL,
305 "racoon unprivileged process running with PID %d\n", child_pid);
306
307 #if defined(__NetBSD__) || defined(__FreeBSD__)
308 setproctitle("[priv]");
309 #endif
310
311 /*
312 * Don't catch any signal
313 * This duplicate session:signals[], which is static...
314 */
315 signal(SIGPIPE, SIG_IGN);
316 signal(SIGHUP, SIG_DFL);
317 signal(SIGINT, SIG_DFL);
318 signal(SIGTERM, SIG_DFL);
319 signal(SIGUSR1, SIG_DFL);
320 signal(SIGUSR2, SIG_DFL);
321 signal(SIGCHLD, SIG_DFL);
322
323 for (;;) {
324 size_t len;
325 struct privsep_com_msg *combuf;
326 struct privsep_com_msg *reply;
327 char *data;
328 size_t totallen;
329 char *bufs[PRIVSEP_NBUF_MAX];
330 int i;
331
332 if (privsep_recv(privsep_sock[0], &combuf, &len) != 0)
333 goto out;
334
335 /* Safety checks and gather the data */
336 if (len < sizeof(*combuf)) {
337 plog(LLV_ERROR, LOCATION, NULL,
338 "corrupted privsep message (short buflen)\n");
339 goto out;
340 }
341
342 data = (char *)(combuf + 1);
343 totallen = sizeof(*combuf);
344 for (i = 0; i < PRIVSEP_NBUF_MAX; i++) {
345 bufs[i] = (char *)data;
346 data += combuf->bufs.buflen[i];
347 totallen += combuf->bufs.buflen[i];
348 }
349
350 if (totallen > len) {
351 plog(LLV_ERROR, LOCATION, NULL,
352 "corrupted privsep message (bufs too big)\n");
353 goto out;
354 }
355
356 /* Prepare the reply buffer */
357 if ((reply = racoon_malloc(sizeof(*reply))) == NULL) {
358 plog(LLV_ERROR, LOCATION, NULL,
359 "Cannot allocate reply buffer: %s\n",
360 strerror(errno));
361 goto out;
362 }
363 bzero(reply, sizeof(*reply));
364 reply->hdr.ac_cmd = combuf->hdr.ac_cmd;
365 reply->hdr.ac_len = sizeof(*reply);
366
367 switch(combuf->hdr.ac_cmd) {
368 /*
369 * XXX Improvement: instead of returning the key,
370 * stuff eay_get_pkcs1privkey and eay_get_x509sign
371 * together and sign the hash in the privileged
372 * instance?
373 * pro: the key remains inaccessible to unpriv
374 * con: a compromised unpriv racoon can still sign anything
375 */
376 case PRIVSEP_EAY_GET_PKCS1PRIVKEY: {
377 vchar_t *privkey;
378
379 /* Make sure the string is NULL terminated */
380 if (safety_check(combuf, 0) != 0)
381 break;
382 bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
383
384 if (unsafe_path(bufs[0], LC_PATHTYPE_CERT) != 0) {
385 plog(LLV_ERROR, LOCATION, NULL,
386 "privsep_eay_get_pkcs1privkey: "
387 "unsafe cert \"%s\"\n", bufs[0]);
388 }
389
390 plog(LLV_DEBUG, LOCATION, NULL,
391 "eay_get_pkcs1privkey(\"%s\")\n", bufs[0]);
392
393 if ((privkey = eay_get_pkcs1privkey(bufs[0])) == NULL){
394 reply->hdr.ac_errno = errno;
395 break;
396 }
397
398 reply->bufs.buflen[0] = privkey->l;
399 reply->hdr.ac_len = sizeof(*reply) + privkey->l;
400 reply = racoon_realloc(reply, reply->hdr.ac_len);
401 if (reply == NULL) {
402 plog(LLV_ERROR, LOCATION, NULL,
403 "Cannot allocate reply buffer: %s\n",
404 strerror(errno));
405 goto out;
406 }
407
408 memcpy(reply + 1, privkey->v, privkey->l);
409 vfree(privkey);
410 break;
411 }
412
413 case PRIVSEP_SCRIPT_EXEC: {
414 char *script;
415 int name;
416 char **envp = NULL;
417 int envc = 0;
418 int count = 0;
419 int j;
420
421 /*
422 * First count the bufs, and make sure strings
423 * are NULL terminated.
424 *
425 * We expect: script, name, envp[], void
426 */
427 if (safety_check(combuf, 0) != 0)
428 break;
429 bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
430 count++; /* script */
431
432 count++; /* name */
433
434 for (; count < PRIVSEP_NBUF_MAX; count++) {
435 if (combuf->bufs.buflen[count] == 0)
436 break;
437 bufs[count]
438 [combuf->bufs.buflen[count] - 1] = '\0';
439 envc++;
440 }
441
442 /* count a void buf and perform safety check */
443 count++;
444 if (count >= PRIVSEP_NBUF_MAX) {
445 plog(LLV_ERROR, LOCATION, NULL,
446 "privsep_script_exec: too many args\n");
447 goto out;
448 }
449
450
451 /*
452 * Allocate the arrays for envp
453 */
454 envp = racoon_malloc((envc + 1) * sizeof(char *));
455 if (envp == NULL) {
456 plog(LLV_ERROR, LOCATION, NULL,
457 "cannot allocate memory: %s\n",
458 strerror(errno));
459 goto out;
460 }
461 bzero(envp, (envc + 1) * sizeof(char *));
462
463
464 /*
465 * Populate script, name and envp
466 */
467 count = 0;
468 script = bufs[count++];
469
470 if (combuf->bufs.buflen[count] != sizeof(name)) {
471 plog(LLV_ERROR, LOCATION, NULL,
472 "privsep_script_exec: corrupted message\n");
473 goto out;
474 }
475 memcpy((char *)&name, bufs[count++], sizeof(name));
476
477 for (j = 0; combuf->bufs.buflen[count]; count++)
478 envp[j++] = bufs[count];
479
480 count++; /* void */
481
482 plog(LLV_DEBUG, LOCATION, NULL,
483 "script_exec(\"%s\", %d, %p)\n",
484 script, name, envp);
485
486 /*
487 * Check env for dangerous variables
488 * Check script path and name
489 * Perform fork and execve
490 */
491 if ((unsafe_env(envp) == 0) &&
492 (unknown_name(name) == 0) &&
493 (unsafe_path(script, LC_PATHTYPE_SCRIPT) == 0))
494 (void)script_exec(script, name, envp);
495 else
496 plog(LLV_ERROR, LOCATION, NULL,
497 "privsep_script_exec: "
498 "unsafe script \"%s\"\n", script);
499
500 racoon_free(envp);
501 break;
502 }
503
504 case PRIVSEP_GETPSK: {
505 vchar_t *psk;
506 int keylen;
507
508 /* Make sure the string is NULL terminated */
509 if (safety_check(combuf, 0) != 0)
510 break;
511 bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
512
513 if (combuf->bufs.buflen[1] != sizeof(keylen)) {
514 plog(LLV_ERROR, LOCATION, NULL,
515 "privsep_getpsk: corrupted message\n");
516 goto out;
517 }
518 memcpy(&keylen, bufs[1], sizeof(keylen));
519
520 plog(LLV_DEBUG, LOCATION, NULL,
521 "getpsk(\"%s\", %d)\n", bufs[0], keylen);
522
523 if ((psk = getpsk(bufs[0], keylen)) == NULL) {
524 reply->hdr.ac_errno = errno;
525 break;
526 }
527
528 reply->bufs.buflen[0] = psk->l;
529 reply->hdr.ac_len = sizeof(*reply) + psk->l;
530 reply = racoon_realloc(reply, reply->hdr.ac_len);
531 if (reply == NULL) {
532 plog(LLV_ERROR, LOCATION, NULL,
533 "Cannot allocate reply buffer: %s\n",
534 strerror(errno));
535 goto out;
536 }
537
538 memcpy(reply + 1, psk->v, psk->l);
539 vfree(psk);
540 break;
541 }
542
543 case PRIVSEP_SOCKET: {
544 struct socket_args socket_args;
545 int s;
546
547 /* Make sure the string is NULL terminated */
548 if (safety_check(combuf, 0) != 0)
549 break;
550
551 if (combuf->bufs.buflen[0] !=
552 sizeof(struct socket_args)) {
553 plog(LLV_ERROR, LOCATION, NULL,
554 "privsep_socket: corrupted message\n");
555 goto out;
556 }
557 memcpy(&socket_args, bufs[0],
558 sizeof(struct socket_args));
559
560 if (socket_args.domain != PF_INET &&
561 socket_args.domain != PF_INET6) {
562 plog(LLV_ERROR, LOCATION, NULL,
563 "privsep_socket: "
564 "unauthorized domain (%d)\n",
565 socket_args.domain);
566 goto out;
567 }
568
569 if ((s = socket(socket_args.domain, socket_args.type,
570 socket_args.protocol)) == -1) {
571 reply->hdr.ac_errno = errno;
572 break;
573 }
574
575 if (send_fd(privsep_sock[0], s) < 0) {
576 plog(LLV_ERROR, LOCATION, NULL,
577 "privsep_socket: send_fd failed\n");
578 close(s);
579 goto out;
580 }
581
582 close(s);
583 break;
584 }
585
586 case PRIVSEP_BIND: {
587 struct bind_args bind_args;
588 int err, port = 0;
589
590 /* Make sure the string is NULL terminated */
591 if (safety_check(combuf, 0) != 0)
592 break;
593
594 if (combuf->bufs.buflen[0] !=
595 sizeof(struct bind_args)) {
596 plog(LLV_ERROR, LOCATION, NULL,
597 "privsep_bind: corrupted message\n");
598 goto out;
599 }
600 memcpy(&bind_args, bufs[0], sizeof(struct bind_args));
601
602 if (combuf->bufs.buflen[1] != bind_args.addrlen) {
603 plog(LLV_ERROR, LOCATION, NULL,
604 "privsep_bind: corrupted message\n");
605 goto out;
606 }
607 bind_args.addr = (const struct sockaddr *)bufs[1];
608
609 if ((bind_args.s = rec_fd(privsep_sock[0])) < 0) {
610 plog(LLV_ERROR, LOCATION, NULL,
611 "privsep_bind: rec_fd failed\n");
612 goto out;
613 }
614
615 port = extract_port(bind_args.addr);
616 if (port != PORT_ISAKMP && port != PORT_ISAKMP_NATT &&
617 port != lcconf->port_isakmp &&
618 port != lcconf->port_isakmp_natt) {
619 plog(LLV_ERROR, LOCATION, NULL,
620 "privsep_bind: "
621 "unauthorized port (%d)\n",
622 port);
623 close(bind_args.s);
624 goto out;
625 }
626
627 err = bind(bind_args.s, bind_args.addr,
628 bind_args.addrlen);
629
630 if (err)
631 reply->hdr.ac_errno = errno;
632
633 close(bind_args.s);
634 break;
635 }
636
637 case PRIVSEP_SETSOCKOPTS: {
638 struct sockopt_args sockopt_args;
639 int err;
640
641 /* Make sure the string is NULL terminated */
642 if (safety_check(combuf, 0) != 0)
643 break;
644
645 if (combuf->bufs.buflen[0] !=
646 sizeof(struct sockopt_args)) {
647 plog(LLV_ERROR, LOCATION, NULL,
648 "privsep_setsockopt: "
649 "corrupted message\n");
650 goto out;
651 }
652 memcpy(&sockopt_args, bufs[0],
653 sizeof(struct sockopt_args));
654
655 if (combuf->bufs.buflen[1] != sockopt_args.optlen) {
656 plog(LLV_ERROR, LOCATION, NULL,
657 "privsep_setsockopt: corrupted message\n");
658 goto out;
659 }
660 sockopt_args.optval = bufs[1];
661
662 if (sockopt_args.optname !=
663 (sockopt_args.level ==
664 IPPROTO_IP ? IP_IPSEC_POLICY :
665 IPV6_IPSEC_POLICY)) {
666 plog(LLV_ERROR, LOCATION, NULL,
667 "privsep_setsockopt: "
668 "unauthorized option (%d)\n",
669 sockopt_args.optname);
670 goto out;
671 }
672
673 if ((sockopt_args.s = rec_fd(privsep_sock[0])) < 0) {
674 plog(LLV_ERROR, LOCATION, NULL,
675 "privsep_setsockopt: rec_fd failed\n");
676 goto out;
677 }
678
679 err = setsockopt(sockopt_args.s,
680 sockopt_args.level,
681 sockopt_args.optname,
682 sockopt_args.optval,
683 sockopt_args.optlen);
684 if (err)
685 reply->hdr.ac_errno = errno;
686
687 close(sockopt_args.s);
688 break;
689 }
690
691 #ifdef ENABLE_HYBRID
692 case PRIVSEP_ACCOUNTING_SYSTEM: {
693 int port;
694 int inout;
695 struct sockaddr *raddr;
696
697 if (safety_check(combuf, 0) != 0)
698 break;
699 if (safety_check(combuf, 1) != 0)
700 break;
701 if (safety_check(combuf, 2) != 0)
702 break;
703 if (safety_check(combuf, 3) != 0)
704 break;
705
706 memcpy(&port, bufs[0], sizeof(port));
707 raddr = (struct sockaddr *)bufs[1];
708
709 bufs[2][combuf->bufs.buflen[2] - 1] = '\0';
710 memcpy(&inout, bufs[3], sizeof(port));
711
712 if (port_check(port) != 0)
713 break;
714
715 plog(LLV_DEBUG, LOCATION, NULL,
716 "accounting_system(%d, %s, %s)\n",
717 port, saddr2str(raddr), bufs[2]);
718
719 errno = 0;
720 if (isakmp_cfg_accounting_system(port,
721 raddr, bufs[2], inout) != 0) {
722 if (errno == 0)
723 reply->hdr.ac_errno = EINVAL;
724 else
725 reply->hdr.ac_errno = errno;
726 }
727 break;
728 }
729 case PRIVSEP_XAUTH_LOGIN_SYSTEM: {
730 if (safety_check(combuf, 0) != 0)
731 break;
732 bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
733
734 if (safety_check(combuf, 1) != 0)
735 break;
736 bufs[1][combuf->bufs.buflen[1] - 1] = '\0';
737
738 plog(LLV_DEBUG, LOCATION, NULL,
739 "xauth_login_system(\"%s\", <password>)\n",
740 bufs[0]);
741
742 errno = 0;
743 if (xauth_login_system(bufs[0], bufs[1]) != 0) {
744 if (errno == 0)
745 reply->hdr.ac_errno = EINVAL;
746 else
747 reply->hdr.ac_errno = errno;
748 }
749 break;
750 }
751 #ifdef HAVE_LIBPAM
752 case PRIVSEP_ACCOUNTING_PAM: {
753 int port;
754 int inout;
755 int pool_size;
756
757 if (safety_check(combuf, 0) != 0)
758 break;
759 if (safety_check(combuf, 1) != 0)
760 break;
761 if (safety_check(combuf, 2) != 0)
762 break;
763
764 memcpy(&port, bufs[0], sizeof(port));
765 memcpy(&inout, bufs[1], sizeof(inout));
766 memcpy(&pool_size, bufs[2], sizeof(pool_size));
767
768 if (pool_size != isakmp_cfg_config.pool_size)
769 if (isakmp_cfg_resize_pool(pool_size) != 0)
770 break;
771
772 if (port_check(port) != 0)
773 break;
774
775 plog(LLV_DEBUG, LOCATION, NULL,
776 "isakmp_cfg_accounting_pam(%d, %d)\n",
777 port, inout);
778
779 errno = 0;
780 if (isakmp_cfg_accounting_pam(port, inout) != 0) {
781 if (errno == 0)
782 reply->hdr.ac_errno = EINVAL;
783 else
784 reply->hdr.ac_errno = errno;
785 }
786 break;
787 }
788
789 case PRIVSEP_XAUTH_LOGIN_PAM: {
790 int port;
791 int pool_size;
792 struct sockaddr *raddr;
793
794 if (safety_check(combuf, 0) != 0)
795 break;
796 if (safety_check(combuf, 1) != 0)
797 break;
798 if (safety_check(combuf, 2) != 0)
799 break;
800 if (safety_check(combuf, 3) != 0)
801 break;
802 if (safety_check(combuf, 4) != 0)
803 break;
804
805 memcpy(&port, bufs[0], sizeof(port));
806 memcpy(&pool_size, bufs[1], sizeof(pool_size));
807 raddr = (struct sockaddr *)bufs[2];
808
809 bufs[3][combuf->bufs.buflen[3] - 1] = '\0';
810 bufs[4][combuf->bufs.buflen[4] - 1] = '\0';
811
812 if (pool_size != isakmp_cfg_config.pool_size)
813 if (isakmp_cfg_resize_pool(pool_size) != 0)
814 break;
815
816 if (port_check(port) != 0)
817 break;
818
819 plog(LLV_DEBUG, LOCATION, NULL,
820 "xauth_login_pam(%d, %s, \"%s\", <password>)\n",
821 port, saddr2str(raddr), bufs[3]);
822
823 errno = 0;
824 if (xauth_login_pam(port,
825 raddr, bufs[3], bufs[4]) != 0) {
826 if (errno == 0)
827 reply->hdr.ac_errno = EINVAL;
828 else
829 reply->hdr.ac_errno = errno;
830 }
831 break;
832 }
833
834 case PRIVSEP_CLEANUP_PAM: {
835 int port;
836 int pool_size;
837
838 if (safety_check(combuf, 0) != 0)
839 break;
840 if (safety_check(combuf, 1) != 0)
841 break;
842
843 memcpy(&port, bufs[0], sizeof(port));
844 memcpy(&pool_size, bufs[1], sizeof(pool_size));
845
846 if (pool_size != isakmp_cfg_config.pool_size)
847 if (isakmp_cfg_resize_pool(pool_size) != 0)
848 break;
849
850 if (port_check(port) != 0)
851 break;
852
853 plog(LLV_DEBUG, LOCATION, NULL,
854 "cleanup_pam(%d)\n", port);
855
856 cleanup_pam(port);
857 reply->hdr.ac_errno = 0;
858
859 break;
860 }
861 #endif /* HAVE_LIBPAM */
862 #endif /* ENABLE_HYBRID */
863
864 default:
865 plog(LLV_ERROR, LOCATION, NULL,
866 "unexpected privsep command %d\n",
867 combuf->hdr.ac_cmd);
868 goto out;
869 }
870
871 /* This frees reply */
872 if (privsep_send(privsep_sock[0],
873 reply, reply->hdr.ac_len) != 0) {
874 racoon_free(reply);
875 goto out;
876 }
877
878 racoon_free(combuf);
879 }
880
881 out:
882 plog(LLV_INFO, LOCATION, NULL,
883 "racoon privileged process %d terminated\n", getpid());
884 _exit(0);
885 }
886
887
888 vchar_t *
privsep_eay_get_pkcs1privkey(char * path)889 privsep_eay_get_pkcs1privkey(char *path)
890 {
891 vchar_t *privkey;
892 struct privsep_com_msg *msg;
893 size_t len;
894
895 if (geteuid() == 0)
896 return eay_get_pkcs1privkey(path);
897
898 len = sizeof(*msg) + strlen(path) + 1;
899 if ((msg = racoon_malloc(len)) == NULL) {
900 plog(LLV_ERROR, LOCATION, NULL,
901 "Cannot allocate memory: %s\n", strerror(errno));
902 return NULL;
903 }
904 bzero(msg, len);
905 msg->hdr.ac_cmd = PRIVSEP_EAY_GET_PKCS1PRIVKEY;
906 msg->hdr.ac_len = len;
907 msg->bufs.buflen[0] = len - sizeof(*msg);
908 memcpy(msg + 1, path, msg->bufs.buflen[0]);
909
910 if (privsep_send(privsep_sock[1], msg, len) != 0)
911 goto out;
912
913 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
914 return NULL;
915
916 if (msg->hdr.ac_errno != 0) {
917 errno = msg->hdr.ac_errno;
918 goto out;
919 }
920
921 if ((privkey = vmalloc(len - sizeof(*msg))) == NULL)
922 goto out;
923
924 memcpy(privkey->v, msg + 1, privkey->l);
925 racoon_free(msg);
926 return privkey;
927
928 out:
929 racoon_free(msg);
930 return NULL;
931 }
932
933 int
privsep_script_exec(char * script,int name,char * const envp[])934 privsep_script_exec(char *script, int name, char *const envp[])
935 {
936 int count = 0;
937 char *const *c;
938 char *data;
939 size_t len;
940 struct privsep_com_msg *msg;
941
942 if (geteuid() == 0)
943 return script_exec(script, name, envp);
944
945 if ((msg = racoon_malloc(sizeof(*msg))) == NULL) {
946 plog(LLV_ERROR, LOCATION, NULL,
947 "Cannot allocate memory: %s\n", strerror(errno));
948 return -1;
949 }
950
951 bzero(msg, sizeof(*msg));
952 msg->hdr.ac_cmd = PRIVSEP_SCRIPT_EXEC;
953 msg->hdr.ac_len = sizeof(*msg);
954
955 /*
956 * We send:
957 * script, name, envp[0], ... envp[N], void
958 */
959
960 /*
961 * Safety check on the counts: PRIVSEP_NBUF_MAX max
962 */
963 count = 0;
964 count++; /* script */
965 count++; /* name */
966 for (c = envp; *c; c++) /* envp */
967 count++;
968 count++; /* void */
969
970 if (count > PRIVSEP_NBUF_MAX) {
971 plog(LLV_ERROR, LOCATION, NULL, "Unexpected error: "
972 "privsep_script_exec count > PRIVSEP_NBUF_MAX\n");
973 racoon_free(msg);
974 return -1;
975 }
976
977
978 /*
979 * Compute the length
980 */
981 count = 0;
982 msg->bufs.buflen[count] = strlen(script) + 1; /* script */
983 msg->hdr.ac_len += msg->bufs.buflen[count++];
984
985 msg->bufs.buflen[count] = sizeof(name); /* name */
986 msg->hdr.ac_len += msg->bufs.buflen[count++];
987
988 for (c = envp; *c; c++) { /* envp */
989 msg->bufs.buflen[count] = strlen(*c) + 1;
990 msg->hdr.ac_len += msg->bufs.buflen[count++];
991 }
992
993 msg->bufs.buflen[count] = 0; /* void */
994 msg->hdr.ac_len += msg->bufs.buflen[count++];
995
996 if ((msg = racoon_realloc(msg, msg->hdr.ac_len)) == NULL) {
997 plog(LLV_ERROR, LOCATION, NULL,
998 "Cannot allocate memory: %s\n", strerror(errno));
999 return -1;
1000 }
1001
1002 /*
1003 * Now copy the data
1004 */
1005 data = (char *)(msg + 1);
1006 count = 0;
1007
1008 memcpy(data, (char *)script, msg->bufs.buflen[count]); /* script */
1009 data += msg->bufs.buflen[count++];
1010
1011 memcpy(data, (char *)&name, msg->bufs.buflen[count]); /* name */
1012 data += msg->bufs.buflen[count++];
1013
1014 for (c = envp; *c; c++) { /* envp */
1015 memcpy(data, *c, msg->bufs.buflen[count]);
1016 data += msg->bufs.buflen[count++];
1017 }
1018
1019 count++; /* void */
1020
1021 /*
1022 * And send it!
1023 */
1024 if (privsep_send(privsep_sock[1], msg, msg->hdr.ac_len) != 0)
1025 goto out;
1026
1027 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1028 return -1;
1029
1030 if (msg->hdr.ac_errno != 0) {
1031 errno = msg->hdr.ac_errno;
1032 out:
1033 racoon_free(msg);
1034 return -1;
1035 }
1036
1037 racoon_free(msg);
1038 return 0;
1039 }
1040
1041 vchar_t *
privsep_getpsk(const char * str,int keylen)1042 privsep_getpsk(const char *str, int keylen)
1043 {
1044 vchar_t *psk;
1045 struct privsep_com_msg *msg;
1046 size_t len;
1047 char *data;
1048
1049 if (geteuid() == 0)
1050 return getpsk(str, keylen);
1051
1052 len = sizeof(*msg) + strlen(str) + 1 + sizeof(keylen);
1053 if ((msg = racoon_malloc(len)) == NULL) {
1054 plog(LLV_ERROR, LOCATION, NULL,
1055 "Cannot allocate memory: %s\n", strerror(errno));
1056 return NULL;
1057 }
1058 bzero(msg, len);
1059 msg->hdr.ac_cmd = PRIVSEP_GETPSK;
1060 msg->hdr.ac_len = len;
1061
1062 data = (char *)(msg + 1);
1063 msg->bufs.buflen[0] = strlen(str) + 1;
1064 memcpy(data, str, msg->bufs.buflen[0]);
1065
1066 data += msg->bufs.buflen[0];
1067 msg->bufs.buflen[1] = sizeof(keylen);
1068 memcpy(data, &keylen, sizeof(keylen));
1069
1070 if (privsep_send(privsep_sock[1], msg, len) != 0)
1071 goto out;
1072
1073 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1074 return NULL;
1075
1076 if (msg->hdr.ac_errno != 0) {
1077 errno = msg->hdr.ac_errno;
1078 goto out;
1079 }
1080
1081 if ((psk = vmalloc(len - sizeof(*msg))) == NULL)
1082 goto out;
1083
1084 memcpy(psk->v, msg + 1, psk->l);
1085 racoon_free(msg);
1086 return psk;
1087
1088 out:
1089 racoon_free(msg);
1090 return NULL;
1091 }
1092
1093 /*
1094 * Create a privileged socket. On BSD systems a socket obtains special
1095 * capabilities if it is created by root; setsockopt(IP_IPSEC_POLICY) will
1096 * succeed but will be ineffective if performed on an unprivileged socket.
1097 */
1098 int
privsep_socket(int domain,int type,int protocol)1099 privsep_socket(int domain, int type, int protocol)
1100 {
1101 struct privsep_com_msg *msg;
1102 size_t len;
1103 char *data;
1104 struct socket_args socket_args;
1105 int s;
1106
1107 if (geteuid() == 0)
1108 return socket(domain, type, protocol);
1109
1110 len = sizeof(*msg) + sizeof(socket_args);
1111
1112 if ((msg = racoon_malloc(len)) == NULL) {
1113 plog(LLV_ERROR, LOCATION, NULL,
1114 "Cannot allocate memory: %s\n", strerror(errno));
1115 return -1;
1116 }
1117 bzero(msg, len);
1118 msg->hdr.ac_cmd = PRIVSEP_SOCKET;
1119 msg->hdr.ac_len = len;
1120
1121 socket_args.domain = domain;
1122 socket_args.type = type;
1123 socket_args.protocol = protocol;
1124
1125 data = (char *)(msg + 1);
1126 msg->bufs.buflen[0] = sizeof(socket_args);
1127 memcpy(data, &socket_args, msg->bufs.buflen[0]);
1128
1129 /* frees msg */
1130 if (privsep_send(privsep_sock[1], msg, len) != 0)
1131 goto out;
1132
1133 /* Get the privileged socket descriptor from the privileged process. */
1134 if ((s = rec_fd(privsep_sock[1])) == -1)
1135 return -1;
1136
1137 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1138 goto out;
1139
1140 if (msg->hdr.ac_errno != 0) {
1141 errno = msg->hdr.ac_errno;
1142 goto out;
1143 }
1144
1145 racoon_free(msg);
1146 return s;
1147
1148 out:
1149 racoon_free(msg);
1150 return -1;
1151 }
1152
1153 /*
1154 * Bind() a socket to a port. This works just like regular bind(), except that
1155 * if you want to bind to the designated isakmp ports and you don't have the
1156 * privilege to do so, it will ask a privileged process to do it.
1157 */
1158 int
privsep_bind(int s,const struct sockaddr * addr,socklen_t addrlen)1159 privsep_bind(int s, const struct sockaddr *addr, socklen_t addrlen)
1160 {
1161 struct privsep_com_msg *msg;
1162 size_t len;
1163 char *data;
1164 struct bind_args bind_args;
1165 int err, saved_errno = 0;
1166
1167 err = bind(s, addr, addrlen);
1168 if ((err == 0) || (saved_errno = errno) != EACCES || geteuid() == 0) {
1169 if (saved_errno)
1170 plog(LLV_ERROR, LOCATION, NULL,
1171 "privsep_bind (%s) = %d\n", strerror(saved_errno), err);
1172 errno = saved_errno;
1173 return err;
1174 }
1175
1176 len = sizeof(*msg) + sizeof(bind_args) + addrlen;
1177
1178 if ((msg = racoon_malloc(len)) == NULL) {
1179 plog(LLV_ERROR, LOCATION, NULL,
1180 "Cannot allocate memory: %s\n", strerror(errno));
1181 return -1;
1182 }
1183 bzero(msg, len);
1184 msg->hdr.ac_cmd = PRIVSEP_BIND;
1185 msg->hdr.ac_len = len;
1186
1187 bind_args.s = -1;
1188 bind_args.addr = NULL;
1189 bind_args.addrlen = addrlen;
1190
1191 data = (char *)(msg + 1);
1192 msg->bufs.buflen[0] = sizeof(bind_args);
1193 memcpy(data, &bind_args, msg->bufs.buflen[0]);
1194
1195 data += msg->bufs.buflen[0];
1196 msg->bufs.buflen[1] = addrlen;
1197 memcpy(data, addr, addrlen);
1198
1199 /* frees msg */
1200 if (privsep_send(privsep_sock[1], msg, len) != 0)
1201 goto out;
1202
1203 /* Send the socket descriptor to the privileged process. */
1204 if (send_fd(privsep_sock[1], s) < 0)
1205 return -1;
1206
1207 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1208 goto out;
1209
1210 if (msg->hdr.ac_errno != 0) {
1211 errno = msg->hdr.ac_errno;
1212 goto out;
1213 }
1214
1215 racoon_free(msg);
1216 return 0;
1217
1218 out:
1219 racoon_free(msg);
1220 return -1;
1221 }
1222
1223 /*
1224 * Set socket options. This works just like regular setsockopt(), except that
1225 * if you want to change IP_IPSEC_POLICY or IPV6_IPSEC_POLICY and you don't
1226 * have the privilege to do so, it will ask a privileged process to do it.
1227 */
1228 int
privsep_setsockopt(int s,int level,int optname,const void * optval,socklen_t optlen)1229 privsep_setsockopt(int s, int level, int optname, const void *optval,
1230 socklen_t optlen)
1231 {
1232 struct privsep_com_msg *msg;
1233 size_t len;
1234 char *data;
1235 struct sockopt_args sockopt_args;
1236 int err, saved_errno = 0;
1237
1238 if ((err = setsockopt(s, level, optname, optval, optlen)) == 0 ||
1239 (saved_errno = errno) != EACCES ||
1240 geteuid() == 0) {
1241 if (saved_errno)
1242 plog(LLV_ERROR, LOCATION, NULL,
1243 "privsep_setsockopt (%s)\n",
1244 strerror(saved_errno));
1245
1246 errno = saved_errno;
1247 return err;
1248 }
1249
1250 len = sizeof(*msg) + sizeof(sockopt_args) + optlen;
1251
1252 if ((msg = racoon_malloc(len)) == NULL) {
1253 plog(LLV_ERROR, LOCATION, NULL,
1254 "Cannot allocate memory: %s\n", strerror(errno));
1255 return -1;
1256 }
1257 bzero(msg, len);
1258 msg->hdr.ac_cmd = PRIVSEP_SETSOCKOPTS;
1259 msg->hdr.ac_len = len;
1260
1261 sockopt_args.s = -1;
1262 sockopt_args.level = level;
1263 sockopt_args.optname = optname;
1264 sockopt_args.optval = NULL;
1265 sockopt_args.optlen = optlen;
1266
1267 data = (char *)(msg + 1);
1268 msg->bufs.buflen[0] = sizeof(sockopt_args);
1269 memcpy(data, &sockopt_args, msg->bufs.buflen[0]);
1270
1271 data += msg->bufs.buflen[0];
1272 msg->bufs.buflen[1] = optlen;
1273 memcpy(data, optval, optlen);
1274
1275 /* frees msg */
1276 if (privsep_send(privsep_sock[1], msg, len) != 0)
1277 goto out;
1278
1279 if (send_fd(privsep_sock[1], s) < 0)
1280 return -1;
1281
1282 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) {
1283 plog(LLV_ERROR, LOCATION, NULL,
1284 "privsep_recv failed\n");
1285 goto out;
1286 }
1287
1288 if (msg->hdr.ac_errno != 0) {
1289 errno = msg->hdr.ac_errno;
1290 goto out;
1291 }
1292
1293 racoon_free(msg);
1294 return 0;
1295
1296 out:
1297 racoon_free(msg);
1298 return -1;
1299 }
1300
1301 #ifdef ENABLE_HYBRID
1302 int
privsep_xauth_login_system(char * usr,char * pwd)1303 privsep_xauth_login_system(char *usr, char *pwd)
1304 {
1305 struct privsep_com_msg *msg;
1306 size_t len;
1307 char *data;
1308
1309 if (geteuid() == 0)
1310 return xauth_login_system(usr, pwd);
1311
1312 len = sizeof(*msg) + strlen(usr) + 1 + strlen(pwd) + 1;
1313 if ((msg = racoon_malloc(len)) == NULL) {
1314 plog(LLV_ERROR, LOCATION, NULL,
1315 "Cannot allocate memory: %s\n", strerror(errno));
1316 return -1;
1317 }
1318 bzero(msg, len);
1319 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_SYSTEM;
1320 msg->hdr.ac_len = len;
1321
1322 data = (char *)(msg + 1);
1323 msg->bufs.buflen[0] = strlen(usr) + 1;
1324 memcpy(data, usr, msg->bufs.buflen[0]);
1325 data += msg->bufs.buflen[0];
1326
1327 msg->bufs.buflen[1] = strlen(pwd) + 1;
1328 memcpy(data, pwd, msg->bufs.buflen[1]);
1329
1330 /* frees msg */
1331 if (privsep_send(privsep_sock[1], msg, len) != 0)
1332 goto out;
1333
1334 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1335 return -1;
1336
1337 if (msg->hdr.ac_errno != 0) {
1338 out:
1339 racoon_free(msg);
1340 return -1;
1341 }
1342
1343 racoon_free(msg);
1344 return 0;
1345 }
1346
1347 int
privsep_accounting_system(int port,struct sockaddr * raddr,char * usr,int inout)1348 privsep_accounting_system(int port, struct sockaddr *raddr, char *usr,
1349 int inout)
1350 {
1351 struct privsep_com_msg *msg;
1352 size_t len;
1353 char *data;
1354
1355 if (geteuid() == 0)
1356 return isakmp_cfg_accounting_system(port, raddr,
1357 usr, inout);
1358
1359 len = sizeof(*msg)
1360 + sizeof(port)
1361 + sysdep_sa_len(raddr)
1362 + strlen(usr) + 1
1363 + sizeof(inout);
1364
1365 if ((msg = racoon_malloc(len)) == NULL) {
1366 plog(LLV_ERROR, LOCATION, NULL,
1367 "Cannot allocate memory: %s\n", strerror(errno));
1368 return -1;
1369 }
1370 bzero(msg, len);
1371 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_SYSTEM;
1372 msg->hdr.ac_len = len;
1373 msg->bufs.buflen[0] = sizeof(port);
1374 msg->bufs.buflen[1] = sysdep_sa_len(raddr);
1375 msg->bufs.buflen[2] = strlen(usr) + 1;
1376 msg->bufs.buflen[3] = sizeof(inout);
1377
1378 data = (char *)(msg + 1);
1379 memcpy(data, &port, msg->bufs.buflen[0]);
1380
1381 data += msg->bufs.buflen[0];
1382 memcpy(data, raddr, msg->bufs.buflen[1]);
1383
1384 data += msg->bufs.buflen[1];
1385 memcpy(data, usr, msg->bufs.buflen[2]);
1386
1387 data += msg->bufs.buflen[2];
1388 memcpy(data, &inout, msg->bufs.buflen[3]);
1389
1390 /* frees msg */
1391 if (privsep_send(privsep_sock[1], msg, len) != 0)
1392 goto out;
1393
1394 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1395 return -1;
1396
1397 if (msg->hdr.ac_errno != 0) {
1398 errno = msg->hdr.ac_errno;
1399 goto out;
1400 }
1401
1402 racoon_free(msg);
1403 return 0;
1404
1405 out:
1406 racoon_free(msg);
1407 return -1;
1408 }
1409
1410 static int
port_check(int port)1411 port_check(int port)
1412 {
1413 if ((port < 0) || (port >= isakmp_cfg_config.pool_size)) {
1414 plog(LLV_ERROR, LOCATION, NULL,
1415 "privsep: port %d outside of allowed range [0,%zu]\n",
1416 port, isakmp_cfg_config.pool_size - 1);
1417 return -1;
1418 }
1419
1420 return 0;
1421 }
1422 #endif
1423
1424 static int
safety_check(struct privsep_com_msg * msg,int index)1425 safety_check(struct privsep_com_msg *msg, int index)
1426 {
1427 if (index >= PRIVSEP_NBUF_MAX) {
1428 plog(LLV_ERROR, LOCATION, NULL,
1429 "privsep: Corrupted message, too many buffers\n");
1430 return -1;
1431 }
1432
1433 if (msg->bufs.buflen[index] == 0) {
1434 plog(LLV_ERROR, LOCATION, NULL,
1435 "privsep: Corrupted message, unexpected void buffer\n");
1436 return -1;
1437 }
1438
1439 return 0;
1440 }
1441
1442 /*
1443 * Filter unsafe environment variables
1444 */
1445 static int
unsafe_env(char * const * envp)1446 unsafe_env(char *const *envp)
1447 {
1448 char *const *e;
1449 const char *const *be;
1450 const char *const bad_env[] = { "PATH=", "LD_LIBRARY_PATH=", "IFS=", NULL };
1451
1452 for (e = envp; *e; e++) {
1453 for (be = bad_env; *be; be++) {
1454 if (strncmp(*e, *be, strlen(*be)) == 0) {
1455 goto found;
1456 }
1457 }
1458 }
1459
1460 return 0;
1461 found:
1462 plog(LLV_ERROR, LOCATION, NULL,
1463 "privsep_script_exec: unsafe environment variable\n");
1464 return -1;
1465 }
1466
1467 /*
1468 * Check path safety
1469 */
1470 static int
unsafe_path(char * script,int pathtype)1471 unsafe_path(char *script, int pathtype)
1472 {
1473 char *path;
1474 char rpath[MAXPATHLEN + 1];
1475 size_t len;
1476
1477 if (script == NULL)
1478 return -1;
1479
1480 path = lcconf->pathinfo[pathtype];
1481
1482 /* No path was given for scripts: skip the check */
1483 if (path == NULL)
1484 return 0;
1485
1486 if (realpath(script, rpath) == NULL) {
1487 plog(LLV_ERROR, LOCATION, NULL,
1488 "script path \"%s\" is invalid\n", script);
1489 return -1;
1490 }
1491
1492 len = strlen(path);
1493 if (strncmp(path, rpath, len) != 0)
1494 return -1;
1495
1496 return 0;
1497 }
1498
1499 static int
unknown_name(int name)1500 unknown_name(int name)
1501 {
1502 if ((name < 0) || (name > SCRIPT_MAX)) {
1503 plog(LLV_ERROR, LOCATION, NULL,
1504 "privsep_script_exec: unsafe name index\n");
1505 return -1;
1506 }
1507
1508 return 0;
1509 }
1510
1511 /* Receive a file descriptor through the argument socket */
1512 static int
rec_fd(int s)1513 rec_fd(int s)
1514 {
1515 struct msghdr msg;
1516 struct cmsghdr *cmsg;
1517 int *fdptr;
1518 char cmsbuf[1024];
1519 struct iovec iov;
1520 char iobuf[1];
1521
1522 iov.iov_base = iobuf;
1523 iov.iov_len = 1;
1524
1525 if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(int))) {
1526 plog(LLV_ERROR, LOCATION, NULL,
1527 "send_fd: buffer size too small\n");
1528 return -1;
1529 }
1530 bzero(&msg, sizeof(msg));
1531 msg.msg_name = NULL;
1532 msg.msg_namelen = 0;
1533 msg.msg_iov = &iov;
1534 msg.msg_iovlen = 1;
1535 msg.msg_control = cmsbuf;
1536 msg.msg_controllen = CMSG_SPACE(sizeof(int));
1537
1538 if (recvmsg(s, &msg, MSG_WAITALL) == -1)
1539 return -1;
1540
1541 cmsg = CMSG_FIRSTHDR(&msg);
1542 fdptr = (int *) CMSG_DATA(cmsg);
1543 return fdptr[0];
1544 }
1545
1546 /* Send the file descriptor fd through the argument socket s */
1547 static int
send_fd(int s,int fd)1548 send_fd(int s, int fd)
1549 {
1550 struct msghdr msg;
1551 struct cmsghdr *cmsg;
1552 char cmsbuf[1024];
1553 struct iovec iov;
1554 int *fdptr;
1555
1556 iov.iov_base = __UNCONST(" ");
1557 iov.iov_len = 1;
1558
1559 if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) {
1560 plog(LLV_ERROR, LOCATION, NULL,
1561 "send_fd: buffer size too small\n");
1562 return -1;
1563 }
1564 bzero(&msg, sizeof(msg));
1565 msg.msg_name = NULL;
1566 msg.msg_namelen = 0;
1567 msg.msg_iov = &iov;
1568 msg.msg_iovlen = 1;
1569 msg.msg_control = cmsbuf;
1570 msg.msg_controllen = CMSG_SPACE(sizeof(fd));
1571 msg.msg_flags = 0;
1572
1573 cmsg = CMSG_FIRSTHDR(&msg);
1574 cmsg->cmsg_level = SOL_SOCKET;
1575 cmsg->cmsg_type = SCM_RIGHTS;
1576 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1577 fdptr = (int *)CMSG_DATA(cmsg);
1578 fdptr[0] = fd;
1579 msg.msg_controllen = cmsg->cmsg_len;
1580
1581 if (sendmsg(s, &msg, 0) == -1)
1582 return -1;
1583
1584 return 0;
1585 }
1586
1587 #ifdef HAVE_LIBPAM
1588 int
privsep_accounting_pam(int port,int inout)1589 privsep_accounting_pam(int port, int inout)
1590 {
1591 struct privsep_com_msg *msg;
1592 size_t len;
1593 int *port_data;
1594 int *inout_data;
1595 int *pool_size_data;
1596
1597 if (geteuid() == 0)
1598 return isakmp_cfg_accounting_pam(port, inout);
1599
1600 len = sizeof(*msg)
1601 + sizeof(port)
1602 + sizeof(inout)
1603 + sizeof(isakmp_cfg_config.pool_size);
1604
1605 if ((msg = racoon_malloc(len)) == NULL) {
1606 plog(LLV_ERROR, LOCATION, NULL,
1607 "Cannot allocate memory: %s\n", strerror(errno));
1608 return -1;
1609 }
1610 bzero(msg, len);
1611 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_PAM;
1612 msg->hdr.ac_len = len;
1613 msg->bufs.buflen[0] = sizeof(port);
1614 msg->bufs.buflen[1] = sizeof(inout);
1615 msg->bufs.buflen[2] = sizeof(isakmp_cfg_config.pool_size);
1616
1617 port_data = (int *)(msg + 1);
1618 inout_data = (int *)(port_data + 1);
1619 pool_size_data = (int *)(inout_data + 1);
1620
1621 *port_data = port;
1622 *inout_data = inout;
1623 *pool_size_data = isakmp_cfg_config.pool_size;
1624
1625 /* frees msg */
1626 if (privsep_send(privsep_sock[1], msg, len) != 0)
1627 goto out;
1628
1629 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1630 return -1;
1631
1632 if (msg->hdr.ac_errno != 0) {
1633 errno = msg->hdr.ac_errno;
1634 goto out;
1635 }
1636
1637 racoon_free(msg);
1638 return 0;
1639
1640 out:
1641 racoon_free(msg);
1642 return -1;
1643 }
1644
1645 int
privsep_xauth_login_pam(int port,struct sockaddr * raddr,char * usr,char * pwd)1646 privsep_xauth_login_pam(int port, struct sockaddr *raddr, char *usr, char *pwd)
1647 {
1648 struct privsep_com_msg *msg;
1649 size_t len;
1650 char *data;
1651
1652 if (geteuid() == 0)
1653 return xauth_login_pam(port, raddr, usr, pwd);
1654
1655 len = sizeof(*msg)
1656 + sizeof(port)
1657 + sizeof(isakmp_cfg_config.pool_size)
1658 + sysdep_sa_len(raddr)
1659 + strlen(usr) + 1
1660 + strlen(pwd) + 1;
1661
1662 if ((msg = racoon_malloc(len)) == NULL) {
1663 plog(LLV_ERROR, LOCATION, NULL,
1664 "Cannot allocate memory: %s\n", strerror(errno));
1665 return -1;
1666 }
1667 bzero(msg, len);
1668 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_PAM;
1669 msg->hdr.ac_len = len;
1670 msg->bufs.buflen[0] = sizeof(port);
1671 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size);
1672 msg->bufs.buflen[2] = sysdep_sa_len(raddr);
1673 msg->bufs.buflen[3] = strlen(usr) + 1;
1674 msg->bufs.buflen[4] = strlen(pwd) + 1;
1675
1676 data = (char *)(msg + 1);
1677 memcpy(data, &port, msg->bufs.buflen[0]);
1678
1679 data += msg->bufs.buflen[0];
1680 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]);
1681
1682 data += msg->bufs.buflen[1];
1683 memcpy(data, raddr, msg->bufs.buflen[2]);
1684
1685 data += msg->bufs.buflen[2];
1686 memcpy(data, usr, msg->bufs.buflen[3]);
1687
1688 data += msg->bufs.buflen[3];
1689 memcpy(data, pwd, msg->bufs.buflen[4]);
1690
1691 /* frees msg */
1692 if (privsep_send(privsep_sock[1], msg, len) != 0)
1693 goto out;
1694
1695 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1696 return -1;
1697
1698 if (msg->hdr.ac_errno != 0) {
1699 errno = msg->hdr.ac_errno;
1700 goto out;
1701 }
1702
1703 racoon_free(msg);
1704 return 0;
1705
1706 out:
1707 racoon_free(msg);
1708 return -1;
1709 }
1710
1711 void
privsep_cleanup_pam(int port)1712 privsep_cleanup_pam(int port)
1713 {
1714 struct privsep_com_msg *msg;
1715 size_t len;
1716 char *data;
1717
1718 if (geteuid() == 0) {
1719 cleanup_pam(port);
1720 return;
1721 }
1722
1723 len = sizeof(*msg)
1724 + sizeof(port)
1725 + sizeof(isakmp_cfg_config.pool_size);
1726
1727 if ((msg = racoon_malloc(len)) == NULL) {
1728 plog(LLV_ERROR, LOCATION, NULL,
1729 "Cannot allocate memory: %s\n", strerror(errno));
1730 return;
1731 }
1732 bzero(msg, len);
1733 msg->hdr.ac_cmd = PRIVSEP_CLEANUP_PAM;
1734 msg->hdr.ac_len = len;
1735 msg->bufs.buflen[0] = sizeof(port);
1736 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size);
1737
1738 data = (char *)(msg + 1);
1739 memcpy(data, &port, msg->bufs.buflen[0]);
1740
1741 data += msg->bufs.buflen[0];
1742 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]);
1743
1744 /* frees msg */
1745 if (privsep_send(privsep_sock[1], msg, len) != 0)
1746 goto out;
1747
1748 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1749 return;
1750
1751 if (msg->hdr.ac_errno != 0)
1752 errno = msg->hdr.ac_errno;
1753
1754 out:
1755 racoon_free(msg);
1756 return;
1757 }
1758 #endif
1759