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