[BACK]Return to cvsd.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Annotation of src/usr.bin/cvs/cvsd.c, Revision 1.3

1.1       jfb         1: /*     $OpenBSD$       */
                      2: /*
                      3:  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  *
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. The name of the author may not be used to endorse or promote products
                     13:  *    derived from this software without specific prior written permission.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     16:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     17:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
                     18:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     19:  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     20:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     21:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     22:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     23:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26:
                     27: #include <sys/param.h>
                     28: #include <sys/stat.h>
                     29: #include <sys/wait.h>
                     30: #include <sys/uio.h>
                     31:
                     32: #include <err.h>
                     33: #include <pwd.h>
                     34: #include <grp.h>
                     35: #include <poll.h>
                     36: #include <fcntl.h>
                     37: #include <dirent.h>
                     38: #include <stdlib.h>
                     39: #include <stdio.h>
                     40: #include <unistd.h>
                     41: #include <signal.h>
                     42: #include <errno.h>
                     43: #include <string.h>
                     44: #include <sysexits.h>
                     45:
                     46: #include "log.h"
                     47: #include "sock.h"
                     48: #include "cvs.h"
                     49: #include "cvsd.h"
                     50:
                     51:
                     52: static void  cvsd_parent_loop (void);
                     53: static void  cvsd_child_loop  (void);
                     54: static int   cvsd_privdrop    (void);
                     55:
                     56:
                     57: extern char *__progname;
                     58:
                     59:
                     60:
                     61: int foreground = 0;
                     62:
1.3     ! jfb        63: volatile sig_atomic_t running = 0;
1.1       jfb        64: volatile sig_atomic_t restart = 0;
                     65:
                     66:
                     67: uid_t cvsd_uid = -1;
                     68: gid_t cvsd_gid = -1;
                     69:
                     70:
                     71: char *cvsd_root = NULL;
1.3     ! jfb        72: char *cvsd_conffile = CVSD_CONF;
1.1       jfb        73:
                     74:
                     75: static int    cvsd_privfd = -1;
                     76:
                     77:
                     78:
                     79: static TAILQ_HEAD(,cvsd_child) cvsd_children;
                     80: static volatile sig_atomic_t   cvsd_chnum = 0;
                     81: static volatile sig_atomic_t   cvsd_chmin = CVSD_CHILD_DEFMIN;
                     82: static volatile sig_atomic_t   cvsd_chmax = CVSD_CHILD_DEFMAX;
                     83:
                     84:
1.3     ! jfb        85: void   usage           (void);
        !            86: void   sighup_handler  (int);
        !            87: void   sigint_handler  (int);
        !            88: void   sigchld_handler (int);
        !            89: int    cvsd_msghdlr    (struct cvsd_child *, int);
        !            90:
        !            91:
1.1       jfb        92: /*
                     93:  * sighup_handler()
                     94:  *
                     95:  * Handler for the SIGHUP signal.
                     96:  */
                     97:
                     98: void
                     99: sighup_handler(int signo)
                    100: {
                    101:        restart = 1;
                    102: }
                    103:
                    104:
                    105: /*
                    106:  * sigint_handler()
                    107:  *
                    108:  * Handler for the SIGINT signal.
                    109:  */
                    110:
                    111: void
                    112: sigint_handler(int signo)
                    113: {
                    114: }
                    115:
                    116:
                    117: /*
                    118:  * sigchld_handler()
                    119:  *
                    120:  */
                    121:
                    122: void
                    123: sigchld_handler(int signo)
                    124: {
                    125:        int status;
                    126:
                    127:        wait(&status);
                    128:
                    129: }
                    130:
                    131:
                    132: /*
                    133:  * usage()
                    134:  *
                    135:  * Display program usage.
                    136:  */
                    137:
                    138: void
                    139: usage(void)
                    140: {
                    141:        fprintf(stderr,
1.3     ! jfb       142:            "Usage: %s [-dfpv] [-c config] [-r root] [-s path]\n"
1.1       jfb       143:            "\t-d\t\tStart the server in debugging mode (very verbose)\n"
                    144:            "\t-f\t\tStay in foreground instead of becoming a daemon\n"
                    145:            "\t-p\t\tPerform permission and ownership check on the repository\n"
                    146:            "\t-r root\tUse <root> as the root directory of the repository\n"
                    147:            "\t-s path\tUse <path> as the path for the CVS server socket\n"
                    148:            "\t-v\t\tBe verbose\n",
                    149:            __progname);
                    150: }
                    151:
                    152:
                    153: int
                    154: main(int argc, char **argv)
                    155: {
                    156:        u_int i;
                    157:        int ret, checkrepo;
                    158:        struct passwd *pwd;
                    159:        struct group *grp;
                    160:
                    161:        checkrepo = 0;
                    162:
                    163:        if (cvs_log_init(LD_STD|LD_SYSLOG, LF_PID) < 0)
                    164:                err(1, "failed to initialize logging mechanism");
                    165:
1.3     ! jfb       166:        while ((ret = getopt(argc, argv, "a:c:dfpr:s:v")) != -1) {
1.1       jfb       167:                switch (ret) {
1.3     ! jfb       168:                case 'c':
        !           169:                        cvsd_conffile = optarg;
1.1       jfb       170:                        break;
                    171:                case 'd':
                    172:                        cvs_log_filter(LP_FILTER_UNSET, LP_DEBUG);
                    173:                        cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
                    174:                        break;
                    175:                case 'f':
                    176:                        foreground = 1;
                    177:                        break;
                    178:                case 'p':
                    179:                        checkrepo = 1;
                    180:                        break;
                    181:                case 'r':
                    182:                        cvsd_root = optarg;
                    183:                        break;
                    184:                case 's':
                    185:                        cvsd_sock_path = optarg;
                    186:                        break;
                    187:                case 'v':
                    188:                        cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
                    189:                        break;
                    190:                default:
                    191:                        usage();
                    192:                        exit(EX_USAGE);
                    193:                }
                    194:        }
                    195:
                    196:        argc -= optind;
                    197:        argv += optind;
                    198:
1.3     ! jfb       199:        if (cvs_conf_read(cvsd_conffile) < 0)
        !           200:                errx(1, "error parsing configuration file `%s'", cvsd_conffile);
1.1       jfb       201:
                    202:        if (cvsd_root == NULL)
                    203:                errx(1, "no CVS root directory specified");
                    204:
                    205:        if (argc > 0)
                    206:                errx(EX_USAGE, "unrecognized trailing arguments");
                    207:
                    208:        TAILQ_INIT(&cvsd_children);
                    209:
                    210:        pwd = getpwnam(CVSD_USER);
                    211:        if (pwd == NULL)
                    212:                err(EX_NOUSER, "failed to get user `%s'", CVSD_USER);
                    213:
                    214:        grp = getgrnam(CVSD_GROUP);
                    215:        if (grp == NULL)
                    216:                err(EX_NOUSER, "failed to get group `%s'", CVSD_GROUP);
                    217:
                    218:        cvsd_uid = pwd->pw_uid;
                    219:        cvsd_gid = grp->gr_gid;
                    220:
                    221:        signal(SIGHUP, sighup_handler);
                    222:        signal(SIGINT, sigint_handler);
                    223:        signal(SIGQUIT, sigint_handler);
                    224:        signal(SIGTERM, sigint_handler);
                    225:
                    226:        if (!foreground && daemon(0, 0) == -1) {
                    227:                cvs_log(LP_ERRNO, "failed to become a daemon");
                    228:                exit(EX_OSERR);
                    229:        }
                    230:
                    231:        if (cvsd_sock_open() < 0) {
                    232:                exit(1);
                    233:        }
                    234:
                    235:        if (setegid(cvsd_gid) == -1) {
                    236:                cvs_log(LP_ERRNO, "failed to drop group privileges");
                    237:                exit(EX_OSERR);
                    238:        }
                    239:        if (seteuid(cvsd_uid) == -1) {
                    240:                cvs_log(LP_ERRNO, "failed to drop user privileges");
                    241:                exit(EX_OSERR);
                    242:        }
                    243:
                    244:        if (checkrepo && cvsd_checkperms("/") != 0) {
                    245:                cvs_log(LP_ERR,
                    246:                    "exiting due to permission errors on repository");
                    247:                exit(1);
                    248:        }
                    249:
                    250:        /* spawn the initial pool of children */
1.3     ! jfb       251:        for (i = 0; i < (u_int)cvsd_chmin; i++) {
        !           252:                ret = cvsd_child_fork(NULL);
1.1       jfb       253:                if (ret == -1) {
                    254:                        cvs_log(LP_ERR, "failed to spawn child");
                    255:                        exit(EX_OSERR);
                    256:                }
                    257:        }
                    258:
1.3     ! jfb       259:        cvsd_parent_loop();
1.1       jfb       260:
                    261:        cvs_log(LP_NOTICE, "shutting down");
                    262:        cvs_log_cleanup();
                    263:
                    264:        cvsd_sock_close();
                    265:
                    266:        return (0);
                    267: }
                    268:
                    269:
                    270: /*
                    271:  * cvsd_privdrop()
                    272:  *
                    273:  * Drop privileges.
                    274:  */
                    275:
                    276: int
                    277: cvsd_privdrop(void)
                    278: {
                    279:        cvs_log(LP_INFO, "dropping privileges to %s:%s", CVSD_USER,
                    280:            CVSD_GROUP);
1.2       jfb       281:        if (setgid(cvsd_gid) == -1) {
1.1       jfb       282:                cvs_log(LP_ERRNO, "failed to drop group privileges to %s",
                    283:                    CVSD_GROUP);
                    284:                return (-1);
                    285:        }
                    286:
1.2       jfb       287:        if (setuid(cvsd_uid) == -1) {
1.1       jfb       288:                cvs_log(LP_ERRNO, "failed to drop user privileges to %s",
                    289:                    CVSD_USER);
                    290:                return (-1);
                    291:        }
                    292:
                    293:        return (0);
                    294: }
                    295:
                    296:
                    297: /*
                    298:  * cvsd_checkperms()
                    299:  *
                    300:  * Check permissions on the CVS repository and log warnings for any
                    301:  * weird of loose permissions.
                    302:  * Returns the number of warnings on success, or -1 on failure.
                    303:  */
                    304:
                    305: int
                    306: cvsd_checkperms(const char *path)
                    307: {
                    308:        int fd, nbwarn, ret;
                    309:        mode_t fmode;
                    310:        long base;
                    311:        void *dp, *endp;
                    312:        char buf[1024], spath[MAXPATHLEN];
                    313:        struct stat st;
                    314:        struct dirent *dep;
                    315:
                    316:        nbwarn = 0;
                    317:
                    318:        cvs_log(LP_DEBUG, "checking permissions on `%s'", path);
                    319:
                    320:        if (stat(path, &st) == -1) {
                    321:                cvs_log(LP_ERRNO, "failed to stat `%s'", path);
                    322:                return (-1);
                    323:        }
                    324:
                    325:        if (S_ISDIR(st.st_mode))
                    326:                fmode = CVSD_DPERM;
                    327:        else
                    328:                fmode = CVSD_FPERM;
                    329:
                    330:        if (st.st_uid != cvsd_uid) {
                    331:                cvs_log(LP_WARN, "owner of `%s' is not %s", path, CVSD_USER);
                    332:                nbwarn++;
                    333:        }
                    334:
                    335:        if (st.st_gid != cvsd_gid) {
                    336:                cvs_log(LP_WARN, "group of `%s' is not %s", path, CVSD_GROUP);
                    337:                nbwarn++;
                    338:        }
                    339:
                    340:        if (st.st_mode & S_IWGRP) {
                    341:                cvs_log(LP_WARN, "file `%s' is group-writable", path,
                    342:                    fmode);
                    343:                nbwarn++;
                    344:        }
                    345:
                    346:        if (st.st_mode & S_IWOTH) {
                    347:                cvs_log(LP_WARN, "file `%s' is world-writable", path,
                    348:                    fmode);
                    349:                nbwarn++;
                    350:        }
                    351:
                    352:        if (S_ISDIR(st.st_mode)) {
                    353:                fd = open(path, O_RDONLY, 0);
                    354:                if (fd == -1) {
                    355:                        cvs_log(LP_ERRNO, "failed to open directory `%s'",
                    356:                            path);
                    357:                        return (nbwarn);
                    358:                }
                    359:                /* recurse */
                    360:                ret = getdirentries(fd, buf, sizeof(buf), &base);
                    361:                if (ret == -1) {
                    362:                        cvs_log(LP_ERRNO,
                    363:                            "failed to get directory entries for `%s'", path);
                    364:                        (void)close(fd);
                    365:                        return (nbwarn);
                    366:                }
                    367:
                    368:                dp = buf;
                    369:                endp = buf + ret;
                    370:
                    371:                while (dp < endp) {
                    372:                        dep = (struct dirent *)dp;
                    373:                        dp += dep->d_reclen;
                    374:
                    375:                        if ((dep->d_namlen == 1) && (dep->d_name[0] == '.'))
                    376:                                continue;
                    377:                        if ((dep->d_namlen == 2) && (dep->d_name[0] == '.') &&
                    378:                            (dep->d_name[1] == '.'))
                    379:                                continue;
                    380:
                    381:                        /* skip the CVSROOT directory */
                    382:                        if (strcmp(dep->d_name, CVS_PATH_ROOT) == 0)
                    383:                                continue;
                    384:
                    385:                        snprintf(spath, sizeof(spath), "%s/%s", path,
                    386:                            dep->d_name);
                    387:                        ret = cvsd_checkperms(spath);
                    388:                        if (ret == -1)
                    389:                                nbwarn++;
                    390:                        else
                    391:                                nbwarn += ret;
                    392:                }
                    393:                (void)close(fd);
                    394:        }
                    395:
                    396:
                    397:        return (nbwarn);
                    398: }
                    399:
                    400:
                    401: /*
1.3     ! jfb       402:  * cvsd_child_fork()
1.1       jfb       403:  *
                    404:  * Fork a child process which chroots to the CVS repository's root directory.
                    405:  * We need to temporarily regain privileges in order to chroot.
1.3     ! jfb       406:  * If the <chpp> argument is not NULL, a reference to the newly created child
        !           407:  * structure will be returned.
        !           408:  * On success, returns 0 in the child process context, 1 in the parent's
        !           409:  * context, or -1 on failure.
1.1       jfb       410:  */
                    411:
                    412: int
1.3     ! jfb       413: cvsd_child_fork(struct cvsd_child **chpp)
1.1       jfb       414: {
                    415:        int svec[2];
                    416:        pid_t pid;
                    417:        struct cvsd_child *chp;
                    418:
1.3     ! jfb       419:        if (cvsd_chnum == cvsd_chmax) {
        !           420:                cvs_log(LP_WARN, "child pool reached limit of processes");
        !           421:                return (-1);
        !           422:        }
        !           423:
1.1       jfb       424:        if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, svec) == -1) {
                    425:                cvs_log(LP_ERRNO, "failed to create socket pair");
                    426:                return (-1);
                    427:        }
                    428:
                    429:        /*
                    430:         * We need to temporarily regain original privileges in order for the
                    431:         * child to chroot().
                    432:         */
                    433:        if (seteuid(0) == -1) {
                    434:                cvs_log(LP_ERRNO, "failed to regain privileges");
                    435:                return (-1);
                    436:        }
                    437:
                    438:        pid = fork();
                    439:        if (pid == -1) {
                    440:                cvs_log(LP_ERRNO, "failed to fork child");
                    441:                (void)close(svec[0]);
                    442:                (void)close(svec[1]);
                    443:                return (-1);
                    444:        }
                    445:
                    446:        if (pid == 0) {
                    447:                cvsd_privfd = svec[1];
                    448:                (void)close(svec[0]);
                    449:
                    450:                cvs_log(LP_INFO, "changing root to %s", cvsd_root);
                    451:                if (chroot(cvsd_root) == -1) {
                    452:                        cvs_log(LP_ERRNO, "failed to chroot to `%s'",
                    453:                            cvsd_root);
                    454:                        exit(EX_OSERR);
                    455:                }
                    456:                (void)chdir("/");
                    457:
1.2       jfb       458:                if (cvsd_privdrop() < 0)
1.1       jfb       459:                        exit(EX_OSERR);
                    460:
                    461:                setproctitle("%s [child %d]", __progname, getpid());
                    462:
                    463:                cvsd_child_loop();
                    464:
                    465:                return (0);
                    466:        }
                    467:
                    468:        cvs_log(LP_INFO, "spawning child %d", pid);
                    469:
                    470:        if (seteuid(cvsd_uid) == -1) {
                    471:                cvs_log(LP_ERRNO, "failed to redrop privs");
                    472:                return (-1);
                    473:        }
                    474:
                    475:        chp = (struct cvsd_child *)malloc(sizeof(*chp));
                    476:        if (chp == NULL) {
                    477:                cvs_log(LP_ERRNO, "failed to allocate child data");
                    478:                return (-1);
                    479:        }
                    480:
                    481:        chp->ch_pid = pid;
                    482:        chp->ch_sock = svec[0];
1.3     ! jfb       483:        chp->ch_state = CVSD_ST_IDLE;
        !           484:
        !           485:        TAILQ_INSERT_TAIL(&cvsd_children, chp, ch_list);
        !           486:
        !           487:        if (chpp != NULL)
        !           488:                *chpp = chp;
1.1       jfb       489:        (void)close(svec[1]);
1.3     ! jfb       490:        return (1);
        !           491: }
        !           492:
        !           493:
        !           494: /*
        !           495:  * cvsd_child_reap()
        !           496:  *
        !           497:  * Returns 0 on success, or -1 on failure.
        !           498:  */
        !           499:
        !           500: int
        !           501: cvsd_child_reap(struct cvsd_child *ch)
        !           502: {
        !           503:
        !           504:
        !           505:        return (0);
        !           506: }
        !           507:
        !           508:
        !           509: /*
        !           510:  * cvsd_child_get()
        !           511:  *
        !           512:  * Find a child process in idle state and return a pointer to the child's
        !           513:  * structure.  If there are no available child processes, a new one will be
        !           514:  * created unless the number of children has attained the maximum, in which
        !           515:  * case NULL is returned.
        !           516:  */
        !           517:
        !           518: struct cvsd_child*
        !           519: cvsd_child_get(void)
        !           520: {
        !           521:        struct cvsd_child *chp;
1.1       jfb       522:
1.3     ! jfb       523:        TAILQ_FOREACH(chp, &cvsd_children, ch_list)
        !           524:                if (chp->ch_state == CVSD_ST_IDLE)
        !           525:                        return (chp);
        !           526:
        !           527:        /* no available child, attempt to fork a new one */
        !           528:        chp = NULL;
        !           529:        if ((cvsd_chnum < cvsd_chmax) && (cvsd_child_fork(&chp) < 0))
        !           530:                return (NULL);
        !           531:
        !           532:        return (chp);
1.1       jfb       533: }
                    534:
                    535:
1.3     ! jfb       536:
1.1       jfb       537: /*
                    538:  * cvsd_parent_loop()
                    539:  *
                    540:  * Main loop of the parent cvsd process, which listens on its end of the
1.3     ! jfb       541:  * local socket for requests from the cvs(1) program and on any outstanding
        !           542:  * messages from the children.
1.1       jfb       543:  */
                    544:
                    545: static void
                    546: cvsd_parent_loop(void)
                    547: {
1.3     ! jfb       548:        int cfd, timeout, ret;
1.1       jfb       549:        nfds_t nfds, i;
                    550:        struct pollfd *pfd;
                    551:        struct cvsd_child *chp;
                    552:
                    553:        nfds = 0;
                    554:        timeout = INFTIM;
1.3     ! jfb       555:        pfd = NULL;
1.1       jfb       556:
                    557:        for (;;) {
1.3     ! jfb       558:                if (!running)
        !           559:                        break;
        !           560:
        !           561:                if (restart) {
        !           562:                        /* restart server */
        !           563:                }
        !           564:                nfds = cvsd_chnum + 1;
1.1       jfb       565:                pfd = (struct pollfd *)realloc(pfd,
                    566:                    nfds * sizeof(struct pollfd));
                    567:                if (pfd == NULL) {
                    568:                        cvs_log(LP_ERRNO, "failed to reallocate polling data");
                    569:                        return;
                    570:                }
                    571:
1.3     ! jfb       572:                pfd[0].fd = cvsd_sock;
        !           573:                pfd[0].events = POLLIN;
        !           574:                pfd[0].revents = 0;
        !           575:                i = 1;
1.1       jfb       576:                TAILQ_FOREACH(chp, &cvsd_children, ch_list) {
                    577:                        pfd[i].fd = chp->ch_sock;
                    578:                        pfd[i].events = POLLIN;
                    579:                        pfd[i].revents = 0;
                    580:                        i++;
                    581:
1.3     ! jfb       582:                        if (i == nfds)   /* just a precaution */
1.1       jfb       583:                                break;
                    584:                }
                    585:
                    586:                ret = poll(pfd, nfds, timeout);
                    587:                if (ret == -1) {
                    588:                        cvs_log(LP_ERRNO, "poll error");
                    589:                        break;
                    590:                }
                    591:
1.3     ! jfb       592:                if (pfd[0].revents & (POLLERR|POLLNVAL)) {
        !           593:                        cvs_log(LP_ERR, "poll error on request socket");
        !           594:                }
        !           595:                else if (pfd[0].revents & POLLIN) {
        !           596:                        cfd = cvsd_sock_accept(pfd[0].fd);
        !           597:                        if (cfd == -1)
        !           598:                        chp = cvsd_child_get();
        !           599:                        if (chp == NULL) {
        !           600:                                cvs_log(LP_ALERT,
        !           601:                                    "request queue not implemented");
        !           602:                                break;
        !           603:                        }
        !           604:
        !           605:                        if (cvsd_sendmsg(chp->ch_sock, CVSD_MSG_PASSFD,
        !           606:                            &cfd, sizeof(cfd)) < 0)
        !           607:                                break;
        !           608:
        !           609:                        /* mark the child as busy */
        !           610:                        chp->ch_state = CVSD_ST_BUSY;
        !           611:                }
        !           612:
1.1       jfb       613:                chp = TAILQ_FIRST(&cvsd_children);
1.3     ! jfb       614:                for (i = 1; i < nfds; i++) {
1.1       jfb       615:                        if (pfd[i].revents & (POLLERR|POLLNVAL)) {
                    616:                                cvs_log(LP_ERR,
                    617:                                    "poll error on child socket (PID %d)",
                    618:                                    chp->ch_pid);
                    619:                        }
1.3     ! jfb       620:                        else if (pfd[i].revents & POLLIN)
1.1       jfb       621:                                cvsd_msghdlr(chp, pfd[i].fd);
                    622:
                    623:                        chp = TAILQ_NEXT(chp, ch_list);
                    624:                }
                    625:
                    626:        }
                    627: }
                    628:
                    629:
                    630: /*
                    631:  * cvsd_child_loop()
                    632:  *
                    633:  */
                    634:
                    635: static void
                    636: cvsd_child_loop(void)
                    637: {
                    638:        int ret, timeout;
1.3     ! jfb       639:        uid_t uid;
        !           640:        gid_t gid;
1.1       jfb       641:        struct pollfd pfd[1];
                    642:
                    643:        pfd[0].fd = cvsd_privfd;
                    644:        pfd[0].events = POLLIN;
                    645:        timeout = INFTIM;
                    646:
                    647:        for (;;) {
                    648:                ret = poll(pfd, 1, timeout);
                    649:                if (ret == -1) {
                    650:                }
                    651:                else if (ret == 0) {
                    652:                        cvs_log(LP_INFO, "parent process closed descriptor");
                    653:                        break;
                    654:                }
                    655:                cvs_log(LP_INFO, "polling");
                    656:
1.3     ! jfb       657:                if (pfd[0].revents & (POLLERR|POLLNVAL)) {
        !           658:                        cvs_log(LP_ERR, "poll error");
        !           659:                        break;
        !           660:                }
1.1       jfb       661:        }
                    662:
                    663:        exit(0);
                    664: }
                    665:
                    666:
                    667: /*
                    668:  * cvsd_msghdlr()
1.3     ! jfb       669:  *
        !           670:  * Handler for messages received from child processes.
        !           671:  * Returns 0 on success, or -1 on failure.
1.1       jfb       672:  */
                    673:
                    674: int
                    675: cvsd_msghdlr(struct cvsd_child *child, int fd)
                    676: {
                    677:        uid_t uid;
                    678:        ssize_t ret;
                    679:        char rbuf[CVSD_MSG_MAXLEN];
                    680:        struct group *gr;
                    681:        struct passwd *pw;
                    682:        struct iovec iov[2];
                    683:        struct cvsd_msg msg;
                    684:
                    685:        ret = read(fd, &msg, sizeof(msg));
                    686:        if (ret == -1) {
                    687:                cvs_log(LP_ERRNO, "failed to read CVS message");
                    688:                return (-1);
                    689:        }
                    690:        else if (ret == 0) {
                    691:                cvs_log(LP_WARN, "child closed socket pair");
                    692:                return (0);
                    693:        }
                    694:
                    695:        if (msg.cm_len > 0) {
                    696:                ret = read(fd, rbuf, msg.cm_len);
                    697:                if (ret != (ssize_t)msg.cm_len) {
                    698:                        cvs_log(LP_ERR, "failed to read entire msg");
                    699:                        return (-1);
                    700:                }
                    701:        }
                    702:
                    703:        /* setup the I/O vector for the reply */
                    704:        iov[0].iov_base = &msg;
                    705:        iov[0].iov_len = sizeof(msg);
                    706:
                    707:        msg.cm_type = CVSD_MSG_ERROR;
                    708:        msg.cm_len = 0;
                    709:
                    710:        switch (msg.cm_type) {
                    711:        case CVSD_MSG_GETUID:
                    712:                rbuf[ret] = '\0';
                    713:                cvs_log(LP_INFO, "getting UID for `%s'", rbuf);
                    714:
                    715:                pw = getpwnam(rbuf);
                    716:                if (pw != NULL) {
                    717:                        msg.cm_type = CVSD_MSG_UID;
                    718:                        msg.cm_len = sizeof(uid_t);
                    719:                        iov[1].iov_len = msg.cm_len;
                    720:                        iov[1].iov_base = &(pw->pw_uid);
                    721:                }
                    722:                break;
                    723:        case CVSD_MSG_GETUNAME:
                    724:                memcpy(&uid, rbuf, sizeof(uid));
                    725:                cvs_log(LP_INFO, "getting username for UID %u", uid);
                    726:                pw = getpwuid(uid);
                    727:                if (pw != NULL) {
                    728:                        msg.cm_type = CVSD_MSG_UNAME;
                    729:                        msg.cm_len = strlen(pw->pw_name);
                    730:                        iov[1].iov_len = msg.cm_len;
                    731:                        iov[1].iov_base = pw->pw_name;
                    732:                }
                    733:                break;
1.3     ! jfb       734:        case CVSD_MSG_GETGID:
        !           735:                rbuf[ret] = '\0';
        !           736:                cvs_log(LP_INFO, "getting GID for `%s'", rbuf);
        !           737:
        !           738:                gr = getgrnam(rbuf);
        !           739:                if (gr != NULL) {
        !           740:                        msg.cm_type = CVSD_MSG_GID;
        !           741:                        msg.cm_len = sizeof(gid_t);
        !           742:                        iov[1].iov_len = msg.cm_len;
        !           743:                        iov[1].iov_base = &(gr->gr_gid);
        !           744:                }
        !           745:                break;
        !           746:        case CVSD_MSG_SETIDLE:
        !           747:                child->ch_state = CVSD_ST_IDLE;
        !           748:                break;
1.1       jfb       749:        default:
                    750:                cvs_log(LP_ERR, "unknown command type %u", msg.cm_type);
                    751:                return (-1);
                    752:        }
                    753:
                    754:        ret = writev(fd, iov, 2);
                    755:
                    756:        return (ret);
1.3     ! jfb       757: }
        !           758:
        !           759:
        !           760: /*
        !           761:  * cvsd_set()
        !           762:  *
        !           763:  * Generic interface to set some of the parameters of the cvs server.
        !           764:  * Returns 0 on success, or -1 on failure.
        !           765:  */
        !           766:
        !           767: int
        !           768: cvsd_set(int what, ...)
        !           769: {
        !           770:        char *str;
        !           771:        va_list vap;
        !           772:
        !           773:        va_start(vap, what);
        !           774:
        !           775:        switch (what) {
        !           776:        case CVSD_SET_ROOT:
        !           777:                str = va_arg(vap, char *);
        !           778:                cvsd_root = str;
        !           779:                break;
        !           780:        case CVSD_SET_CHMIN:
        !           781:                cvsd_chmin = va_arg(vap, int);
        !           782:                /* we should increase the number of children accordingly */
        !           783:                break;
        !           784:        case CVSD_SET_CHMAX:
        !           785:                cvsd_chmax = va_arg(vap, int);
        !           786:                /* we should decrease the number of children accordingly */
        !           787:                break;
        !           788:        case CVSD_SET_ADDR:
        !           789:                /* this is more like and add than a set */
        !           790:                break;
        !           791:        case CVSD_SET_SOCK:
        !           792:                cvsd_sock_path = va_arg(vap, char *);
        !           793:                if (cvsd_sock_open() < 0)
        !           794:                        return (-1);
        !           795:                break;
        !           796:        default:
        !           797:                cvs_log(LP_ERR, "invalid field to set");
        !           798:                return (-1);
        !           799:        }
        !           800:
        !           801:        va_end(vap);
        !           802:
        !           803:        return (0);
1.1       jfb       804: }