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