source: rtems-libbsd/ipsec-tools/src/racoon/privsep.c @ b376ae1

55-freebsd-126-freebsd-12
Last change on this file since b376ae1 was b376ae1, checked in by Christian Mauderer <christian.mauderer@…>, on 05/03/18 at 12:15:11

ipsec-tools: Port libipsec, setkey and racoon.

Note that this replaces the libipsec from FreeBSD with the one provided
by ipsec-tools.

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