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