Annotation of embedaddon/strongswan/src/libstrongswan/utils/process.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2014 Martin Willi
                      3:  * Copyright (C) 2014 revosec AG
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: /* vasprintf() */
                     17: #define _GNU_SOURCE
                     18: #include "process.h"
                     19: 
                     20: #include <library.h>
                     21: #include <utils/debug.h>
                     22: 
                     23: #include <fcntl.h>
                     24: #include <stdio.h>
                     25: #include <stdarg.h>
                     26: 
                     27: typedef struct private_process_t private_process_t;
                     28: 
                     29: /**
                     30:  * Ends of a pipe()
                     31:  */
                     32: enum {
                     33:        PIPE_READ = 0,
                     34:        PIPE_WRITE = 1,
                     35:        PIPE_ENDS,
                     36: };
                     37: 
                     38: #ifndef WIN32
                     39: 
                     40: #include <unistd.h>
                     41: #include <errno.h>
                     42: #include <sys/wait.h>
                     43: #include <signal.h>
                     44: 
                     45: /**
                     46:  * Private data of an process_t object.
                     47:  */
                     48: struct private_process_t {
                     49: 
                     50:        /**
                     51:         * Public process_t interface.
                     52:         */
                     53:        process_t public;
                     54: 
                     55:        /**
                     56:         * child stdin pipe
                     57:         */
                     58:        int in[PIPE_ENDS];
                     59: 
                     60:        /**
                     61:         * child stdout pipe
                     62:         */
                     63:        int out[PIPE_ENDS];
                     64: 
                     65:        /**
                     66:         * child stderr pipe
                     67:         */
                     68:        int err[PIPE_ENDS];
                     69: 
                     70:        /**
                     71:         * child process
                     72:         */
                     73:        int pid;
                     74: };
                     75: 
                     76: /**
                     77:  * Close a file descriptor if it is not -1
                     78:  */
                     79: static void close_if(int *fd)
                     80: {
                     81:        if (*fd != -1)
                     82:        {
                     83:                close(*fd);
                     84:                *fd = -1;
                     85:        }
                     86: }
                     87: 
                     88: /**
                     89:  * Destroy a process structure, close all pipes
                     90:  */
                     91: static void process_destroy(private_process_t *this)
                     92: {
                     93:        close_if(&this->in[PIPE_READ]);
                     94:        close_if(&this->in[PIPE_WRITE]);
                     95:        close_if(&this->out[PIPE_READ]);
                     96:        close_if(&this->out[PIPE_WRITE]);
                     97:        close_if(&this->err[PIPE_READ]);
                     98:        close_if(&this->err[PIPE_WRITE]);
                     99:        free(this);
                    100: }
                    101: 
                    102: METHOD(process_t, wait_, bool,
                    103:        private_process_t *this, int *code)
                    104: {
                    105:        int status, ret;
                    106: 
                    107:        ret = waitpid(this->pid, &status, 0);
                    108:        process_destroy(this);
                    109:        if (ret == -1)
                    110:        {
                    111:                return FALSE;
                    112:        }
                    113:        if (!WIFEXITED(status))
                    114:        {
                    115:                return FALSE;
                    116:        }
                    117:        if (code)
                    118:        {
                    119:                *code = WEXITSTATUS(status);
                    120:        }
                    121:        return TRUE;
                    122: }
                    123: 
                    124: /**
                    125:  * See header
                    126:  */
                    127: process_t* process_start(char *const argv[], char *const envp[],
                    128:                                                 int *in, int *out, int *err, bool close_all)
                    129: {
                    130:        private_process_t *this;
                    131:        char *empty[] = { NULL };
                    132: 
                    133:        INIT(this,
                    134:                .public = {
                    135:                        .wait = _wait_,
                    136:                },
                    137:                .in = { -1, -1 },
                    138:                .out = { -1, -1 },
                    139:                .err = { -1, -1 },
                    140:        );
                    141: 
                    142:        if (in && pipe(this->in) != 0)
                    143:        {
                    144:                DBG1(DBG_LIB, "creating stdin pipe failed: %s", strerror(errno));
                    145:                process_destroy(this);
                    146:                return NULL;
                    147:        }
                    148:        if (out && pipe(this->out) != 0)
                    149:        {
                    150:                DBG1(DBG_LIB, "creating stdout pipe failed: %s", strerror(errno));
                    151:                process_destroy(this);
                    152:                return NULL;
                    153:        }
                    154:        if (err && pipe(this->err) != 0)
                    155:        {
                    156:                DBG1(DBG_LIB, "creating stderr pipe failed: %s", strerror(errno));
                    157:                process_destroy(this);
                    158:                return NULL;
                    159:        }
                    160: 
                    161:        this->pid = fork();
                    162:        switch (this->pid)
                    163:        {
                    164:                case -1:
                    165:                        DBG1(DBG_LIB, "forking process failed: %s", strerror(errno));
                    166:                        process_destroy(this);
                    167:                        return NULL;
                    168:                case 0:
                    169:                        /* child */
                    170:                        close_if(&this->in[PIPE_WRITE]);
                    171:                        close_if(&this->out[PIPE_READ]);
                    172:                        close_if(&this->err[PIPE_READ]);
                    173:                        if (this->in[PIPE_READ] != -1)
                    174:                        {
                    175:                                if (dup2(this->in[PIPE_READ], 0) == -1)
                    176:                                {
                    177:                                        raise(SIGKILL);
                    178:                                }
                    179:                        }
                    180:                        if (this->out[PIPE_WRITE] != -1)
                    181:                        {
                    182:                                if (dup2(this->out[PIPE_WRITE], 1) == -1)
                    183:                                {
                    184:                                        raise(SIGKILL);
                    185:                                }
                    186:                        }
                    187:                        if (this->err[PIPE_WRITE] != -1)
                    188:                        {
                    189:                                if (dup2(this->err[PIPE_WRITE], 2) == -1)
                    190:                                {
                    191:                                        raise(SIGKILL);
                    192:                                }
                    193:                        }
                    194:                        if (close_all)
                    195:                        {
                    196:                                closefrom(3);
                    197:                        }
                    198:                        if (execve(argv[0], argv, envp ?: empty) == -1)
                    199:                        {
                    200:                                raise(SIGKILL);
                    201:                        }
                    202:                        /* not reached */
                    203:                default:
                    204:                        /* parent */
                    205:                        close_if(&this->in[PIPE_READ]);
                    206:                        close_if(&this->out[PIPE_WRITE]);
                    207:                        close_if(&this->err[PIPE_WRITE]);
                    208:                        if (in)
                    209:                        {
                    210:                                *in = this->in[PIPE_WRITE];
                    211:                                this->in[PIPE_WRITE] = -1;
                    212:                        }
                    213:                        if (out)
                    214:                        {
                    215:                                *out = this->out[PIPE_READ];
                    216:                                this->out[PIPE_READ] = -1;
                    217:                        }
                    218:                        if (err)
                    219:                        {
                    220:                                *err = this->err[PIPE_READ];
                    221:                                this->err[PIPE_READ] = -1;
                    222:                        }
                    223:                        return &this->public;
                    224:        }
                    225: }
                    226: 
                    227: /**
                    228:  * See header
                    229:  */
                    230: process_t* process_start_shell(char *const envp[], int *in, int *out, int *err,
                    231:                                                           char *fmt, ...)
                    232: {
                    233:        char *argv[] = {
                    234:                "/bin/sh",
                    235:                "-c",
                    236:                NULL,
                    237:                NULL
                    238:        };
                    239:        process_t *process;
                    240:        va_list args;
                    241:        int len;
                    242: 
                    243:        va_start(args, fmt);
                    244:        len = vasprintf(&argv[2], fmt, args);
                    245:        va_end(args);
                    246:        if (len < 0)
                    247:        {
                    248:                return NULL;
                    249:        }
                    250: 
                    251:        process = process_start(argv, envp, in, out, err, TRUE);
                    252:        free(argv[2]);
                    253:        return process;
                    254: }
                    255: 
                    256: #else /* WIN32 */
                    257: 
                    258: /**
                    259:  * Private data of an process_t object.
                    260:  */
                    261: struct private_process_t {
                    262: 
                    263:        /**
                    264:         * Public process_t interface.
                    265:         */
                    266:        process_t public;
                    267: 
                    268:        /**
                    269:         * child stdin pipe
                    270:         */
                    271:        HANDLE in[PIPE_ENDS];
                    272: 
                    273:        /**
                    274:         * child stdout pipe
                    275:         */
                    276:        HANDLE out[PIPE_ENDS];
                    277: 
                    278:        /**
                    279:         * child stderr pipe
                    280:         */
                    281:        HANDLE err[PIPE_ENDS];
                    282: 
                    283:        /**
                    284:         * child process information
                    285:         */
                    286:        PROCESS_INFORMATION pi;
                    287: };
                    288: 
                    289: /**
                    290:  * Clean up state associated to child process
                    291:  */
                    292: static void process_destroy(private_process_t *this)
                    293: {
                    294:        if (this->in[PIPE_READ])
                    295:        {
                    296:                CloseHandle(this->in[PIPE_READ]);
                    297:        }
                    298:        if (this->in[PIPE_WRITE])
                    299:        {
                    300:                CloseHandle(this->in[PIPE_WRITE]);
                    301:        }
                    302:        if (this->out[PIPE_READ])
                    303:        {
                    304:                CloseHandle(this->out[PIPE_READ]);
                    305:        }
                    306:        if (this->out[PIPE_WRITE])
                    307:        {
                    308:                CloseHandle(this->out[PIPE_WRITE]);
                    309:        }
                    310:        if (this->err[PIPE_READ])
                    311:        {
                    312:                CloseHandle(this->err[PIPE_READ]);
                    313:        }
                    314:        if (this->err[PIPE_WRITE])
                    315:        {
                    316:                CloseHandle(this->err[PIPE_WRITE]);
                    317:        }
                    318:        if (this->pi.hProcess)
                    319:        {
                    320:                CloseHandle(this->pi.hProcess);
                    321:                CloseHandle(this->pi.hThread);
                    322:        }
                    323:        free(this);
                    324: }
                    325: 
                    326: METHOD(process_t, wait_, bool,
                    327:        private_process_t *this, int *code)
                    328: {
                    329:        DWORD ec;
                    330: 
                    331:        if (WaitForSingleObject(this->pi.hProcess, INFINITE) != WAIT_OBJECT_0)
                    332:        {
                    333:                DBG1(DBG_LIB, "waiting for child process failed: 0x%08x",
                    334:                         GetLastError());
                    335:                process_destroy(this);
                    336:                return FALSE;
                    337:        }
                    338:        if (code)
                    339:        {
                    340:                if (!GetExitCodeProcess(this->pi.hProcess, &ec))
                    341:                {
                    342:                        DBG1(DBG_LIB, "getting child process exit code failed: 0x%08x",
                    343:                                 GetLastError());
                    344:                        process_destroy(this);
                    345:                        return FALSE;
                    346:                }
                    347:                *code = ec;
                    348:        }
                    349:        process_destroy(this);
                    350:        return TRUE;
                    351: }
                    352: 
                    353: /**
                    354:  * Append a command line argument to buf, optionally quoted
                    355:  */
                    356: static void append_arg(char *buf, u_int len, char *arg, char *quote)
                    357: {
                    358:        char *space = "";
                    359:        int current;
                    360: 
                    361:        current = strlen(buf);
                    362:        if (current)
                    363:        {
                    364:                space = " ";
                    365:        }
                    366:        snprintf(buf + current, len - current, "%s%s%s%s", space, quote, arg, quote);
                    367: }
                    368: 
                    369: /**
                    370:  * Append a null-terminate env string to buf
                    371:  */
                    372: static void append_env(char *buf, u_int len, char *env)
                    373: {
                    374:        char *pos = buf;
                    375:        int current;
                    376: 
                    377:        while (TRUE)
                    378:        {
                    379:                pos += strlen(pos);
                    380:                if (!pos[1])
                    381:                {
                    382:                        if (pos == buf)
                    383:                        {
                    384:                                current = 0;
                    385:                        }
                    386:                        else
                    387:                        {
                    388:                                current = pos - buf + 1;
                    389:                        }
                    390:                        snprintf(buf + current, len - current, "%s", env);
                    391:                        break;
                    392:                }
                    393:                pos++;
                    394:        }
                    395: }
                    396: 
                    397: /**
                    398:  * See header
                    399:  */
                    400: process_t* process_start(char *const argv[], char *const envp[],
                    401:                                                 int *in, int *out, int *err, bool close_all)
                    402: {
                    403:        private_process_t *this;
                    404:        char arg[32768], env[32768];
                    405:        SECURITY_ATTRIBUTES sa = {
                    406:                .nLength = sizeof(SECURITY_ATTRIBUTES),
                    407:                .bInheritHandle = TRUE,
                    408:        };
                    409:        STARTUPINFO sui = {
                    410:                .cb = sizeof(STARTUPINFO),
                    411:        };
                    412:        int i;
                    413: 
                    414:        memset(arg, 0, sizeof(arg));
                    415:        memset(env, 0, sizeof(env));
                    416: 
                    417:        for (i = 0; argv[i]; i++)
                    418:        {
                    419:                if (!strchr(argv[i], ' '))
                    420:                {       /* no spaces, fine for appending */
                    421:                        append_arg(arg, sizeof(arg) - 1, argv[i], "");
                    422:                }
                    423:                else if (argv[i][0] == '"' &&
                    424:                                 argv[i][strlen(argv[i]) - 1] == '"' &&
                    425:                                 strchr(argv[i] + 1, '"') == argv[i] + strlen(argv[i]) - 1)
                    426:                {       /* already properly quoted */
                    427:                        append_arg(arg, sizeof(arg) - 1, argv[i], "");
                    428:                }
                    429:                else if (strchr(argv[i], ' ') && !strchr(argv[i], '"'))
                    430:                {       /* spaces, but no quotes; append quoted */
                    431:                        append_arg(arg, sizeof(arg) - 1, argv[i], "\"");
                    432:                }
                    433:                else
                    434:                {
                    435:                        DBG1(DBG_LIB, "invalid command line argument: %s", argv[i]);
                    436:                        return NULL;
                    437:                }
                    438:        }
                    439:        if (envp)
                    440:        {
                    441:                for (i = 0; envp[i]; i++)
                    442:                {
                    443:                        append_env(env, sizeof(env) - 1, envp[i]);
                    444:                }
                    445:        }
                    446: 
                    447:        INIT(this,
                    448:                .public = {
                    449:                        .wait = _wait_,
                    450:                },
                    451:        );
                    452: 
                    453:        if (in)
                    454:        {
                    455:                sui.dwFlags = STARTF_USESTDHANDLES;
                    456:                if (!CreatePipe(&this->in[PIPE_READ], &this->in[PIPE_WRITE], &sa, 0))
                    457:                {
                    458:                        process_destroy(this);
                    459:                        return NULL;
                    460:                }
                    461:                if (!SetHandleInformation(this->in[PIPE_WRITE], HANDLE_FLAG_INHERIT, 0))
                    462:                {
                    463:                        process_destroy(this);
                    464:                        return NULL;
                    465:                }
                    466:                sui.hStdInput = this->in[PIPE_READ];
                    467:                *in = _open_osfhandle((uintptr_t)this->in[PIPE_WRITE], 0);
                    468:                if (*in == -1)
                    469:                {
                    470:                        process_destroy(this);
                    471:                        return NULL;
                    472:                }
                    473:        }
                    474:        if (out)
                    475:        {
                    476:                sui.dwFlags = STARTF_USESTDHANDLES;
                    477:                if (!CreatePipe(&this->out[PIPE_READ], &this->out[PIPE_WRITE], &sa, 0))
                    478:                {
                    479:                        process_destroy(this);
                    480:                        return NULL;
                    481:                }
                    482:                if (!SetHandleInformation(this->out[PIPE_READ], HANDLE_FLAG_INHERIT, 0))
                    483:                {
                    484:                        process_destroy(this);
                    485:                        return NULL;
                    486:                }
                    487:                sui.hStdOutput = this->out[PIPE_WRITE];
                    488:                *out = _open_osfhandle((uintptr_t)this->out[PIPE_READ], 0);
                    489:                if (*out == -1)
                    490:                {
                    491:                        process_destroy(this);
                    492:                        return NULL;
                    493:                }
                    494:        }
                    495:        if (err)
                    496:        {
                    497:                sui.dwFlags = STARTF_USESTDHANDLES;
                    498:                if (!CreatePipe(&this->err[PIPE_READ], &this->err[PIPE_WRITE], &sa, 0))
                    499:                {
                    500:                        process_destroy(this);
                    501:                        return NULL;
                    502:                }
                    503:                if (!SetHandleInformation(this->err[PIPE_READ], HANDLE_FLAG_INHERIT, 0))
                    504:                {
                    505:                        process_destroy(this);
                    506:                        return NULL;
                    507:                }
                    508:                sui.hStdError = this->err[PIPE_WRITE];
                    509:                *err = _open_osfhandle((uintptr_t)this->err[PIPE_READ], 0);
                    510:                if (*err == -1)
                    511:                {
                    512:                        process_destroy(this);
                    513:                        return NULL;
                    514:                }
                    515:        }
                    516: 
                    517:        if (!CreateProcess(argv[0], arg, NULL, NULL, TRUE,
                    518:                                           NORMAL_PRIORITY_CLASS, env, NULL, &sui, &this->pi))
                    519:        {
                    520:                DBG1(DBG_LIB, "creating process '%s' failed: 0x%08x",
                    521:                         argv[0], GetLastError());
                    522:                process_destroy(this);
                    523:                return NULL;
                    524:        }
                    525: 
                    526:        /* close child process end of pipes */
                    527:        if (this->in[PIPE_READ])
                    528:        {
                    529:                CloseHandle(this->in[PIPE_READ]);
                    530:                this->in[PIPE_READ] = NULL;
                    531:        }
                    532:        if (this->out[PIPE_WRITE])
                    533:        {
                    534:                CloseHandle(this->out[PIPE_WRITE]);
                    535:                this->out[PIPE_WRITE] = NULL;
                    536:        }
                    537:        if (this->err[PIPE_WRITE])
                    538:        {
                    539:                CloseHandle(this->err[PIPE_WRITE]);
                    540:                this->err[PIPE_WRITE] = NULL;
                    541:        }
                    542:        /* our side gets closed over the osf_handle closed by caller */
                    543:        this->in[PIPE_WRITE] = NULL;
                    544:        this->out[PIPE_READ] = NULL;
                    545:        this->err[PIPE_READ] = NULL;
                    546:        return &this->public;
                    547: }
                    548: 
                    549: /**
                    550:  * See header
                    551:  */
                    552: process_t* process_start_shell(char *const envp[], int *in, int *out, int *err,
                    553:                                                           char *fmt, ...)
                    554: {
                    555:        char path[MAX_PATH], *exe = "system32\\cmd.exe";
                    556:        char *argv[] = {
                    557:                path,
                    558:                "/C",
                    559:                NULL,
                    560:                NULL
                    561:        };
                    562:        process_t *process;
                    563:        va_list args;
                    564:        int len;
                    565: 
                    566:        len = GetSystemWindowsDirectory(path, sizeof(path));
                    567:        if (len == 0 || len >= sizeof(path) - strlen(exe))
                    568:        {
                    569:                DBG1(DBG_LIB, "resolving Windows directory failed: 0x%08x",
                    570:                         GetLastError());
                    571:                return NULL;
                    572:        }
                    573:        if (path[len + 1] != '\\')
                    574:        {
                    575:                strncat(path, "\\", sizeof(path) - len++);
                    576:        }
                    577:        strncat(path, exe, sizeof(path) - len);
                    578: 
                    579:        va_start(args, fmt);
                    580:        len = vasprintf(&argv[2], fmt, args);
                    581:        va_end(args);
                    582:        if (len < 0)
                    583:        {
                    584:                return NULL;
                    585:        }
                    586: 
                    587:        process = process_start(argv, envp, in, out, err, TRUE);
                    588:        free(argv[2]);
                    589:        return process;
                    590: }
                    591: 
                    592: #endif /* WIN32 */

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