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