blob: 55a39084f14364e807a172f26144d68ff73c1db2 [file] [log] [blame]
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001/* $NetBSD: privsep.c,v 1.21 2011/03/06 08:28:10 tteras Exp $ */
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08002
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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -070045#include <sys/types.h>
Chung-yih Wang0a1907d2009-04-23 12:26:00 +080046#include <sys/socket.h>
47#include <sys/param.h>
48
Chia-chi Yehf8a6a762011-07-04 17:21:23 -070049#include <netinet/in.h>
50
Chung-yih Wang0a1907d2009-04-23 12:26:00 +080051#include "gcmalloc.h"
52#include "vmbuf.h"
53#include "misc.h"
54#include "plog.h"
55#include "var.h"
Chung-yih Wang0a1907d2009-04-23 12:26:00 +080056
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
71static int privsep_sock[2] = { -1, -1 };
72
73static int privsep_recv(int, struct privsep_com_msg **, size_t *);
74static int privsep_send(int, struct privsep_com_msg *, size_t);
75static int safety_check(struct privsep_com_msg *, int i);
76static int port_check(int);
77static int unsafe_env(char *const *);
78static int unknown_name(int);
79static int unsafe_path(char *, int);
Chia-chi Yehf8a6a762011-07-04 17:21:23 -070080static int rec_fd(int);
81static int send_fd(int, int);
82
83struct socket_args {
84 int domain;
85 int type;
86 int protocol;
87};
88
89struct sockopt_args {
90 int s;
91 int level;
92 int optname;
93 const void *optval;
94 socklen_t optlen;
95};
96
97struct bind_args {
98 int s;
99 const struct sockaddr *addr;
100 socklen_t addrlen;
101};
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800102
103static int
104privsep_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
125static int
126privsep_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;
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700143 if (errno == ECONNRESET)
144 return -1;
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800145
146 plog(LLV_ERROR, LOCATION, NULL,
147 "privsep_recv failed: %s\n",
148 strerror(errno));
149 return -1;
150 }
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700151
152 /* EOF, other side has closed. */
153 if (len == 0)
154 return -1;
155
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800156 /* 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;
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700175 if (errno == ECONNRESET)
176 return -1;
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800177 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
196int
197privsep_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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700209 * in the privileged instance
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800210 */
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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700218 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, privsep_sock) != 0) {
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800219 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 */
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700232 (void)close(privsep_sock[0]);
233
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800234 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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700280 default: /* Parent: privileged process */
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800281 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;
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800291 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,
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700300 "racoon privileged process running with PID %d\n", getpid());
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800301
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700302 plog(LLV_INFO, LOCATION, NULL,
303 "racoon unprivileged process running with PID %d\n", child_pid);
304
305#if defined(__NetBSD__) || defined(__FreeBSD__)
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800306 setproctitle("[priv]");
307#endif
308
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700309 /*
310 * Don't catch any signal
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800311 * This duplicate session:signals[], which is static...
312 */
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700313 signal(SIGPIPE, SIG_IGN);
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800314 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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700370 * together and sign the hash in the privileged
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800371 * 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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700542 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
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800690#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],
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700874 reply, reply->hdr.ac_len) != 0) {
875 racoon_free(reply);
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800876 goto out;
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700877 }
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800878
879 racoon_free(combuf);
880 }
881
882out:
Chia-chi Yehf8a6a762011-07-04 17:21:23 -0700883 plog(LLV_INFO, LOCATION, NULL,
884 "racoon privileged process %d terminated\n", getpid());
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800885 _exit(0);
886}
887
888
889vchar_t *
890privsep_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
930out:
931 racoon_free(msg);
932 return NULL;
933}
934
Chung-yih Wang0a1907d2009-04-23 12:26:00 +0800935int
936privsep_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
1045vchar_t *
1046privsep_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
1095out:
1096 racoon_free(msg);
1097 return NULL;
1098}
1099
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001100/*
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 */
1105int
1106privsep_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
1158out:
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 */
1168int
1169privsep_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
1231out:
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 */
1241int
1242privsep_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
1313out:
1314 racoon_free(msg);
1315 return -1;
1316}
1317
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08001318#ifdef ENABLE_HYBRID
1319int
1320privsep_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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001349 /* frees msg */
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08001350 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
1365int
1366privsep_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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001412 /* frees msg */
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08001413 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
1427out:
1428 racoon_free(msg);
1429 return -1;
1430}
1431
1432static int
1433port_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
1447static int
1448safety_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/*
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001468 * Filter unsafe environment variables
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08001469 */
1470static int
1471unsafe_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;
1487found:
1488 plog(LLV_ERROR, LOCATION, NULL,
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001489 "privsep_script_exec: unsafe environment variable\n");
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08001490 return -1;
1491}
1492
1493/*
1494 * Check path safety
1495 */
1496static int
1497unsafe_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
1527static int
1528unknown_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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001540/* Receive a file descriptor through the argument socket */
1541static int
1542rec_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 */
1578static int
1579send_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
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08001620#ifdef HAVE_LIBPAM
1621int
1622privsep_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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001661 /* frees msg */
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08001662 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
1676out:
1677 racoon_free(msg);
1678 return -1;
1679}
1680
1681int
1682privsep_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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001732 /* frees msg */
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08001733 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
1747out:
1748 racoon_free(msg);
1749 return -1;
1750}
1751
1752void
1753privsep_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
Chia-chi Yehf8a6a762011-07-04 17:21:23 -07001785 /* frees msg */
Chung-yih Wang0a1907d2009-04-23 12:26:00 +08001786 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