No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / ipsec-tools / src / racoon / privsep.c
blob0804da7d300a7ad03cf1551717d2ab37fa8760ee
1 /* $NetBSD: privsep.c,v 1.18 2008/12/08 06:00:53 tteras Exp $ */
3 /* Id: privsep.c,v 1.15 2005/08/08 11:23:44 vanhu Exp */
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.
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.
34 #include "config.h"
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>
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <sys/param.h>
49 #include <netinet/in.h>
51 #include "gcmalloc.h"
52 #include "vmbuf.h"
53 #include "misc.h"
54 #include "plog.h"
55 #include "var.h"
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"
71 static int privsep_sock[2] = { -1, -1 };
73 static int privsep_recv(int, struct privsep_com_msg **, size_t *);
74 static int privsep_send(int, struct privsep_com_msg *, size_t);
75 static int safety_check(struct privsep_com_msg *, int i);
76 static int port_check(int);
77 static int unsafe_env(char *const *);
78 static int unknown_name(int);
79 static int unsafe_path(char *, int);
80 static int rec_fd(int);
81 static int send_fd(int, int);
83 struct socket_args {
84 int domain;
85 int type;
86 int protocol;
89 struct sockopt_args {
90 int s;
91 int level;
92 int optname;
93 const void *optval;
94 socklen_t optlen;
97 struct bind_args {
98 int s;
99 const struct sockaddr *addr;
100 socklen_t addrlen;
103 static int
104 privsep_send(sock, buf, len)
105 int sock;
106 struct privsep_com_msg *buf;
107 size_t len;
109 if (buf == NULL)
110 return 0;
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;
119 racoon_free((char *)buf);
121 return 0;
125 static int
126 privsep_recv(sock, bufp, lenp)
127 int sock;
128 struct privsep_com_msg **bufp;
129 size_t *lenp;
131 struct admin_com com;
132 struct admin_com *combuf;
133 size_t len;
135 *bufp = NULL;
136 *lenp = 0;
138 /* Get the header */
139 while ((len = recvfrom(sock, (char *)&com,
140 sizeof(com), MSG_PEEK, NULL, NULL)) == -1) {
141 if (errno == EINTR)
142 continue;
143 if (errno == ECONNRESET)
144 return -1;
146 plog(LLV_ERROR, LOCATION, NULL,
147 "privsep_recv failed: %s\n",
148 strerror(errno));
149 return -1;
152 /* EOF, other side has closed. */
153 if (len == 0)
154 return -1;
156 /* Check for short packets */
157 if (len < sizeof(com)) {
158 plog(LLV_ERROR, LOCATION, NULL,
159 "corrupted privsep message (short header)\n");
160 return -1;
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;
170 /* Get the whole buffer */
171 while ((len = recvfrom(sock, (char *)combuf,
172 com.ac_len, 0, NULL, NULL)) == -1) {
173 if (errno == EINTR)
174 continue;
175 if (errno == ECONNRESET)
176 return -1;
177 plog(LLV_ERROR, LOCATION, NULL,
178 "failed to recv privsep command: %s\n",
179 strerror(errno));
180 return -1;
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;
190 *bufp = (struct privsep_com_msg *)combuf;
191 *lenp = len;
193 return 0;
197 privsep_init(void)
199 int i;
200 pid_t child_pid;
202 /* If running as root, we don't use the privsep code path */
203 if (lcconf->uid == 0)
204 return 0;
207 * When running privsep, certificate and script paths
208 * are mandatory, as they enable us to check path safety
209 * in the privileged instance
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;
218 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, privsep_sock) != 0) {
219 plog(LLV_ERROR, LOCATION, NULL,
220 "Cannot allocate privsep_sock: %s\n", strerror(errno));
221 return -1;
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;
231 case 0: /* Child: drop privileges */
232 (void)close(privsep_sock[0]);
234 if (lcconf->chroot != NULL) {
235 if (chdir(lcconf->chroot) != 0) {
236 plog(LLV_ERROR, LOCATION, NULL,
237 "Cannot chdir(%s): %s\n", lcconf->chroot,
238 strerror(errno));
239 return -1;
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;
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;
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;
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;
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;
277 return 0;
278 break;
280 default: /* Parent: privileged process */
281 break;
285 * Close everything except the socketpair,
286 * and stdout if running in the forground.
288 for (i = sysconf(_SC_OPEN_MAX); i > 0; i--) {
289 if (i == privsep_sock[0])
290 continue;
291 if ((f_foreground) && (i == 1))
292 continue;
293 (void)close(i);
296 /* Above trickery closed the log file, reopen it */
297 ploginit();
299 plog(LLV_INFO, LOCATION, NULL,
300 "racoon privileged process running with PID %d\n", getpid());
302 plog(LLV_INFO, LOCATION, NULL,
303 "racoon unprivileged process running with PID %d\n", child_pid);
305 #if defined(__NetBSD__) || defined(__FreeBSD__)
306 setproctitle("[priv]");
307 #endif
310 * Don't catch any signal
311 * This duplicate session:signals[], which is static...
313 signal(SIGPIPE, SIG_IGN);
314 signal(SIGHUP, SIG_DFL);
315 signal(SIGINT, SIG_DFL);
316 signal(SIGTERM, SIG_DFL);
317 signal(SIGUSR1, SIG_DFL);
318 signal(SIGUSR2, SIG_DFL);
319 signal(SIGCHLD, SIG_DFL);
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;
331 if (privsep_recv(privsep_sock[0], &combuf, &len) != 0)
332 goto out;
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;
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];
349 if (totallen > len) {
350 plog(LLV_ERROR, LOCATION, NULL,
351 "corrupted privsep message (bufs too big)\n");
352 goto out;
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;
362 bzero(reply, sizeof(*reply));
363 reply->hdr.ac_cmd = combuf->hdr.ac_cmd;
364 reply->hdr.ac_len = sizeof(*reply);
366 switch(combuf->hdr.ac_cmd) {
368 * XXX Improvement: instead of returning the key,
369 * stuff eay_get_pkcs1privkey and eay_get_x509sign
370 * together and sign the hash in the privileged
371 * instance?
372 * pro: the key remains inaccessible to unpriv
373 * con: a compromised unpriv racoon can still sign anything
375 case PRIVSEP_EAY_GET_PKCS1PRIVKEY: {
376 vchar_t *privkey;
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';
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]);
389 plog(LLV_DEBUG, LOCATION, NULL,
390 "eay_get_pkcs1privkey(\"%s\")\n", bufs[0]);
392 if ((privkey = eay_get_pkcs1privkey(bufs[0])) == NULL){
393 reply->hdr.ac_errno = errno;
394 break;
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;
407 memcpy(reply + 1, privkey->v, privkey->l);
408 vfree(privkey);
409 break;
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;
421 * First count the bufs, and make sure strings
422 * are NULL terminated.
424 * We expect: script, name, envp[], void
426 if (safety_check(combuf, 0) != 0)
427 break;
428 bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
429 count++; /* script */
431 count++; /* name */
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++;
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;
451 * Allocate the arrays for envp
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;
460 bzero(envp, (envc + 1) * sizeof(char *));
464 * Populate script, name and envp
466 count = 0;
467 script = bufs[count++];
469 if (combuf->bufs.buflen[count] != sizeof(name)) {
470 plog(LLV_ERROR, LOCATION, NULL,
471 "privsep_script_exec: corrupted message\n");
472 goto out;
474 memcpy((char *)&name, bufs[count++], sizeof(name));
476 for (i = 0; combuf->bufs.buflen[count]; count++)
477 envp[i++] = bufs[count];
479 count++; /* void */
481 plog(LLV_DEBUG, LOCATION, NULL,
482 "script_exec(\"%s\", %d, %p)\n",
483 script, name, envp);
486 * Check env for dangerous variables
487 * Check script path and name
488 * Perform fork and execve
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);
499 racoon_free(envp);
500 break;
503 case PRIVSEP_GETPSK: {
504 vchar_t *psk;
505 int keylen;
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';
512 if (combuf->bufs.buflen[1] != sizeof(keylen)) {
513 plog(LLV_ERROR, LOCATION, NULL,
514 "privsep_getpsk: corrupted message\n");
515 goto out;
517 memcpy(&keylen, bufs[1], sizeof(keylen));
519 plog(LLV_DEBUG, LOCATION, NULL,
520 "getpsk(\"%s\", %d)\n", bufs[0], keylen);
522 if ((psk = getpsk(bufs[0], keylen)) == NULL) {
523 reply->hdr.ac_errno = errno;
524 break;
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;
537 memcpy(reply + 1, psk->v, psk->l);
538 vfree(psk);
539 break;
542 case PRIVSEP_SOCKET: {
543 struct socket_args socket_args;
544 int s;
546 /* Make sure the string is NULL terminated */
547 if (safety_check(combuf, 0) != 0)
548 break;
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;
556 memcpy(&socket_args, bufs[0],
557 sizeof(struct socket_args));
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;
568 if ((s = socket(socket_args.domain, socket_args.type,
569 socket_args.protocol)) == -1) {
570 reply->hdr.ac_errno = errno;
571 break;
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;
581 close(s);
582 break;
585 case PRIVSEP_BIND: {
586 struct bind_args bind_args;
587 int err, port = 0;
589 /* Make sure the string is NULL terminated */
590 if (safety_check(combuf, 0) != 0)
591 break;
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;
599 memcpy(&bind_args, bufs[0], sizeof(struct bind_args));
601 if (combuf->bufs.buflen[1] != bind_args.addrlen) {
602 plog(LLV_ERROR, LOCATION, NULL,
603 "privsep_bind: corrupted message\n");
604 goto out;
606 bind_args.addr = (const struct sockaddr *)bufs[1];
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;
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;
626 err = bind(bind_args.s, bind_args.addr,
627 bind_args.addrlen);
629 if (err)
630 reply->hdr.ac_errno = errno;
632 close(bind_args.s);
633 break;
636 case PRIVSEP_SETSOCKOPTS: {
637 struct sockopt_args sockopt_args;
638 int err;
640 /* Make sure the string is NULL terminated */
641 if (safety_check(combuf, 0) != 0)
642 break;
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;
651 memcpy(&sockopt_args, bufs[0],
652 sizeof(struct sockopt_args));
654 if (combuf->bufs.buflen[1] != sockopt_args.optlen) {
655 plog(LLV_ERROR, LOCATION, NULL,
656 "privsep_setsockopt: corrupted message\n");
657 goto out;
659 sockopt_args.optval = bufs[1];
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;
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;
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;
686 close(sockopt_args.s);
687 break;
690 #ifdef ENABLE_HYBRID
691 case PRIVSEP_ACCOUNTING_SYSTEM: {
692 int pool_size;
693 int port;
694 int inout;
695 struct sockaddr *raddr;
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;
706 memcpy(&port, bufs[0], sizeof(port));
707 raddr = (struct sockaddr *)bufs[1];
709 bufs[2][combuf->bufs.buflen[2] - 1] = '\0';
710 memcpy(&inout, bufs[3], sizeof(port));
712 if (port_check(port) != 0)
713 break;
715 plog(LLV_DEBUG, LOCATION, NULL,
716 "accounting_system(%d, %s, %s)\n",
717 port, saddr2str(raddr), bufs[2]);
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;
727 break;
729 case PRIVSEP_XAUTH_LOGIN_SYSTEM: {
730 if (safety_check(combuf, 0) != 0)
731 break;
732 bufs[0][combuf->bufs.buflen[0] - 1] = '\0';
734 if (safety_check(combuf, 1) != 0)
735 break;
736 bufs[1][combuf->bufs.buflen[1] - 1] = '\0';
738 plog(LLV_DEBUG, LOCATION, NULL,
739 "xauth_login_system(\"%s\", <password>)\n",
740 bufs[0]);
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;
749 break;
751 #ifdef HAVE_LIBPAM
752 case PRIVSEP_ACCOUNTING_PAM: {
753 int port;
754 int inout;
755 int pool_size;
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;
764 memcpy(&port, bufs[0], sizeof(port));
765 memcpy(&inout, bufs[1], sizeof(inout));
766 memcpy(&pool_size, bufs[2], sizeof(pool_size));
768 if (pool_size != isakmp_cfg_config.pool_size)
769 if (isakmp_cfg_resize_pool(pool_size) != 0)
770 break;
772 if (port_check(port) != 0)
773 break;
775 plog(LLV_DEBUG, LOCATION, NULL,
776 "isakmp_cfg_accounting_pam(%d, %d)\n",
777 port, inout);
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;
786 break;
789 case PRIVSEP_XAUTH_LOGIN_PAM: {
790 int port;
791 int pool_size;
792 struct sockaddr *raddr;
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;
805 memcpy(&port, bufs[0], sizeof(port));
806 memcpy(&pool_size, bufs[1], sizeof(pool_size));
807 raddr = (struct sockaddr *)bufs[2];
809 bufs[3][combuf->bufs.buflen[3] - 1] = '\0';
810 bufs[4][combuf->bufs.buflen[4] - 1] = '\0';
812 if (pool_size != isakmp_cfg_config.pool_size)
813 if (isakmp_cfg_resize_pool(pool_size) != 0)
814 break;
816 if (port_check(port) != 0)
817 break;
819 plog(LLV_DEBUG, LOCATION, NULL,
820 "xauth_login_pam(%d, %s, \"%s\", <password>)\n",
821 port, saddr2str(raddr), bufs[3]);
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;
831 break;
834 case PRIVSEP_CLEANUP_PAM: {
835 int port;
836 int pool_size;
838 if (safety_check(combuf, 0) != 0)
839 break;
840 if (safety_check(combuf, 1) != 0)
841 break;
843 memcpy(&port, bufs[0], sizeof(port));
844 memcpy(&pool_size, bufs[1], sizeof(pool_size));
846 if (pool_size != isakmp_cfg_config.pool_size)
847 if (isakmp_cfg_resize_pool(pool_size) != 0)
848 break;
850 if (port_check(port) != 0)
851 break;
853 plog(LLV_DEBUG, LOCATION, NULL,
854 "cleanup_pam(%d)\n", port);
856 cleanup_pam(port);
857 reply->hdr.ac_errno = 0;
859 break;
861 #endif /* HAVE_LIBPAM */
862 #endif /* ENABLE_HYBRID */
864 default:
865 plog(LLV_ERROR, LOCATION, NULL,
866 "unexpected privsep command %d\n",
867 combuf->hdr.ac_cmd);
868 goto out;
869 break;
872 /* This frees reply */
873 if (privsep_send(privsep_sock[0],
874 reply, reply->hdr.ac_len) != 0) {
875 racoon_free(reply);
876 goto out;
879 racoon_free(combuf);
882 out:
883 plog(LLV_INFO, LOCATION, NULL,
884 "racoon privileged process %d terminated\n", getpid());
885 _exit(0);
889 vchar_t *
890 privsep_eay_get_pkcs1privkey(path)
891 char *path;
893 vchar_t *privkey;
894 struct privsep_com_msg *msg;
895 size_t len;
897 if (geteuid() == 0)
898 return eay_get_pkcs1privkey(path);
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;
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]);
912 if (privsep_send(privsep_sock[1], msg, len) != 0)
913 return NULL;
915 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
916 return NULL;
918 if (msg->hdr.ac_errno != 0) {
919 errno = msg->hdr.ac_errno;
920 goto out;
923 if ((privkey = vmalloc(len - sizeof(*msg))) == NULL)
924 goto out;
926 memcpy(privkey->v, msg + 1, privkey->l);
927 racoon_free(msg);
928 return privkey;
930 out:
931 racoon_free(msg);
932 return NULL;
936 privsep_script_exec(script, name, envp)
937 char *script;
938 int name;
939 char *const envp[];
941 int count = 0;
942 char *const *c;
943 char *data;
944 size_t len;
945 struct privsep_com_msg *msg;
947 if (geteuid() == 0)
948 return script_exec(script, name, envp);
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;
956 bzero(msg, sizeof(*msg));
957 msg->hdr.ac_cmd = PRIVSEP_SCRIPT_EXEC;
958 msg->hdr.ac_len = sizeof(*msg);
961 * We send:
962 * script, name, envp[0], ... envp[N], void
966 * Safety check on the counts: PRIVSEP_NBUF_MAX max
968 count = 0;
969 count++; /* script */
970 count++; /* name */
971 for (c = envp; *c; c++) /* envp */
972 count++;
973 count++; /* void */
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;
984 * Compute the length
986 count = 0;
987 msg->bufs.buflen[count] = strlen(script) + 1; /* script */
988 msg->hdr.ac_len += msg->bufs.buflen[count++];
990 msg->bufs.buflen[count] = sizeof(name); /* name */
991 msg->hdr.ac_len += msg->bufs.buflen[count++];
993 for (c = envp; *c; c++) { /* envp */
994 msg->bufs.buflen[count] = strlen(*c) + 1;
995 msg->hdr.ac_len += msg->bufs.buflen[count++];
998 msg->bufs.buflen[count] = 0; /* void */
999 msg->hdr.ac_len += msg->bufs.buflen[count++];
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;
1008 * Now copy the data
1010 data = (char *)(msg + 1);
1011 count = 0;
1013 memcpy(data, (char *)script, msg->bufs.buflen[count]); /* script */
1014 data += msg->bufs.buflen[count++];
1016 memcpy(data, (char *)&name, msg->bufs.buflen[count]); /* name */
1017 data += msg->bufs.buflen[count++];
1019 for (c = envp; *c; c++) { /* envp */
1020 memcpy(data, *c, msg->bufs.buflen[count]);
1021 data += msg->bufs.buflen[count++];
1024 count++; /* void */
1027 * And send it!
1029 if (privsep_send(privsep_sock[1], msg, msg->hdr.ac_len) != 0)
1030 return -1;
1032 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1033 return -1;
1035 if (msg->hdr.ac_errno != 0) {
1036 errno = msg->hdr.ac_errno;
1037 racoon_free(msg);
1038 return -1;
1041 racoon_free(msg);
1042 return 0;
1045 vchar_t *
1046 privsep_getpsk(str, keylen)
1047 const char *str;
1048 int keylen;
1050 vchar_t *psk;
1051 struct privsep_com_msg *msg;
1052 size_t len;
1053 int *keylenp;
1054 char *data;
1056 if (geteuid() == 0)
1057 return getpsk(str, keylen);
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;
1065 bzero(msg, len);
1066 msg->hdr.ac_cmd = PRIVSEP_GETPSK;
1067 msg->hdr.ac_len = len;
1069 data = (char *)(msg + 1);
1070 msg->bufs.buflen[0] = strlen(str) + 1;
1071 memcpy(data, str, msg->bufs.buflen[0]);
1073 data += msg->bufs.buflen[0];
1074 msg->bufs.buflen[1] = sizeof(keylen);
1075 memcpy(data, &keylen, sizeof(keylen));
1077 if (privsep_send(privsep_sock[1], msg, len) != 0)
1078 return NULL;
1080 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1081 return NULL;
1083 if (msg->hdr.ac_errno != 0) {
1084 errno = msg->hdr.ac_errno;
1085 goto out;
1088 if ((psk = vmalloc(len - sizeof(*msg))) == NULL)
1089 goto out;
1091 memcpy(psk->v, msg + 1, psk->l);
1092 racoon_free(msg);
1093 return psk;
1095 out:
1096 racoon_free(msg);
1097 return NULL;
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.
1106 privsep_socket(domain, type, protocol)
1107 int domain;
1108 int type;
1109 int protocol;
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;
1117 if (geteuid() == 0)
1118 return socket(domain, type, protocol);
1120 len = sizeof(*msg) + sizeof(socket_args);
1122 if ((msg = racoon_malloc(len)) == NULL) {
1123 plog(LLV_ERROR, LOCATION, NULL,
1124 "Cannot allocate memory: %s\n", strerror(errno));
1125 return -1;
1127 bzero(msg, len);
1128 msg->hdr.ac_cmd = PRIVSEP_SOCKET;
1129 msg->hdr.ac_len = len;
1131 socket_args.domain = domain;
1132 socket_args.type = type;
1133 socket_args.protocol = protocol;
1135 data = (char *)(msg + 1);
1136 msg->bufs.buflen[0] = sizeof(socket_args);
1137 memcpy(data, &socket_args, msg->bufs.buflen[0]);
1139 /* frees msg */
1140 if (privsep_send(privsep_sock[1], msg, len) != 0)
1141 goto out;
1143 /* Get the privileged socket descriptor from the privileged process. */
1144 if ((s = rec_fd(privsep_sock[1])) == -1)
1145 return -1;
1147 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1148 goto out;
1150 if (msg->hdr.ac_errno != 0) {
1151 errno = msg->hdr.ac_errno;
1152 goto out;
1155 racoon_free(msg);
1156 return s;
1158 out:
1159 racoon_free(msg);
1160 return -1;
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.
1169 privsep_bind(s, addr, addrlen)
1170 int s;
1171 const struct sockaddr *addr;
1172 socklen_t addrlen;
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;
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;
1189 len = sizeof(*msg) + sizeof(bind_args) + addrlen;
1191 if ((msg = racoon_malloc(len)) == NULL) {
1192 plog(LLV_ERROR, LOCATION, NULL,
1193 "Cannot allocate memory: %s\n", strerror(errno));
1194 return -1;
1196 bzero(msg, len);
1197 msg->hdr.ac_cmd = PRIVSEP_BIND;
1198 msg->hdr.ac_len = len;
1200 bind_args.s = -1;
1201 bind_args.addr = NULL;
1202 bind_args.addrlen = addrlen;
1204 data = (char *)(msg + 1);
1205 msg->bufs.buflen[0] = sizeof(bind_args);
1206 memcpy(data, &bind_args, msg->bufs.buflen[0]);
1208 data += msg->bufs.buflen[0];
1209 msg->bufs.buflen[1] = addrlen;
1210 memcpy(data, addr, addrlen);
1212 /* frees msg */
1213 if (privsep_send(privsep_sock[1], msg, len) != 0)
1214 goto out;
1216 /* Send the socket descriptor to the privileged process. */
1217 if (send_fd(privsep_sock[1], s) < 0)
1218 return -1;
1220 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1221 goto out;
1223 if (msg->hdr.ac_errno != 0) {
1224 errno = msg->hdr.ac_errno;
1225 goto out;
1228 racoon_free(msg);
1229 return 0;
1231 out:
1232 racoon_free(msg);
1233 return -1;
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.
1242 privsep_setsockopt(s, level, optname, optval, optlen)
1243 int s;
1244 int level;
1245 int optname;
1246 const void *optval;
1247 socklen_t optlen;
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;
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));
1263 errno = saved_errno;
1264 return err;
1267 len = sizeof(*msg) + sizeof(sockopt_args) + optlen;
1269 if ((msg = racoon_malloc(len)) == NULL) {
1270 plog(LLV_ERROR, LOCATION, NULL,
1271 "Cannot allocate memory: %s\n", strerror(errno));
1272 return -1;
1274 bzero(msg, len);
1275 msg->hdr.ac_cmd = PRIVSEP_SETSOCKOPTS;
1276 msg->hdr.ac_len = len;
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;
1284 data = (char *)(msg + 1);
1285 msg->bufs.buflen[0] = sizeof(sockopt_args);
1286 memcpy(data, &sockopt_args, msg->bufs.buflen[0]);
1288 data += msg->bufs.buflen[0];
1289 msg->bufs.buflen[1] = optlen;
1290 memcpy(data, optval, optlen);
1292 /* frees msg */
1293 if (privsep_send(privsep_sock[1], msg, len) != 0)
1294 goto out;
1296 if (send_fd(privsep_sock[1], s) < 0)
1297 return -1;
1299 if (privsep_recv(privsep_sock[1], &msg, &len) != 0) {
1300 plog(LLV_ERROR, LOCATION, NULL,
1301 "privsep_recv failed\n");
1302 goto out;
1305 if (msg->hdr.ac_errno != 0) {
1306 errno = msg->hdr.ac_errno;
1307 goto out;
1310 racoon_free(msg);
1311 return 0;
1313 out:
1314 racoon_free(msg);
1315 return -1;
1318 #ifdef ENABLE_HYBRID
1320 privsep_xauth_login_system(usr, pwd)
1321 char *usr;
1322 char *pwd;
1324 struct privsep_com_msg *msg;
1325 size_t len;
1326 char *data;
1328 if (geteuid() == 0)
1329 return xauth_login_system(usr, pwd);
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;
1337 bzero(msg, len);
1338 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_SYSTEM;
1339 msg->hdr.ac_len = len;
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];
1346 msg->bufs.buflen[1] = strlen(pwd) + 1;
1347 memcpy(data, pwd, msg->bufs.buflen[1]);
1349 /* frees msg */
1350 if (privsep_send(privsep_sock[1], msg, len) != 0)
1351 return -1;
1353 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1354 return -1;
1356 if (msg->hdr.ac_errno != 0) {
1357 racoon_free(msg);
1358 return -1;
1361 racoon_free(msg);
1362 return 0;
1365 int
1366 privsep_accounting_system(port, raddr, usr, inout)
1367 int port;
1368 struct sockaddr *raddr;
1369 char *usr;
1370 int inout;
1372 struct privsep_com_msg *msg;
1373 size_t len;
1374 char *data;
1375 int result;
1377 if (geteuid() == 0)
1378 return isakmp_cfg_accounting_system(port, raddr,
1379 usr, inout);
1381 len = sizeof(*msg)
1382 + sizeof(port)
1383 + sysdep_sa_len(raddr)
1384 + strlen(usr) + 1
1385 + sizeof(inout);
1387 if ((msg = racoon_malloc(len)) == NULL) {
1388 plog(LLV_ERROR, LOCATION, NULL,
1389 "Cannot allocate memory: %s\n", strerror(errno));
1390 return -1;
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);
1400 data = (char *)(msg + 1);
1401 memcpy(data, &port, msg->bufs.buflen[0]);
1403 data += msg->bufs.buflen[0];
1404 memcpy(data, raddr, msg->bufs.buflen[1]);
1406 data += msg->bufs.buflen[1];
1407 memcpy(data, usr, msg->bufs.buflen[2]);
1409 data += msg->bufs.buflen[2];
1410 memcpy(data, &inout, msg->bufs.buflen[3]);
1412 /* frees msg */
1413 if (privsep_send(privsep_sock[1], msg, len) != 0)
1414 return -1;
1416 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1417 return -1;
1419 if (msg->hdr.ac_errno != 0) {
1420 errno = msg->hdr.ac_errno;
1421 goto out;
1424 racoon_free(msg);
1425 return 0;
1427 out:
1428 racoon_free(msg);
1429 return -1;
1432 static int
1433 port_check(port)
1434 int port;
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;
1443 return 0;
1445 #endif
1447 static int
1448 safety_check(msg, index)
1449 struct privsep_com_msg *msg;
1450 int index;
1452 if (index >= PRIVSEP_NBUF_MAX) {
1453 plog(LLV_ERROR, LOCATION, NULL,
1454 "privsep: Corrupted message, too many buffers\n");
1455 return -1;
1458 if (msg->bufs.buflen[index] == 0) {
1459 plog(LLV_ERROR, LOCATION, NULL,
1460 "privsep: Corrupted message, unexpected void buffer\n");
1461 return -1;
1464 return 0;
1468 * Filter unsafe environement variables
1470 static int
1471 unsafe_env(envp)
1472 char *const *envp;
1474 char *const *e;
1475 char *const *be;
1476 char *const bad_env[] = { "PATH=", "LD_LIBRARY_PATH=", "IFS=", NULL };
1478 for (e = envp; *e; e++) {
1479 for (be = bad_env; *be; be++) {
1480 if (strncmp(*e, *be, strlen(*be)) == 0) {
1481 goto found;
1486 return 0;
1487 found:
1488 plog(LLV_ERROR, LOCATION, NULL,
1489 "privsep_script_exec: unsafe environement variable\n");
1490 return -1;
1494 * Check path safety
1496 static int
1497 unsafe_path(script, pathtype)
1498 char *script;
1499 int pathtype;
1501 char *path;
1502 char rpath[MAXPATHLEN + 1];
1503 size_t len;
1505 if (script == NULL)
1506 return -1;
1508 path = lcconf->pathinfo[pathtype];
1510 /* No path was given for scripts: skip the check */
1511 if (path == NULL)
1512 return 0;
1514 if (realpath(script, rpath) == NULL) {
1515 plog(LLV_ERROR, LOCATION, NULL,
1516 "script path \"%s\" is invalid\n", script);
1517 return -1;
1520 len = strlen(path);
1521 if (strncmp(path, rpath, len) != 0)
1522 return -1;
1524 return 0;
1527 static int
1528 unknown_name(name)
1529 int name;
1531 if ((name < 0) || (name > SCRIPT_MAX)) {
1532 plog(LLV_ERROR, LOCATION, NULL,
1533 "privsep_script_exec: unsafe name index\n");
1534 return -1;
1537 return 0;
1540 /* Receive a file descriptor through the argument socket */
1541 static int
1542 rec_fd(s)
1543 int s;
1545 struct msghdr msg;
1546 struct cmsghdr *cmsg;
1547 int fd;
1548 char cmsbuf[1024];
1549 struct iovec iov;
1550 char iobuf[1];
1552 iov.iov_base = iobuf;
1553 iov.iov_len = 1;
1555 if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) {
1556 plog(LLV_ERROR, LOCATION, NULL,
1557 "send_fd: buffer size too small\n");
1558 return -1;
1560 bzero(&msg, sizeof(msg));
1561 msg.msg_name = NULL;
1562 msg.msg_namelen = 0;
1563 msg.msg_iov = &iov;
1564 msg.msg_iovlen = 1;
1565 msg.msg_control = cmsbuf;
1566 msg.msg_controllen = CMSG_SPACE(sizeof(fd));
1568 if (recvmsg(s, &msg, MSG_WAITALL) == -1)
1569 return -1;
1571 cmsg = CMSG_FIRSTHDR(&msg);
1572 return *(int *)CMSG_DATA(cmsg);
1575 /* Send the file descriptor fd through the argument socket s */
1576 static int
1577 send_fd(s, fd)
1578 int s;
1579 int fd;
1581 struct msghdr msg;
1582 struct cmsghdr *cmsg;
1583 char cmsbuf[1024];
1584 struct iovec iov;
1586 iov.iov_base = " ";
1587 iov.iov_len = 1;
1589 if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) {
1590 plog(LLV_ERROR, LOCATION, NULL,
1591 "send_fd: buffer size too small\n");
1592 return -1;
1594 bzero(&msg, sizeof(msg));
1595 msg.msg_name = NULL;
1596 msg.msg_namelen = 0;
1597 msg.msg_iov = &iov;
1598 msg.msg_iovlen = 1;
1599 msg.msg_control = cmsbuf;
1600 msg.msg_controllen = CMSG_SPACE(sizeof(fd));
1601 msg.msg_flags = 0;
1603 cmsg = CMSG_FIRSTHDR(&msg);
1604 cmsg->cmsg_level = SOL_SOCKET;
1605 cmsg->cmsg_type = SCM_RIGHTS;
1606 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1607 *(int *)CMSG_DATA(cmsg) = fd;
1608 msg.msg_controllen = cmsg->cmsg_len;
1610 if (sendmsg(s, &msg, 0) == -1)
1611 return -1;
1613 return 0;
1616 #ifdef HAVE_LIBPAM
1617 int
1618 privsep_accounting_pam(port, inout)
1619 int port;
1620 int inout;
1622 struct privsep_com_msg *msg;
1623 size_t len;
1624 int *port_data;
1625 int *inout_data;
1626 int *pool_size_data;
1627 int result;
1629 if (geteuid() == 0)
1630 return isakmp_cfg_accounting_pam(port, inout);
1632 len = sizeof(*msg)
1633 + sizeof(port)
1634 + sizeof(inout)
1635 + sizeof(isakmp_cfg_config.pool_size);
1637 if ((msg = racoon_malloc(len)) == NULL) {
1638 plog(LLV_ERROR, LOCATION, NULL,
1639 "Cannot allocate memory: %s\n", strerror(errno));
1640 return -1;
1642 bzero(msg, len);
1643 msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_PAM;
1644 msg->hdr.ac_len = len;
1645 msg->bufs.buflen[0] = sizeof(port);
1646 msg->bufs.buflen[1] = sizeof(inout);
1647 msg->bufs.buflen[2] = sizeof(isakmp_cfg_config.pool_size);
1649 port_data = (int *)(msg + 1);
1650 inout_data = (int *)(port_data + 1);
1651 pool_size_data = (int *)(inout_data + 1);
1653 *port_data = port;
1654 *inout_data = inout;
1655 *pool_size_data = isakmp_cfg_config.pool_size;
1657 /* frees msg */
1658 if (privsep_send(privsep_sock[1], msg, len) != 0)
1659 return -1;
1661 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1662 return -1;
1664 if (msg->hdr.ac_errno != 0) {
1665 errno = msg->hdr.ac_errno;
1666 goto out;
1669 racoon_free(msg);
1670 return 0;
1672 out:
1673 racoon_free(msg);
1674 return -1;
1677 int
1678 privsep_xauth_login_pam(port, raddr, usr, pwd)
1679 int port;
1680 struct sockaddr *raddr;
1681 char *usr;
1682 char *pwd;
1684 struct privsep_com_msg *msg;
1685 size_t len;
1686 char *data;
1687 int result;
1689 if (geteuid() == 0)
1690 return xauth_login_pam(port, raddr, usr, pwd);
1692 len = sizeof(*msg)
1693 + sizeof(port)
1694 + sizeof(isakmp_cfg_config.pool_size)
1695 + sysdep_sa_len(raddr)
1696 + strlen(usr) + 1
1697 + strlen(pwd) + 1;
1699 if ((msg = racoon_malloc(len)) == NULL) {
1700 plog(LLV_ERROR, LOCATION, NULL,
1701 "Cannot allocate memory: %s\n", strerror(errno));
1702 return -1;
1704 bzero(msg, len);
1705 msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_PAM;
1706 msg->hdr.ac_len = len;
1707 msg->bufs.buflen[0] = sizeof(port);
1708 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size);
1709 msg->bufs.buflen[2] = sysdep_sa_len(raddr);
1710 msg->bufs.buflen[3] = strlen(usr) + 1;
1711 msg->bufs.buflen[4] = strlen(pwd) + 1;
1713 data = (char *)(msg + 1);
1714 memcpy(data, &port, msg->bufs.buflen[0]);
1716 data += msg->bufs.buflen[0];
1717 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]);
1719 data += msg->bufs.buflen[1];
1720 memcpy(data, raddr, msg->bufs.buflen[2]);
1722 data += msg->bufs.buflen[2];
1723 memcpy(data, usr, msg->bufs.buflen[3]);
1725 data += msg->bufs.buflen[3];
1726 memcpy(data, pwd, msg->bufs.buflen[4]);
1728 /* frees msg */
1729 if (privsep_send(privsep_sock[1], msg, len) != 0)
1730 return -1;
1732 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1733 return -1;
1735 if (msg->hdr.ac_errno != 0) {
1736 errno = msg->hdr.ac_errno;
1737 goto out;
1740 racoon_free(msg);
1741 return 0;
1743 out:
1744 racoon_free(msg);
1745 return -1;
1748 void
1749 privsep_cleanup_pam(port)
1750 int port;
1752 struct privsep_com_msg *msg;
1753 size_t len;
1754 char *data;
1755 int result;
1757 if (geteuid() == 0)
1758 return cleanup_pam(port);
1760 len = sizeof(*msg)
1761 + sizeof(port)
1762 + sizeof(isakmp_cfg_config.pool_size);
1764 if ((msg = racoon_malloc(len)) == NULL) {
1765 plog(LLV_ERROR, LOCATION, NULL,
1766 "Cannot allocate memory: %s\n", strerror(errno));
1767 return;
1769 bzero(msg, len);
1770 msg->hdr.ac_cmd = PRIVSEP_CLEANUP_PAM;
1771 msg->hdr.ac_len = len;
1772 msg->bufs.buflen[0] = sizeof(port);
1773 msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size);
1775 data = (char *)(msg + 1);
1776 memcpy(data, &port, msg->bufs.buflen[0]);
1778 data += msg->bufs.buflen[0];
1779 memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]);
1781 /* frees msg */
1782 if (privsep_send(privsep_sock[1], msg, len) != 0)
1783 return;
1785 if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
1786 return;
1788 if (msg->hdr.ac_errno != 0)
1789 errno = msg->hdr.ac_errno;
1791 racoon_free(msg);
1792 return;
1794 #endif