Annotation of embedaddon/spawn-fcgi/src/spawn-fcgi.c, revision 1.1

1.1     ! misho       1: #ifdef HAVE_CONFIG_H
        !             2: # include "config.h"
        !             3: #endif
        !             4: 
        !             5: #include <sys/types.h>
        !             6: #include <sys/time.h>
        !             7: #include <sys/stat.h>
        !             8: 
        !             9: #include <stdlib.h>
        !            10: #include <string.h>
        !            11: #include <errno.h>
        !            12: #include <stdio.h>
        !            13: #include <unistd.h>
        !            14: #include <fcntl.h>
        !            15: 
        !            16: #ifdef HAVE_PWD_H
        !            17: # include <grp.h>
        !            18: # include <pwd.h>
        !            19: #endif
        !            20: 
        !            21: #ifdef HAVE_GETOPT_H
        !            22: # include <getopt.h>
        !            23: #endif
        !            24: 
        !            25: #define FCGI_LISTENSOCK_FILENO 0
        !            26: 
        !            27: /* "sys-socket.h" */
        !            28: #ifdef __WIN32
        !            29: 
        !            30: # include <winsock2.h>
        !            31: 
        !            32: # define ECONNRESET WSAECONNRESET
        !            33: # define EINPROGRESS WSAEINPROGRESS
        !            34: # define EALREADY WSAEALREADY
        !            35: # define ECONNABORTED WSAECONNABORTED
        !            36: # define ioctl ioctlsocket
        !            37: # define hstrerror(x) ""
        !            38: 
        !            39: #else /* _WIN32 */
        !            40: 
        !            41: # include <sys/socket.h>
        !            42: # include <sys/ioctl.h>
        !            43: # include <netinet/in.h>
        !            44: # include <netinet/tcp.h>
        !            45: # include <sys/un.h>
        !            46: # include <arpa/inet.h>
        !            47: 
        !            48: # include <netdb.h>
        !            49: 
        !            50: #endif /* _WIN32 */
        !            51: /* end "sys-socket.h" */
        !            52: 
        !            53: #ifdef HAVE_SYS_WAIT_H
        !            54: # include <sys/wait.h>
        !            55: #endif
        !            56: 
        !            57: /* for solaris 2.5 and netbsd 1.3.x */
        !            58: #ifndef HAVE_SOCKLEN_T
        !            59: typedef int socklen_t;
        !            60: #endif
        !            61: 
        !            62: #ifndef HAVE_ISSETUGID
        !            63: static int issetugid() {
        !            64:        return (geteuid() != getuid() || getegid() != getgid());
        !            65: }
        !            66: #endif
        !            67: 
        !            68: #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
        !            69: # define USE_IPV6
        !            70: #endif
        !            71: 
        !            72: #ifdef USE_IPV6
        !            73: #define PACKAGE_FEATURES " (ipv6)"
        !            74: #else
        !            75: #define PACKAGE_FEATURES ""
        !            76: #endif
        !            77: 
        !            78: #define PACKAGE_DESC "spawn-fcgi v" PACKAGE_VERSION PACKAGE_FEATURES " - spawns FastCGI processes\n"
        !            79: 
        !            80: #define CONST_STR_LEN(s) s, sizeof(s) - 1
        !            81: 
        !            82: static int bind_socket(const char *addr, unsigned short port, const char *unixsocket, uid_t uid, gid_t gid, int mode) {
        !            83:        int fcgi_fd, socket_type, val;
        !            84: 
        !            85:        struct sockaddr_un fcgi_addr_un;
        !            86:        struct sockaddr_in fcgi_addr_in;
        !            87: #ifdef USE_IPV6
        !            88:        struct sockaddr_in6 fcgi_addr_in6;
        !            89: #endif
        !            90:        struct sockaddr *fcgi_addr;
        !            91: 
        !            92:        socklen_t servlen;
        !            93: 
        !            94:        if (unixsocket) {
        !            95:                memset(&fcgi_addr_un, 0, sizeof(fcgi_addr_un));
        !            96: 
        !            97:                fcgi_addr_un.sun_family = AF_UNIX;
        !            98:                strcpy(fcgi_addr_un.sun_path, unixsocket);
        !            99: 
        !           100: #ifdef SUN_LEN
        !           101:                servlen = SUN_LEN(&fcgi_addr_un);
        !           102: #else
        !           103:                /* stevens says: */
        !           104:                servlen = strlen(fcgi_addr_un.sun_path) + sizeof(fcgi_addr_un.sun_family);
        !           105: #endif
        !           106:                socket_type = AF_UNIX;
        !           107:                fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
        !           108: 
        !           109:                /* check if some backend is listening on the socket
        !           110:                 * as if we delete the socket-file and rebind there will be no "socket already in use" error
        !           111:                 */
        !           112:                if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
        !           113:                        fprintf(stderr, "spawn-fcgi: couldn't create socket: %s\n", strerror(errno));
        !           114:                        return -1;
        !           115:                }
        !           116: 
        !           117:                if (0 == connect(fcgi_fd, fcgi_addr, servlen)) {
        !           118:                        fprintf(stderr, "spawn-fcgi: socket is already in use, can't spawn\n");
        !           119:                        close(fcgi_fd);
        !           120:                        return -1;
        !           121:                }
        !           122: 
        !           123:                /* cleanup previous socket if it exists */
        !           124:                if (-1 == unlink(unixsocket)) {
        !           125:                        switch (errno) {
        !           126:                        case ENOENT:
        !           127:                                break;
        !           128:                        default:
        !           129:                                fprintf(stderr, "spawn-fcgi: removing old socket failed: %s\n", strerror(errno));
        !           130:                                return -1;
        !           131:                        }
        !           132:                }
        !           133: 
        !           134:                close(fcgi_fd);
        !           135:        } else {
        !           136:                memset(&fcgi_addr_in, 0, sizeof(fcgi_addr_in));
        !           137:                fcgi_addr_in.sin_family = AF_INET;
        !           138:                fcgi_addr_in.sin_port = htons(port);
        !           139: 
        !           140:                servlen = sizeof(fcgi_addr_in);
        !           141:                socket_type = AF_INET;
        !           142:                fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
        !           143: 
        !           144: #ifdef USE_IPV6
        !           145:                memset(&fcgi_addr_in6, 0, sizeof(fcgi_addr_in6));
        !           146:                fcgi_addr_in6.sin6_family = AF_INET6;
        !           147:                fcgi_addr_in6.sin6_port = fcgi_addr_in.sin_port;
        !           148: #endif
        !           149: 
        !           150:                if (addr == NULL) {
        !           151:                        fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
        !           152: #ifdef HAVE_INET_PTON
        !           153:                } else if (1 == inet_pton(AF_INET, addr, &fcgi_addr_in.sin_addr)) {
        !           154:                        /* nothing to do */
        !           155: #ifdef HAVE_IPV6
        !           156:                } else if (1 == inet_pton(AF_INET6, addr, &fcgi_addr_in6.sin6_addr)) {
        !           157:                        servlen = sizeof(fcgi_addr_in6);
        !           158:                        socket_type = AF_INET6;
        !           159:                        fcgi_addr = (struct sockaddr *) &fcgi_addr_in6;
        !           160: #endif
        !           161:                } else {
        !           162:                        fprintf(stderr, "spawn-fcgi: '%s' is not a valid IP address\n", addr);
        !           163:                        return -1;
        !           164: #else
        !           165:                } else {
        !           166:                        if ((in_addr_t)(-1) == (fcgi_addr_in.sin_addr.s_addr = inet_addr(addr))) {
        !           167:                                fprintf(stderr, "spawn-fcgi: '%s' is not a valid IPv4 address\n", addr);
        !           168:                                return -1;
        !           169:                        }
        !           170: #endif
        !           171:                }
        !           172:        }
        !           173: 
        !           174: 
        !           175:        if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
        !           176:                fprintf(stderr, "spawn-fcgi: couldn't create socket: %s\n", strerror(errno));
        !           177:                return -1;
        !           178:        }
        !           179: 
        !           180:        val = 1;
        !           181:        if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
        !           182:                fprintf(stderr, "spawn-fcgi: couldn't set SO_REUSEADDR: %s\n", strerror(errno));
        !           183:                return -1;
        !           184:        }
        !           185: 
        !           186:        if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
        !           187:                fprintf(stderr, "spawn-fcgi: bind failed: %s\n", strerror(errno));
        !           188:                return -1;
        !           189:        }
        !           190: 
        !           191:        if (unixsocket) {
        !           192:                if (0 != uid || 0 != gid) {
        !           193:                        if (0 == uid) uid = -1;
        !           194:                        if (0 == gid) gid = -1;
        !           195:                        if (-1 == chown(unixsocket, uid, gid)) {
        !           196:                                fprintf(stderr, "spawn-fcgi: couldn't chown socket: %s\n", strerror(errno));
        !           197:                                close(fcgi_fd);
        !           198:                                unlink(unixsocket);
        !           199:                                return -1;
        !           200:                        }
        !           201:                }
        !           202: 
        !           203:                if (-1 != mode && -1 == chmod(unixsocket, mode)) {
        !           204:                        fprintf(stderr, "spawn-fcgi: couldn't chmod socket: %s\n", strerror(errno));
        !           205:                        close(fcgi_fd);
        !           206:                        unlink(unixsocket);
        !           207:                        return -1;
        !           208:                }
        !           209:        }
        !           210: 
        !           211:        if (-1 == listen(fcgi_fd, 1024)) {
        !           212:                fprintf(stderr, "spawn-fcgi: listen failed: %s\n", strerror(errno));
        !           213:                return -1;
        !           214:        }
        !           215: 
        !           216:        return fcgi_fd;
        !           217: }
        !           218: 
        !           219: static int fcgi_spawn_connection(char *appPath, char **appArgv, int fcgi_fd, int fork_count, int child_count, int pid_fd, int nofork) {
        !           220:        int status, rc = 0;
        !           221:        struct timeval tv = { 0, 100 * 1000 };
        !           222: 
        !           223:        pid_t child;
        !           224: 
        !           225:        while (fork_count-- > 0) {
        !           226: 
        !           227:                if (!nofork) {
        !           228:                        child = fork();
        !           229:                } else {
        !           230:                        child = 0;
        !           231:                }
        !           232: 
        !           233:                switch (child) {
        !           234:                case 0: {
        !           235:                        char cgi_childs[64];
        !           236:                        int max_fd = 0;
        !           237: 
        !           238:                        int i = 0;
        !           239: 
        !           240:                        if (child_count >= 0) {
        !           241:                                snprintf(cgi_childs, sizeof(cgi_childs), "PHP_FCGI_CHILDREN=%d", child_count);
        !           242:                                putenv(cgi_childs);
        !           243:                        }
        !           244: 
        !           245:                        if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
        !           246:                                close(FCGI_LISTENSOCK_FILENO);
        !           247:                                dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
        !           248:                                close(fcgi_fd);
        !           249:                        }
        !           250: 
        !           251:                        /* loose control terminal */
        !           252:                        if (!nofork) {
        !           253:                                setsid();
        !           254: 
        !           255:                                max_fd = open("/dev/null", O_RDWR);
        !           256:                                if (-1 != max_fd) {
        !           257:                                        if (max_fd != STDOUT_FILENO) dup2(max_fd, STDOUT_FILENO);
        !           258:                                        if (max_fd != STDERR_FILENO) dup2(max_fd, STDERR_FILENO);
        !           259:                                        if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO) close(max_fd);
        !           260:                                } else {
        !           261:                                        fprintf(stderr, "spawn-fcgi: couldn't open and redirect stdout/stderr to '/dev/null': %s\n", strerror(errno));
        !           262:                                }
        !           263:                        }
        !           264: 
        !           265:                        /* we don't need the client socket */
        !           266:                        for (i = 3; i < max_fd; i++) {
        !           267:                                if (i != FCGI_LISTENSOCK_FILENO) close(i);
        !           268:                        }
        !           269: 
        !           270:                        /* fork and replace shell */
        !           271:                        if (appArgv) {
        !           272:                                execv(appArgv[0], appArgv);
        !           273: 
        !           274:                        } else {
        !           275:                                char *b = malloc((sizeof("exec ") - 1) + strlen(appPath) + 1);
        !           276:                                strcpy(b, "exec ");
        !           277:                                strcat(b, appPath);
        !           278: 
        !           279:                                /* exec the cgi */
        !           280:                                execl("/bin/sh", "sh", "-c", b, (char *)NULL);
        !           281:                        }
        !           282: 
        !           283:                        /* in nofork mode stderr is still open */
        !           284:                        fprintf(stderr, "spawn-fcgi: exec failed: %s\n", strerror(errno));
        !           285:                        exit(errno);
        !           286: 
        !           287:                        break;
        !           288:                }
        !           289:                case -1:
        !           290:                        /* error */
        !           291:                        fprintf(stderr, "spawn-fcgi: fork failed: %s\n", strerror(errno));
        !           292:                        break;
        !           293:                default:
        !           294:                        /* father */
        !           295: 
        !           296:                        /* wait */
        !           297:                        select(0, NULL, NULL, NULL, &tv);
        !           298: 
        !           299:                        switch (waitpid(child, &status, WNOHANG)) {
        !           300:                        case 0:
        !           301:                                fprintf(stdout, "spawn-fcgi: child spawned successfully: PID: %d\n", child);
        !           302: 
        !           303:                                /* write pid file */
        !           304:                                if (pid_fd != -1) {
        !           305:                                        /* assume a 32bit pid_t */
        !           306:                                        char pidbuf[12];
        !           307: 
        !           308:                                        snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
        !           309: 
        !           310:                                        write(pid_fd, pidbuf, strlen(pidbuf));
        !           311:                                        /* avoid eol for the last one */
        !           312:                                        if (fork_count != 0) {
        !           313:                                                write(pid_fd, "\n", 1);
        !           314:                                        }
        !           315:                                }
        !           316: 
        !           317:                                break;
        !           318:                        case -1:
        !           319:                                break;
        !           320:                        default:
        !           321:                                if (WIFEXITED(status)) {
        !           322:                                        fprintf(stderr, "spawn-fcgi: child exited with: %d\n",
        !           323:                                                WEXITSTATUS(status));
        !           324:                                        rc = WEXITSTATUS(status);
        !           325:                                } else if (WIFSIGNALED(status)) {
        !           326:                                        fprintf(stderr, "spawn-fcgi: child signaled: %d\n",
        !           327:                                                WTERMSIG(status));
        !           328:                                        rc = 1;
        !           329:                                } else {
        !           330:                                        fprintf(stderr, "spawn-fcgi: child died somehow: exit status = %d\n",
        !           331:                                                status);
        !           332:                                        rc = status;
        !           333:                                }
        !           334:                        }
        !           335: 
        !           336:                        break;
        !           337:                }
        !           338:        }
        !           339:        close(pid_fd);
        !           340: 
        !           341:        close(fcgi_fd);
        !           342: 
        !           343:        return rc;
        !           344: }
        !           345: 
        !           346: static int find_user_group(const char *user, const char *group, uid_t *uid, gid_t *gid, const char **username) {
        !           347:        uid_t my_uid = 0;
        !           348:        gid_t my_gid = 0;
        !           349:        struct passwd *my_pwd = NULL;
        !           350:        struct group *my_grp = NULL;
        !           351:        char *endptr = NULL;
        !           352:        *uid = 0; *gid = 0;
        !           353:        if (username) *username = NULL;
        !           354: 
        !           355:        if (user) {
        !           356:                my_uid = strtol(user, &endptr, 10);
        !           357: 
        !           358:                if (my_uid <= 0 || *endptr) {
        !           359:                        if (NULL == (my_pwd = getpwnam(user))) {
        !           360:                                fprintf(stderr, "spawn-fcgi: can't find user name %s\n", user);
        !           361:                                return -1;
        !           362:                        }
        !           363:                        my_uid = my_pwd->pw_uid;
        !           364: 
        !           365:                        if (my_uid == 0) {
        !           366:                                fprintf(stderr, "spawn-fcgi: I will not set uid to 0\n");
        !           367:                                return -1;
        !           368:                        }
        !           369: 
        !           370:                        if (username) *username = user;
        !           371:                } else {
        !           372:                        my_pwd = getpwuid(my_uid);
        !           373:                        if (username && my_pwd) *username = my_pwd->pw_name;
        !           374:                }
        !           375:        }
        !           376: 
        !           377:        if (group) {
        !           378:                my_gid = strtol(group, &endptr, 10);
        !           379: 
        !           380:                if (my_gid <= 0 || *endptr) {
        !           381:                        if (NULL == (my_grp = getgrnam(group))) {
        !           382:                                fprintf(stderr, "spawn-fcgi: can't find group name %s\n", group);
        !           383:                                return -1;
        !           384:                        }
        !           385:                        my_gid = my_grp->gr_gid;
        !           386: 
        !           387:                        if (my_gid == 0) {
        !           388:                                fprintf(stderr, "spawn-fcgi: I will not set gid to 0\n");
        !           389:                                return -1;
        !           390:                        }
        !           391:                }
        !           392:        } else if (my_pwd) {
        !           393:                my_gid = my_pwd->pw_gid;
        !           394: 
        !           395:                if (my_gid == 0) {
        !           396:                        fprintf(stderr, "spawn-fcgi: I will not set gid to 0\n");
        !           397:                        return -1;
        !           398:                }
        !           399:        }
        !           400: 
        !           401:        *uid = my_uid;
        !           402:        *gid = my_gid;
        !           403:        return 0;
        !           404: }
        !           405: 
        !           406: static void show_version () {
        !           407:        write(1, CONST_STR_LEN(
        !           408:                PACKAGE_DESC \
        !           409:                "Build-Date: " __DATE__ " " __TIME__ "\n"
        !           410:        ));
        !           411: }
        !           412: 
        !           413: static void show_help () {
        !           414:        write(1, CONST_STR_LEN(
        !           415:                "Usage: spawn-fcgi [options] [-- <fcgiapp> [fcgi app arguments]]\n" \
        !           416:                "\n" \
        !           417:                PACKAGE_DESC \
        !           418:                "\n" \
        !           419:                "Options:\n" \
        !           420:                " -f <path>      filename of the fcgi-application (deprecated; ignored if\n" \
        !           421:                "                <fcgiapp> is given; needs /bin/sh)\n" \
        !           422:                " -d <directory> chdir to directory before spawning\n" \
        !           423:                " -a <address>   bind to IPv4/IPv6 address (defaults to 0.0.0.0)\n" \
        !           424:                " -p <port>      bind to TCP-port\n" \
        !           425:                " -s <path>      bind to Unix domain socket\n" \
        !           426:                " -M <mode>      change Unix domain socket mode\n" \
        !           427:                " -C <children>  (PHP only) numbers of childs to spawn (default: not setting\n" \
        !           428:                "                the PHP_FCGI_CHILDREN environment variable - PHP defaults to 0)\n" \
        !           429:                " -F <children>  number of children to fork (default 1)\n" \
        !           430:                " -P <path>      name of PID-file for spawned process (ignored in no-fork mode)\n" \
        !           431:                " -n             no fork (for daemontools)\n" \
        !           432:                " -v             show version\n" \
        !           433:                " -?, -h         show this help\n" \
        !           434:                "(root only)\n" \
        !           435:                " -c <directory> chroot to directory\n" \
        !           436:                " -S             create socket before chroot() (default is to create the socket\n" \
        !           437:                "                in the chroot)\n" \
        !           438:                " -u <user>      change to user-id\n" \
        !           439:                " -g <group>     change to group-id (default: primary group of user if -u\n" \
        !           440:                "                is given)\n" \
        !           441:                " -U <user>      change Unix domain socket owner to user-id\n" \
        !           442:                " -G <group>     change Unix domain socket group to group-id\n" \
        !           443:        ));
        !           444: }
        !           445: 
        !           446: 
        !           447: int main(int argc, char **argv) {
        !           448:        char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
        !           449:             *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
        !           450:             *sockusername = NULL, *sockgroupname = NULL, *fcgi_dir = NULL,
        !           451:             *addr = NULL;
        !           452:        char **fcgi_app_argv = { NULL };
        !           453:        char *endptr = NULL;
        !           454:        unsigned short port = 0;
        !           455:        int sockmode = -1;
        !           456:        int child_count = -1;
        !           457:        int fork_count = 1;
        !           458:        int i_am_root, o;
        !           459:        int pid_fd = -1;
        !           460:        int nofork = 0;
        !           461:        int sockbeforechroot = 0;
        !           462:        struct sockaddr_un un;
        !           463:        int fcgi_fd = -1;
        !           464: 
        !           465:        if (argc < 2) { /* no arguments given */
        !           466:                show_help();
        !           467:                return -1;
        !           468:        }
        !           469: 
        !           470:        i_am_root = (getuid() == 0);
        !           471: 
        !           472:        while (-1 != (o = getopt(argc, argv, "c:d:f:g:?hna:p:u:vC:F:s:P:U:G:M:S"))) {
        !           473:                switch(o) {
        !           474:                case 'f': fcgi_app = optarg; break;
        !           475:                case 'd': fcgi_dir = optarg; break;
        !           476:                case 'a': addr = optarg;/* ip addr */ break;
        !           477:                case 'p': port = strtol(optarg, &endptr, 10);/* port */
        !           478:                        if (*endptr) {
        !           479:                                fprintf(stderr, "spawn-fcgi: invalid port: %u\n", (unsigned int) port);
        !           480:                                return -1;
        !           481:                        }
        !           482:                        break;
        !           483:                case 'C': child_count = strtol(optarg, NULL, 10);/*  */ break;
        !           484:                case 'F': fork_count = strtol(optarg, NULL, 10);/*  */ break;
        !           485:                case 's': unixsocket = optarg; /* unix-domain socket */ break;
        !           486:                case 'c': if (i_am_root) { changeroot = optarg; }/* chroot() */ break;
        !           487:                case 'u': if (i_am_root) { username = optarg; } /* set user */ break;
        !           488:                case 'g': if (i_am_root) { groupname = optarg; } /* set group */ break;
        !           489:                case 'U': if (i_am_root) { sockusername = optarg; } /* set socket user */ break;
        !           490:                case 'G': if (i_am_root) { sockgroupname = optarg; } /* set socket group */ break;
        !           491:                case 'S': if (i_am_root) { sockbeforechroot = 1; } /* open socket before chroot() */ break;
        !           492:                case 'M': sockmode = strtol(optarg, NULL, 0); /* set socket mode */ break;
        !           493:                case 'n': nofork = 1; break;
        !           494:                case 'P': pid_file = optarg; /* PID file */ break;
        !           495:                case 'v': show_version(); return 0;
        !           496:                case '?':
        !           497:                case 'h': show_help(); return 0;
        !           498:                default:
        !           499:                        show_help();
        !           500:                        return -1;
        !           501:                }
        !           502:        }
        !           503: 
        !           504:        if (optind < argc) {
        !           505:                fcgi_app_argv = &argv[optind];
        !           506:        }
        !           507: 
        !           508:        if (NULL == fcgi_app && NULL == fcgi_app_argv) {
        !           509:                fprintf(stderr, "spawn-fcgi: no FastCGI application given\n");
        !           510:                return -1;
        !           511:        }
        !           512: 
        !           513:        if (0 == port && NULL == unixsocket) {
        !           514:                fprintf(stderr, "spawn-fcgi: no socket given (use either -p or -s)\n");
        !           515:                return -1;
        !           516:        } else if (0 != port && NULL != unixsocket) {
        !           517:                fprintf(stderr, "spawn-fcgi: either a Unix domain socket or a TCP-port, but not both\n");
        !           518:                return -1;
        !           519:        }
        !           520: 
        !           521:        if (unixsocket && strlen(unixsocket) > sizeof(un.sun_path) - 1) {
        !           522:                fprintf(stderr, "spawn-fcgi: path of the Unix domain socket is too long\n");
        !           523:                return -1;
        !           524:        }
        !           525: 
        !           526:        /* SUID handling */
        !           527:        if (!i_am_root && issetugid()) {
        !           528:                fprintf(stderr, "spawn-fcgi: Are you nuts? Don't apply a SUID bit to this binary\n");
        !           529:                return -1;
        !           530:        }
        !           531: 
        !           532:        if (nofork) pid_file = NULL; /* ignore pid file in no-fork mode */
        !           533: 
        !           534:        if (pid_file &&
        !           535:            (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
        !           536:                struct stat st;
        !           537:                if (errno != EEXIST) {
        !           538:                        fprintf(stderr, "spawn-fcgi: opening PID-file '%s' failed: %s\n",
        !           539:                                pid_file, strerror(errno));
        !           540:                        return -1;
        !           541:                }
        !           542: 
        !           543:                /* ok, file exists */
        !           544: 
        !           545:                if (0 != stat(pid_file, &st)) {
        !           546:                        fprintf(stderr, "spawn-fcgi: stating PID-file '%s' failed: %s\n",
        !           547:                                pid_file, strerror(errno));
        !           548:                        return -1;
        !           549:                }
        !           550: 
        !           551:                /* is it a regular file ? */
        !           552: 
        !           553:                if (!S_ISREG(st.st_mode)) {
        !           554:                        fprintf(stderr, "spawn-fcgi: PID-file exists and isn't regular file: '%s'\n",
        !           555:                                pid_file);
        !           556:                        return -1;
        !           557:                }
        !           558: 
        !           559:                if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
        !           560:                        fprintf(stderr, "spawn-fcgi: opening PID-file '%s' failed: %s\n",
        !           561:                                pid_file, strerror(errno));
        !           562:                        return -1;
        !           563:                }
        !           564:        }
        !           565: 
        !           566:        if (i_am_root) {
        !           567:                uid_t uid, sockuid;
        !           568:                gid_t gid, sockgid;
        !           569:                const char* real_username;
        !           570: 
        !           571:                if (-1 == find_user_group(username, groupname, &uid, &gid, &real_username))
        !           572:                        return -1;
        !           573: 
        !           574:                if (-1 == find_user_group(sockusername, sockgroupname, &sockuid, &sockgid, NULL))
        !           575:                        return -1;
        !           576: 
        !           577:                if (uid != 0 && gid == 0) {
        !           578:                        fprintf(stderr, "spawn-fcgi: WARNING: couldn't find the user for uid %i and no group was specified, so only the user privileges will be dropped\n", (int) uid);
        !           579:                }
        !           580: 
        !           581:                if (0 == sockuid) sockuid = uid;
        !           582:                if (0 == sockgid) sockgid = gid;
        !           583: 
        !           584:                if (sockbeforechroot && -1 == (fcgi_fd = bind_socket(addr, port, unixsocket, sockuid, sockgid, sockmode)))
        !           585:                        return -1;
        !           586: 
        !           587:                /* Change group before chroot, when we have access
        !           588:                 * to /etc/group
        !           589:                 */
        !           590:                if (gid != 0) {
        !           591:                        setgid(gid);
        !           592:                        setgroups(0, NULL);
        !           593:                        if (real_username) {
        !           594:                                initgroups(real_username, gid);
        !           595:                        }
        !           596:                }
        !           597: 
        !           598:                if (changeroot) {
        !           599:                        if (-1 == chroot(changeroot)) {
        !           600:                                fprintf(stderr, "spawn-fcgi: chroot('%s') failed: %s\n", changeroot, strerror(errno));
        !           601:                                return -1;
        !           602:                        }
        !           603:                        if (-1 == chdir("/")) {
        !           604:                                fprintf(stderr, "spawn-fcgi: chdir('/') failed: %s\n", strerror(errno));
        !           605:                                return -1;
        !           606:                        }
        !           607:                }
        !           608: 
        !           609:                if (!sockbeforechroot && -1 == (fcgi_fd = bind_socket(addr, port, unixsocket, sockuid, sockgid, sockmode)))
        !           610:                        return -1;
        !           611: 
        !           612:                /* drop root privs */
        !           613:                if (uid != 0) {
        !           614:                        setuid(uid);
        !           615:                }
        !           616:        } else {
        !           617:                if (-1 == (fcgi_fd = bind_socket(addr, port, unixsocket, 0, 0, sockmode)))
        !           618:                        return -1;
        !           619:        }
        !           620: 
        !           621:        if (fcgi_dir && -1 == chdir(fcgi_dir)) {
        !           622:                fprintf(stderr, "spawn-fcgi: chdir('%s') failed: %s\n", fcgi_dir, strerror(errno));
        !           623:                return -1;
        !           624:        }
        !           625: 
        !           626:        return fcgi_spawn_connection(fcgi_app, fcgi_app_argv, fcgi_fd, fork_count, child_count, pid_fd, nofork);
        !           627: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>