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