]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/privsep.c
ipsec-34.0.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / privsep.c
1 /* $Id: privsep.c,v 1.6.2.7 2005/08/08 11:25:01 vanhu Exp $ */
2
3 /*
4 * Copyright (C) 2004 Emmanuel Dreyfus
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #include <unistd.h>
35 #include <string.h>
36 #ifdef __NetBSD__
37 #include <stdlib.h> /* for setproctitle */
38 #endif
39 #include <errno.h>
40 #include <signal.h>
41 #include <pwd.h>
42
43 #include <sys/socket.h>
44 #include <sys/param.h>
45
46 #include "gcmalloc.h"
47 #include "vmbuf.h"
48 #include "misc.h"
49 #include "plog.h"
50 #include "var.h"
51 #include "libpfkey.h"
52
53 #include "crypto_openssl.h"
54 #include "isakmp_var.h"
55 #include "isakmp.h"
56 #ifdef ENABLE_HYBRID
57 #include "isakmp_xauth.h"
58 #include "isakmp_cfg.h"
59 #endif
60 #include "localconf.h"
61 #include "remoteconf.h"
62 #include "admin.h"
63 #include "privsep.h"
64
65 static int privsep_sock[2] = { -1, -1 };
66
67 static int privsep_recv(int, struct privsep_com_msg **, size_t *);
68 static int privsep_send(int, struct privsep_com_msg *, size_t);
69 static int safety_check(struct privsep_com_msg *, int i);
70 #ifdef HAVE_LIBPAM
71 static int port_check(int);
72 #endif
73 static int unsafe_env(char *const *);
74 static int unknown_name(int);
75 static int unknown_script(int);
76 static int unsafe_path(char *, int);
77 static char *script_name2path(int);
78
79 static int
80 privsep_send(sock, buf, len)
81 int sock;
82 struct privsep_com_msg *buf;
83 size_t len;
84 {
85 if (buf == NULL)
86 return 0;
87
88 if (sendto(sock, (char *)buf, len, 0, NULL, 0) == -1) {
89 plog(LLV_ERROR, LOCATION, NULL,
90 "privsep_send failed: %s\n",
91 strerror(errno));
92 return -1;
93 }
94
95 racoon_free((char *)buf);
96
97 return 0;
98 }
99
100
101 static int
102 privsep_recv(sock, bufp, lenp)
103 int sock;
104 struct privsep_com_msg **bufp;
105 size_t *lenp;
106 {
107 struct admin_com com;
108 struct admin_com *combuf;
109 size_t len;
110
111 *bufp = NULL;
112 *lenp = 0;
113
114 /* Get the header */
115 while ((len = recvfrom(sock, (char *)&com,
116 sizeof(com), MSG_PEEK, NULL, NULL)) == -1) {
117 if (errno == EINTR)
118 continue;
119
120 plog(LLV_ERROR, LOCATION, NULL,
121 "privsep_recv failed: %s\n",
122 strerror(errno));
123 return -1;
124 }
125
126 /* Check for short packets */
127 if (len < sizeof(com)) {
128 plog(LLV_ERROR, LOCATION, NULL,
129 "corrupted privsep message (short header)\n");
130 return -1;
131 }
132
133 /* Allocate buffer for the whole message */
134 if ((combuf = (struct admin_com *)racoon_malloc(com.ac_len)) == NULL) {
135 plog(LLV_ERROR, LOCATION, NULL,
136 "failed to allocate memory: %s\n", strerror(errno));
137 return -1;
138 }
139
140 /* Get the whole buffer */
141 while ((len = recvfrom(sock, (char *)combuf,
142 com.ac_len, 0, NULL, NULL)) == -1) {
143 if (errno == EINTR)
144 continue;
145 plog(LLV_ERROR, LOCATION, NULL,
146 "failed to recv privsep command: %s\n",
147 strerror(errno));
148 return -1;
149 }
150
151 /* We expect len to match */
152 if (len != com.ac_len) {
153 plog(LLV_ERROR, LOCATION, NULL,
154 "corrupted privsep message (short packet)\n");
155 return -1;
156 }
157
158 *bufp = (struct privsep_com_msg *)combuf;
159 *lenp = len;
160
161 return 0;
162 }
163
164 int
165 privsep_init(void)
166 {
167 int i;
168 pid_t child_pid;
169
170 /* If running as root, we don't use the privsep code path */
171 if (lcconf->uid == 0)
172 return 0;
173
174 /*
175 * When running privsep, certificate and script paths
176 * are mandatory, as they enable us to check path safety
177 * in the privilegied instance
178 */
179 if ((lcconf->pathinfo[LC_PATHTYPE_CERT] == NULL) ||
180 (lcconf->pathinfo[LC_PATHTYPE_SCRIPT] == NULL)) {
181 plog(LLV_ERROR, LOCATION, NULL, "privilege separation "
182 "require path cert and path script in the config file\n");
183 return -1;
184 }
185
186 if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, privsep_sock) != 0) {
187 plog(LLV_ERROR, LOCATION, NULL,
188 "Cannot allocate privsep_sock: %s\n", strerror(errno));
189 return -1;
190 }
191
192 switch (child_pid = fork()) {
193 case -1:
194 plog(LLV_ERROR, LOCATION, NULL, "Cannot fork privsep: %s\n",
195 strerror(errno));
196 return -1;
197 break;
198
199 case 0: /* Child: drop privileges */
200 if (lcconf->chroot != NULL) {
201 if (chdir(lcconf->chroot) != 0) {
202 plog(LLV_ERROR, LOCATION, NULL,
203 "Cannot chdir(%s): %s\n", lcconf->chroot,
204 strerror(errno));
205 return -1;
206 }
207 if (chroot(lcconf->chroot) != 0) {
208 plog(LLV_ERROR, LOCATION, NULL,
209 "Cannot chroot(%s): %s\n", lcconf->chroot,
210 strerror(errno));
211 return -1;
212 }
213 }
214
215 if (setgid(lcconf->gid) != 0) {
216 plog(LLV_ERROR, LOCATION, NULL,
217 "Cannot setgid(%d): %s\n", lcconf->gid,
218 strerror(errno));
219 return -1;
220 }
221
222 if (setegid(lcconf->gid) != 0) {
223 plog(LLV_ERROR, LOCATION, NULL,
224 "Cannot setegid(%d): %s\n", lcconf->gid,
225 strerror(errno));
226 return -1;
227 }
228
229 if (setuid(lcconf->uid) != 0) {
230 plog(LLV_ERROR, LOCATION, NULL,
231 "Cannot setuid(%d): %s\n", lcconf->uid,
232 strerror(errno));
233 return -1;
234 }
235
236 if (seteuid(lcconf->uid) != 0) {
237 plog(LLV_ERROR, LOCATION, NULL,
238 "Cannot seteuid(%d): %s\n", lcconf->uid,
239 strerror(errno));
240 return -1;
241 }
242
243 return 0;
244 break;
245
246 default: /* Parent: privilegied process */
247 break;
248 }
249
250 /*
251 * Close everything except the socketpair,
252 * and stdout if running in the forground.
253 */
254 for (i = sysconf(_SC_OPEN_MAX); i > 0; i--) {
255 if (i == privsep_sock[0])
256 continue;
257 if (i == privsep_sock[1])
258 continue;
259 if ((f_foreground) && (i == 1))
260 continue;
261 (void)close(i);
262 }
263
264 /* Above trickery closed the log file, reopen it */
265 ploginit();
266
267 plog(LLV_INFO, LOCATION, NULL,
268 "racoon privilegied process running with PID %d\n", getpid());
269
270 #ifdef __NetBSD__
271 setproctitle("[priv]");
272 #endif
273
274 /*
275 * Don't catch any signal
276 * This duplicate session:signals[], which is static...
277 */
278 signal(SIGHUP, SIG_DFL);
279 signal(SIGINT, SIG_DFL);
280 signal(SIGTERM, SIG_DFL);
281 signal(SIGUSR1, SIG_DFL);
282 signal(SIGUSR2, SIG_DFL);
283 signal(SIGCHLD, SIG_DFL);
284
285 while (1) {
286 size_t len;
287 struct privsep_com_msg *combuf;
288 struct privsep_com_msg *reply;
289 char *data;
290 size_t *buflen;
291 size_t totallen;
292 char *bufs[PRIVSEP_NBUF_MAX];
293 int i;
294
295 if (privsep_recv(privsep_sock[0], &combuf, &len) != 0)
296 goto out;
297
298 /* Safety checks and gather the data */
299 if (len < sizeof(*combuf)) {
300 plog(LLV_ERROR, LOCATION, NULL,
301 "corrupted privsep message (short buflen)\n");
302 goto out;
303 }
304
305 data = (char *)(combuf + 1);
306 totallen = sizeof(*combuf);
307 for (i = 0; i < PRIVSEP_NBUF_MAX; i++) {
308 bufs[i] = (char *)data;
309 data += combuf->bufs.buflen[i];
310 totallen += combuf->bufs.buflen[i];
311 }
312
313 if (totallen > len) {
314 plog(LLV_ERROR, LOCATION, NULL,
315 "corrupted privsep message (bufs too big)\n");
316 goto out;
317 }
318
319 /* Prepare the reply buffer */
320 if ((reply = racoon_malloc(sizeof(*reply))) == NULL) {
321 plog(LLV_ERROR, LOCATION, NULL,
322 "Cannot allocate reply buffer: %s\n",
323 strerror(errno));
324 goto out;
325 }
326 bzero(reply, sizeof(*reply));
327 reply->hdr.ac_cmd = combuf->hdr.ac_cmd;
328 reply->hdr.ac_len = sizeof(*reply);
329
330 switch(combuf->hdr.ac_cmd) {
331 /*
332 * XXX Improvement: instead of returning the key,
333 * stuff eay_get_pkcs1privkey and eay_get_x509sign
334 * together and sign the hash in the privilegied
335 * instance?
336 * pro: the key remains inaccessibleato
337 * con: a compromised unpriv racoon can still sign anything
338 */
339 case PRIVSEP_EAY_GET_PKCS1PRIVKEY: {
340 vchar_t *privkey;
341
342 /* Make sure the string is NULL terminated */
343 if (safety_check(combuf, 0) != 0)
344 break;
345 bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
346
347 if (unsafe_path(bufs[0], LC_PATHTYPE_CERT) != 0) {
348 plog(LLV_ERROR, LOCATION, NULL,
349 "privsep_eay_get_pkcs1privkey: "
350 "unsafe key \"%s\"\n", bufs[0]);
351 }
352
353 if ((privkey = eay_get_pkcs1privkey(bufs[0])) == NULL){
354 reply->hdr.ac_errno = errno;
355 break;
356 }
357
358 reply->bufs.buflen[0] = privkey->l;
359 reply->hdr.ac_len = sizeof(*reply) + privkey->l;
360 reply = racoon_realloc(reply, reply->hdr.ac_len);
361 if (reply == NULL) {
362 plog(LLV_ERROR, LOCATION, NULL,
363 "Cannot allocate reply buffer: %s\n",
364 strerror(errno));
365 goto out;
366 }
367
368 memcpy(reply + 1, privkey->v, privkey->l);
369 vfree(privkey);
370 break;
371 }
372
373 case PRIVSEP_SCRIPT_EXEC: {
374 int script;
375 int name;
376 char **envp = NULL;
377 int envc = 0;
378 int count = 0;
379 int i;
380
381 /*
382 * First count the bufs, and make sure strings
383 * are NULL terminated.
384 *
385 * We expect: script, name, envp[], void
386 */
387 count++; /* script */
388 count++; /* name */
389
390 for (; count < PRIVSEP_NBUF_MAX; count++) {
391 if (combuf->bufs.buflen[count] == 0)
392 break;
393 bufs[count]
394 [combuf->bufs.buflen[count] - 1] = '\0';
395 envc++;
396 }
397
398 /* count a void buf and perform safety check */
399 count++;
400 if (count >= PRIVSEP_NBUF_MAX) {
401 plog(LLV_ERROR, LOCATION, NULL,
402 "privsep_script_exec: too many args\n");
403 goto out;
404 }
405
406
407 /*
408 * Allocate the arrays for envp
409 */
410 envp = racoon_malloc((envc + 1) * sizeof(char *));
411 if (envp == NULL) {
412 plog(LLV_ERROR, LOCATION, NULL,
413 "cannot allocate memory: %s\n",
414 strerror(errno));
415 goto out;
416 }
417 bzero(envp, (envc + 1) * sizeof(char *));
418
419
420 /*
421 * Populate script, name and envp
422 */
423 count = 0;
424
425 if (combuf->bufs.buflen[count] != sizeof(script)) {
426 plog(LLV_ERROR, LOCATION, NULL,
427 "privsep_script_exec: corrupted message\n");
428 goto out;
429 }
430 memcpy((char *)&script, bufs[count++], sizeof(script));
431
432 if (combuf->bufs.buflen[count] != sizeof(name)) {
433 plog(LLV_ERROR, LOCATION, NULL,
434 "privsep_script_exec: corrupted message\n");
435 goto out;
436 }
437 memcpy((char *)&name, bufs[count++], sizeof(name));
438
439 for (i = 0; combuf->bufs.buflen[count]; count++)
440 envp[i++] = bufs[count];
441
442 count++; /* void */
443
444 /*
445 * Check env for dangerous variables
446 * Check script path and name
447 * Perform fork and execve
448 */
449 if ((unsafe_env(envp) == 0) &&
450 (unknown_name(name) == 0) &&
451 (unknown_script(script) == 0) &&
452 (unsafe_path(script_name2path(script),
453 LC_PATHTYPE_SCRIPT) == 0))
454 (void)script_exec(script, name, envp);
455 else
456 plog(LLV_ERROR, LOCATION, NULL,
457 "privsep_script_exec: "
458 "unsafe script \"%s\"\n",
459 script_name2path(script));
460
461 racoon_free(envp);
462 break;
463 }
464
465 case PRIVSEP_GETPSK: {
466 vchar_t *psk;
467 int keylen;
468
469 /* Make sure the string is NULL terminated */
470 if (safety_check(combuf, 0) != 0)
471 break;
472 bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
473
474 if (combuf->bufs.buflen[1] != sizeof(keylen)) {
475 plog(LLV_ERROR, LOCATION, NULL,
476 "privsep_getpsk: corrupted message\n");
477 goto out;
478 }
479 memcpy(&keylen, bufs[1], sizeof(keylen));
480 if ((psk = getpsk(bufs[0], keylen)) == NULL) {
481 reply->hdr.ac_errno = errno;
482 break;
483 }
484
485 reply->bufs.buflen[0] = psk->l;
486 reply->hdr.ac_len = sizeof(*reply) + psk->l;
487 reply = racoon_realloc(reply, reply->hdr.ac_len);
488 if (reply == NULL) {
489 plog(LLV_ERROR, LOCATION, NULL,
490 "Cannot allocate reply buffer: %s\n",
491 strerror(errno));
492 goto out;
493 }
494
495 memcpy(reply + 1, psk->v, psk->l);
496 vfree(psk);
497 break;
498 }
499
500 #ifdef ENABLE_HYBRID
501 case PRIVSEP_XAUTH_LOGIN_SYSTEM: {
502 if (safety_check(combuf, 0) != 0)
503 break;
504 bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
505
506 if (safety_check(combuf, 1) != 0)
507 break;
508 bufs[1][combuf->bufs.buflen[1] - 1] = '\0';
509
510 errno = 0;
511 if (xauth_login_system(bufs[0], bufs[1]) != 0) {
512 if (errno == 0)
513 reply->hdr.ac_errno = EINVAL;
514 else
515 reply->hdr.ac_errno = errno;
516 }
517 break;
518 }
519 #ifdef HAVE_LIBPAM
520 case PRIVSEP_ACCOUNTING_PAM: {
521 int port;
522 int inout;
523
524 if (safety_check(combuf, 0) != 0)
525 break;
526 if (safety_check(combuf, 1) != 0)
527 break;
528
529 memcpy(&port, bufs[0], sizeof(port));
530 memcpy(&inout, bufs[1], sizeof(inout));
531
532 if (port_check(port) != 0)
533 break;
534
535 errno = 0;
536 if (isakmp_cfg_accounting_pam(port, inout) != 0) {
537 if (errno == 0)
538 reply->hdr.ac_errno = EINVAL;
539 else
540 reply->hdr.ac_errno = errno;
541 }
542 break;
543 }
544
545 case PRIVSEP_XAUTH_LOGIN_PAM: {
546 int port;
547 struct sockaddr *raddr;
548
549 if (safety_check(combuf, 0) != 0)
550 break;
551 if (safety_check(combuf, 1) != 0)
552 break;
553 if (safety_check(combuf, 2) != 0)
554 break;
555 if (safety_check(combuf, 3) != 0)
556 break;
557
558 memcpy(&port, bufs[0], sizeof(port));
559 raddr = (struct sockaddr *)bufs[1];
560
561 bufs[2][combuf->bufs.buflen[2] - 1] = '\0';
562 bufs[3][combuf->bufs.buflen[3] - 1] = '\0';
563
564 if (port_check(port) != 0)
565 break;
566
567 errno = 0;
568 if (xauth_login_pam(port,
569 raddr, bufs[2], bufs[3]) != 0) {
570 if (errno == 0)
571 reply->hdr.ac_errno = EINVAL;
572 else
573 reply->hdr.ac_errno = errno;
574 }
575 break;
576 }
577
578 case PRIVSEP_CLEANUP_PAM: {
579 int port;
580
581 if (safety_check(combuf, 0) != 0)
582 break;
583
584 memcpy(&port, bufs[0], sizeof(port));
585
586 if (port_check(port) != 0)
587 break;
588
589 cleanup_pam(port);
590 reply->hdr.ac_errno = 0;
591
592 break;
593 }
594 #endif /* HAVE_LIBPAM */
595 #endif /* ENABLE_HYBRID */
596
597 default:
598 plog(LLV_ERROR, LOCATION, NULL,
599 "unexpected privsep command %d\n",
600 combuf->hdr.ac_cmd);
601 goto out;
602 break;
603 }
604
605 /* This frees reply */
606 if (privsep_send(privsep_sock[0],
607 reply, reply->hdr.ac_len) != 0)
608 goto out;
609
610 racoon_free(combuf);
611 }
612
613 out:
614 plog(LLV_INFO, LOCATION, NULL, "privsep exit\n");
615 _exit(0);
616 }
617
618
619 vchar_t *
620 privsep_eay_get_pkcs1privkey(path)
621 char *path;
622 {
623 vchar_t *privkey;
624 struct privsep_com_msg *msg;
625 size_t len;
626
627 if (geteuid() == 0)
628 return eay_get_pkcs1privkey(path);
629
630 len = sizeof(*msg) + strlen(path) + 1;
631 if ((msg = racoon_malloc(len)) == NULL) {
632 plog(LLV_ERROR, LOCATION, NULL,
633 "Cannot allocate memory: %s\n", strerror(errno));
634 return NULL;
635 }
636 bzero(msg, len);
637 msg->hdr.ac_cmd = PRIVSEP_EAY_GET_PKCS1PRIVKEY;
638 msg->hdr.ac_len = len;
639 msg->bufs.buflen[0] = len - sizeof(*msg);
640 memcpy(msg + 1, path, msg->bufs.buflen[0]);
641
642 if (privsep_send(privsep_sock[1], msg, len) != 0)
643 return NULL;
644
645 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
646 return NULL;
647
648 if (msg->hdr.ac_errno != 0) {
649 errno = msg->hdr.ac_errno;
650 goto out;
651 }
652
653 if ((privkey = vmalloc(len - sizeof(*msg))) == NULL)
654 goto out;
655
656 memcpy(privkey->v, msg + 1, privkey->l);
657 racoon_free(msg);
658 return privkey;
659
660 out:
661 racoon_free(msg);
662 return NULL;
663 }
664
665 /*
666 * No prigilege separation trick here, we just open PFKEY before
667 * dropping root privs and we remember it later.
668 */
669 static int pfkey_socket = -1;
670 int
671 privsep_pfkey_open(void)
672 {
673 int ps;
674
675 if (pfkey_socket != -1)
676 return pfkey_socket;
677
678 ps = pfkey_open();
679 if (ps != -1)
680 pfkey_socket = ps;
681
682 return ps;
683 }
684
685 /*
686 * Consequence of the above trickery: don't
687 * really close PFKEY as we never re-open it.
688 */
689 void
690 privsep_pfkey_close(ps)
691 int ps;
692 {
693 return;
694 }
695
696 int
697 privsep_script_exec(script, name, envp)
698 int script;
699 int name;
700 char *const envp[];
701 {
702 int count = 0;
703 char *const *c;
704 char *data;
705 size_t len;
706 struct privsep_com_msg *msg;
707
708 if (geteuid() == 0)
709 return script_exec(script, name, envp);
710
711 if ((msg = racoon_malloc(sizeof(*msg))) == NULL) {
712 plog(LLV_ERROR, LOCATION, NULL,
713 "Cannot allocate memory: %s\n", strerror(errno));
714 return -1;
715 }
716
717 bzero(msg, sizeof(*msg));
718 msg->hdr.ac_cmd = PRIVSEP_SCRIPT_EXEC;
719 msg->hdr.ac_len = sizeof(*msg);
720
721 /*
722 * We send:
723 * script, name, envp[0], ... envp[N], void
724 */
725
726 /*
727 * Safety check on the counts: PRIVSEP_NBUF_MAX max
728 */
729 count = 0;
730 count++; /* script */
731 count++; /* name */
732 for (c = envp; *c; c++) /* envp */
733 count++;
734 count++; /* void */
735
736 if (count > PRIVSEP_NBUF_MAX) {
737 plog(LLV_ERROR, LOCATION, NULL, "Unexpected error: "
738 "privsep_script_exec count > PRIVSEP_NBUF_MAX\n");
739 racoon_free(msg);
740 return -1;
741 }
742
743
744 /*
745 * Compute the length
746 */
747 count = 0;
748 msg->bufs.buflen[count] = sizeof(script); /* script */
749 msg->hdr.ac_len += msg->bufs.buflen[count++];
750
751 msg->bufs.buflen[count] = sizeof(name); /* name */
752 msg->hdr.ac_len += msg->bufs.buflen[count++];
753
754 for (c = envp; *c; c++) { /* envp */
755 msg->bufs.buflen[count] = strlen(*c) + 1;
756 msg->hdr.ac_len += msg->bufs.buflen[count++];
757 }
758
759 msg->bufs.buflen[count] = 0; /* void */
760 msg->hdr.ac_len += msg->bufs.buflen[count++];
761
762 if ((msg = racoon_realloc(msg, msg->hdr.ac_len)) == NULL) {
763 plog(LLV_ERROR, LOCATION, NULL,
764 "Cannot allocate memory: %s\n", strerror(errno));
765 return -1;
766 }
767
768 /*
769 * Now copy the data
770 */
771 data = (char *)(msg + 1);
772 count = 0;
773
774 memcpy(data, (char *)&script, msg->bufs.buflen[count]); /* script */
775 data += msg->bufs.buflen[count++];
776
777 memcpy(data, (char *)&name, msg->bufs.buflen[count]); /* name */
778 data += msg->bufs.buflen[count++];
779
780 for (c = envp; *c; c++) { /* envp */
781 memcpy(data, *c, msg->bufs.buflen[count]);
782 data += msg->bufs.buflen[count++];
783 }
784
785 count++; /* void */
786
787 /*
788 * And send it!
789 */
790 if (privsep_send(privsep_sock[1], msg, msg->hdr.ac_len) != 0)
791 return -1;
792
793 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
794 return -1;
795
796 if (msg->hdr.ac_errno != 0) {
797 errno = msg->hdr.ac_errno;
798 racoon_free(msg);
799 return -1;
800 }
801
802 racoon_free(msg);
803 return 0;
804 }
805
806 vchar_t *
807 privsep_getpsk(str, keylen)
808 const char *str;
809 int keylen;
810 {
811 vchar_t *psk;
812 struct privsep_com_msg *msg;
813 size_t len;
814 int *keylenp;
815 char *data;
816
817 if (geteuid() == 0)
818 return getpsk(str, keylen);
819
820 len = sizeof(*msg) + strlen(str) + 1 + sizeof(keylen);
821 if ((msg = racoon_malloc(len)) == NULL) {
822 plog(LLV_ERROR, LOCATION, NULL,
823 "Cannot allocate memory: %s\n", strerror(errno));
824 return NULL;
825 }
826 bzero(msg, len);
827 msg->hdr.ac_cmd = PRIVSEP_GETPSK;
828 msg->hdr.ac_len = len;
829
830 data = (char *)(msg + 1);
831 msg->bufs.buflen[0] = strlen(str) + 1;
832 memcpy(data, str, msg->bufs.buflen[0]);
833
834 data += msg->bufs.buflen[0];
835 msg->bufs.buflen[1] = sizeof(keylen);
836 memcpy(data, &keylen, sizeof(keylen));
837
838 if (privsep_send(privsep_sock[1], msg, len) != 0)
839 return NULL;
840
841 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
842 return NULL;
843
844 if (msg->hdr.ac_errno != 0) {
845 errno = msg->hdr.ac_errno;
846 goto out;
847 }
848
849 if ((psk = vmalloc(len - sizeof(*msg))) == NULL)
850 goto out;
851
852 memcpy(psk->v, msg + 1, psk->l);
853 racoon_free(msg);
854 return psk;
855
856 out:
857 racoon_free(msg);
858 return NULL;
859 }
860
861 #ifdef ENABLE_HYBRID
862 int
863 privsep_xauth_login_system(usr, pwd)
864 char *usr;
865 char *pwd;
866 {
867 struct privsep_com_msg *msg;
868 size_t len;
869 char *data;
870
871 if (geteuid() == 0)
872 return xauth_login_system(usr, pwd);
873
874 len = sizeof(*msg) + strlen(usr) + 1 + strlen(pwd) + 1;
875 if ((msg = racoon_malloc(len)) == NULL) {
876 plog(LLV_ERROR, LOCATION, NULL,
877 "Cannot allocate memory: %s\n", strerror(errno));
878 return -1;
879 }
880 bzero(msg, len);
881 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_SYSTEM;
882 msg->hdr.ac_len = len;
883
884 data = (char *)(msg + 1);
885 msg->bufs.buflen[0] = strlen(usr) + 1;
886 memcpy(data, usr, msg->bufs.buflen[0]);
887 data += msg->bufs.buflen[0];
888
889 msg->bufs.buflen[1] = strlen(pwd) + 1;
890 memcpy(data, pwd, msg->bufs.buflen[1]);
891
892 if (privsep_send(privsep_sock[1], msg, len) != 0)
893 return -1;
894
895 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
896 return -1;
897
898 if (msg->hdr.ac_errno != 0) {
899 racoon_free(msg);
900 return -1;
901 }
902
903 racoon_free(msg);
904 return 0;
905 }
906 #endif /* ENABLE_HYBRID */
907
908 #ifdef HAVE_LIBPAM
909 static int
910 port_check(port)
911 int port;
912 {
913 if ((port < 0) || (port >= isakmp_cfg_config.pool_size)) {
914 plog(LLV_ERROR, LOCATION, NULL,
915 "privsep: port %d outside of allowed range [0,%zu]\n",
916 port, isakmp_cfg_config.pool_size - 1);
917 return -1;
918 }
919
920 return 0;
921 }
922 #endif
923
924 static int
925 safety_check(msg, index)
926 struct privsep_com_msg *msg;
927 int index;
928 {
929 if (index >= PRIVSEP_NBUF_MAX) {
930 plog(LLV_ERROR, LOCATION, NULL,
931 "privsep: Corrupted message, too many buffers\n");
932 return -1;
933 }
934
935 if (msg->bufs.buflen[index] == 0) {
936 plog(LLV_ERROR, LOCATION, NULL,
937 "privsep: Corrupted message, unexpected void buffer\n");
938 return -1;
939 }
940
941 return 0;
942 }
943
944 /*
945 * Filter unsafe environement variables
946 */
947 static int
948 unsafe_env(envp)
949 char *const *envp;
950 {
951 char *const *e;
952 char *const *be;
953 char *const bad_env[] = { "PATH=", "LD_LIBRARY_PATH=", "IFS=", NULL };
954
955 for (e = envp; *e; e++) {
956 for (be = bad_env; *be; be++) {
957 if (strncmp(*e, *be, strlen(*be)) == 0) {
958 goto found;
959 }
960 }
961 }
962
963 return 0;
964 found:
965 plog(LLV_ERROR, LOCATION, NULL,
966 "privsep_script_exec: unsafe environement variable\n");
967 return -1;
968 }
969
970 /*
971 * Check path safety
972 */
973 static int
974 unsafe_path(script, pathtype)
975 char *script;
976 int pathtype;
977 {
978 char *path;
979 char rpath[MAXPATHLEN + 1];
980 size_t len;
981
982 if (script == NULL)
983 return -1;
984
985 path = lcconf->pathinfo[pathtype];
986
987 /* No path was given for scripts: skip the check */
988 if (path == NULL)
989 return 0;
990
991 if (realpath(script, rpath) == NULL) {
992 plog(LLV_ERROR, LOCATION, NULL,
993 "script path \"%s\" is invalid\n", script);
994 return -1;
995 }
996
997 len = strlen(path);
998 if (strncmp(path, rpath, len) != 0)
999 return -1;
1000
1001 return 0;
1002 }
1003
1004 static char *
1005 script_name2path(name)
1006 int name;
1007 {
1008 vchar_t **sp;
1009
1010 if (script_paths == NULL) {
1011 plog(LLV_ERROR, LOCATION, NULL,
1012 "script_name2path: script_paths was not initialized\n");
1013 return NULL;
1014 }
1015
1016 sp = (vchar_t **)(script_paths->v);
1017
1018 return sp[name]->v;
1019 }
1020
1021 /*
1022 * Check the script path index is correct
1023 */
1024 static int
1025 unknown_script(script)
1026 int script;
1027 {
1028 if (script_paths == NULL) {
1029 plog(LLV_ERROR, LOCATION, NULL,
1030 "privsep_script_exec: script_paths was not initialized\n");
1031 return -1;
1032 }
1033
1034 if ((script < 0) || (script > (script_paths->l / sizeof(vchar_t *)))) {
1035 plog(LLV_ERROR, LOCATION, NULL,
1036 "privsep_script_exec: unsafe script index\n");
1037 return -1;
1038 }
1039
1040 return 0;
1041 }
1042
1043 static int
1044 unknown_name(name)
1045 int name;
1046 {
1047 if ((name < 0) || (name > SCRIPT_MAX)) {
1048 plog(LLV_ERROR, LOCATION, NULL,
1049 "privsep_script_exec: unsafe name index\n");
1050 return -1;
1051 }
1052
1053 return 0;
1054 }
1055
1056 #ifdef HAVE_LIBPAM
1057 int
1058 privsep_accounting_pam(port, inout)
1059 int port;
1060 int inout;
1061 {
1062 struct privsep_com_msg *msg;
1063 size_t len;
1064 int *port_data;
1065 int *inout_data;
1066 int result;
1067
1068 if (geteuid() == 0)
1069 return isakmp_cfg_accounting_pam(port, inout);
1070
1071 len = sizeof(*msg) + sizeof(port) + sizeof(inout);
1072 if ((msg = racoon_malloc(len)) == NULL) {
1073 plog(LLV_ERROR, LOCATION, NULL,
1074 "Cannot allocate memory: %s\n", strerror(errno));
1075 return -1;
1076 }
1077 bzero(msg, len);
1078 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_PAM;
1079 msg->hdr.ac_len = len;
1080 msg->bufs.buflen[0] = sizeof(port);
1081 msg->bufs.buflen[1] = sizeof(inout);
1082
1083 port_data = (int *)(msg + 1);
1084 inout_data = (int *)(port_data + 1);
1085
1086 *port_data = port;
1087 *inout_data = inout;
1088
1089 if (privsep_send(privsep_sock[1], msg, len) != 0)
1090 return -1;
1091
1092 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1093 return -1;
1094
1095 if (msg->hdr.ac_errno != 0) {
1096 errno = msg->hdr.ac_errno;
1097 goto out;
1098 }
1099
1100 racoon_free(msg);
1101 return 0;
1102
1103 out:
1104 racoon_free(msg);
1105 return -1;
1106 }
1107
1108 int
1109 privsep_xauth_login_pam(port, raddr, usr, pwd)
1110 int port;
1111 struct sockaddr *raddr;
1112 char *usr;
1113 char *pwd;
1114 {
1115 struct privsep_com_msg *msg;
1116 size_t len;
1117 char *data;
1118 int result;
1119
1120 if (geteuid() == 0)
1121 return xauth_login_pam(port, raddr, usr, pwd);
1122
1123 len = sizeof(*msg)
1124 + sizeof(port)
1125 + sysdep_sa_len(raddr)
1126 + strlen(usr) + 1
1127 + strlen(pwd) + 1;
1128 if ((msg = racoon_malloc(len)) == NULL) {
1129 plog(LLV_ERROR, LOCATION, NULL,
1130 "Cannot allocate memory: %s\n", strerror(errno));
1131 return -1;
1132 }
1133 bzero(msg, len);
1134 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_PAM;
1135 msg->hdr.ac_len = len;
1136 msg->bufs.buflen[0] = sizeof(port);
1137 msg->bufs.buflen[1] = sysdep_sa_len(raddr);
1138 msg->bufs.buflen[2] = strlen(usr) + 1;
1139 msg->bufs.buflen[3] = strlen(pwd) + 1;
1140
1141 data = (char *)(msg + 1);
1142 memcpy(data, &port, msg->bufs.buflen[0]);
1143
1144 data += sizeof(msg->bufs.buflen[0]);
1145 memcpy(data, raddr, msg->bufs.buflen[1]);
1146
1147 data += msg->bufs.buflen[1];
1148 memcpy(data, usr, msg->bufs.buflen[2]);
1149
1150 data += msg->bufs.buflen[2];
1151 memcpy(data, pwd, msg->bufs.buflen[3]);
1152
1153 if (privsep_send(privsep_sock[1], msg, len) != 0)
1154 return -1;
1155
1156 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1157 return -1;
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 0;
1166
1167 out:
1168 racoon_free(msg);
1169 return -1;
1170 }
1171
1172 void
1173 privsep_cleanup_pam(port)
1174 int port;
1175 {
1176 struct privsep_com_msg *msg;
1177 size_t len;
1178 char *data;
1179 int result;
1180
1181 if (geteuid() == 0)
1182 return cleanup_pam(port);
1183
1184 len = sizeof(*msg) + sizeof(port);
1185 if ((msg = racoon_malloc(len)) == NULL) {
1186 plog(LLV_ERROR, LOCATION, NULL,
1187 "Cannot allocate memory: %s\n", strerror(errno));
1188 return;
1189 }
1190 bzero(msg, len);
1191 msg->hdr.ac_cmd = PRIVSEP_CLEANUP_PAM;
1192 msg->hdr.ac_len = len;
1193 msg->bufs.buflen[0] = sizeof(port);
1194
1195 data = (char *)(msg + 1);
1196 memcpy(data, &port, msg->bufs.buflen[0]);
1197
1198 if (privsep_send(privsep_sock[1], msg, len) != 0)
1199 return;
1200
1201 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1202 return;
1203
1204 if (msg->hdr.ac_errno != 0)
1205 errno = msg->hdr.ac_errno;
1206
1207 racoon_free(msg);
1208 return;
1209 }
1210 #endif