[BACK]Return to misc.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / crypto / external / bsd / openssh / dist

Annotation of src/crypto/external/bsd/openssh/dist/misc.c, Revision 1.16.2.2

1.16.2.2! pgoyette    1: /*     $NetBSD: misc.c,v 1.18 2018/08/26 07:46:36 christos Exp $       */
        !             2: /* $OpenBSD: misc.c,v 1.131 2018/07/27 05:13:02 dtucker Exp $ */
        !             3:
1.1       christos    4: /*
                      5:  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
                      6:  * Copyright (c) 2005,2006 Damien Miller.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     18:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     19:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     20:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     21:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     22:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     23:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     24:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     25:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     26:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     27:  */
                     28:
1.2       christos   29: #include "includes.h"
1.16.2.2! pgoyette   30: __RCSID("$NetBSD: misc.c,v 1.18 2018/08/26 07:46:36 christos Exp $");
1.1       christos   31: #include <sys/types.h>
                     32: #include <sys/ioctl.h>
                     33: #include <sys/socket.h>
1.16      christos   34: #include <sys/stat.h>
1.12      christos   35: #include <sys/time.h>
1.16      christos   36: #include <sys/wait.h>
1.9       christos   37: #include <sys/un.h>
1.1       christos   38:
                     39: #include <net/if.h>
1.2       christos   40: #include <net/if_tun.h>
1.1       christos   41: #include <netinet/in.h>
1.5       christos   42: #include <netinet/ip.h>
1.1       christos   43: #include <netinet/tcp.h>
                     44:
1.9       christos   45: #include <ctype.h>
1.1       christos   46: #include <errno.h>
                     47: #include <fcntl.h>
                     48: #include <netdb.h>
                     49: #include <paths.h>
                     50: #include <pwd.h>
1.16      christos   51: #include <libgen.h>
1.10      christos   52: #include <limits.h>
1.16      christos   53: #include <signal.h>
1.1       christos   54: #include <stdarg.h>
                     55: #include <stdio.h>
                     56: #include <stdlib.h>
                     57: #include <string.h>
                     58: #include <unistd.h>
                     59:
                     60: #include "xmalloc.h"
                     61: #include "misc.h"
                     62: #include "log.h"
                     63: #include "ssh.h"
1.16      christos   64: #include "sshbuf.h"
                     65: #include "ssherr.h"
1.1       christos   66:
                     67: /* remove newline at end of string */
                     68: char *
                     69: chop(char *s)
                     70: {
                     71:        char *t = s;
                     72:        while (*t) {
                     73:                if (*t == '\n' || *t == '\r') {
                     74:                        *t = '\0';
                     75:                        return s;
                     76:                }
                     77:                t++;
                     78:        }
                     79:        return s;
                     80:
                     81: }
                     82:
                     83: /* set/unset filedescriptor to non-blocking */
                     84: int
                     85: set_nonblock(int fd)
                     86: {
                     87:        int val;
                     88:
1.13      christos   89:        val = fcntl(fd, F_GETFL);
1.1       christos   90:        if (val < 0) {
1.13      christos   91:                error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
1.1       christos   92:                return (-1);
                     93:        }
                     94:        if (val & O_NONBLOCK) {
                     95:                debug3("fd %d is O_NONBLOCK", fd);
                     96:                return (0);
                     97:        }
                     98:        debug2("fd %d setting O_NONBLOCK", fd);
                     99:        val |= O_NONBLOCK;
                    100:        if (fcntl(fd, F_SETFL, val) == -1) {
                    101:                debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
                    102:                    strerror(errno));
                    103:                return (-1);
                    104:        }
                    105:        return (0);
                    106: }
                    107:
                    108: int
                    109: unset_nonblock(int fd)
                    110: {
                    111:        int val;
                    112:
1.13      christos  113:        val = fcntl(fd, F_GETFL);
1.1       christos  114:        if (val < 0) {
1.13      christos  115:                error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
1.1       christos  116:                return (-1);
                    117:        }
                    118:        if (!(val & O_NONBLOCK)) {
                    119:                debug3("fd %d is not O_NONBLOCK", fd);
                    120:                return (0);
                    121:        }
                    122:        debug("fd %d clearing O_NONBLOCK", fd);
                    123:        val &= ~O_NONBLOCK;
                    124:        if (fcntl(fd, F_SETFL, val) == -1) {
                    125:                debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
                    126:                    fd, strerror(errno));
                    127:                return (-1);
                    128:        }
                    129:        return (0);
                    130: }
                    131:
                    132: const char *
                    133: ssh_gai_strerror(int gaierr)
                    134: {
1.8       christos  135:        if (gaierr == EAI_SYSTEM && errno != 0)
1.1       christos  136:                return strerror(errno);
                    137:        return gai_strerror(gaierr);
                    138: }
                    139:
                    140: /* disable nagle on socket */
                    141: void
                    142: set_nodelay(int fd)
                    143: {
                    144:        int opt;
                    145:        socklen_t optlen;
                    146:
                    147:        optlen = sizeof opt;
                    148:        if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
                    149:                debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
                    150:                return;
                    151:        }
                    152:        if (opt == 1) {
                    153:                debug2("fd %d is TCP_NODELAY", fd);
                    154:                return;
                    155:        }
                    156:        opt = 1;
                    157:        debug2("fd %d setting TCP_NODELAY", fd);
                    158:        if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
                    159:                error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
                    160: }
                    161:
1.16.2.1  pgoyette  162: /* Allow local port reuse in TIME_WAIT */
                    163: int
                    164: set_reuseaddr(int fd)
                    165: {
                    166:        int on = 1;
                    167:
                    168:        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
                    169:                error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
                    170:                return -1;
                    171:        }
                    172:        return 0;
                    173: }
                    174:
                    175: /* Get/set routing domain */
                    176: char *
                    177: get_rdomain(int fd)
                    178: {
                    179: #ifdef SO_RTABLE
                    180:        int rtable;
                    181:        char *ret;
                    182:        socklen_t len = sizeof(rtable);
                    183:
                    184:        if (getsockopt(fd, SOL_SOCKET, SO_RTABLE, &rtable, &len) == -1) {
                    185:                error("Failed to get routing domain for fd %d: %s",
                    186:                    fd, strerror(errno));
                    187:                return NULL;
                    188:        }
                    189:        xasprintf(&ret, "%d", rtable);
                    190:        return ret;
                    191: #else
                    192:        return NULL;
                    193: #endif
                    194: }
                    195:
                    196: int
                    197: set_rdomain(int fd, const char *name)
                    198: {
                    199: #ifdef SO_RTABLE
                    200:        int rtable;
                    201:        const char *errstr;
                    202:
                    203:        if (name == NULL)
                    204:                return 0; /* default table */
                    205:
                    206:        rtable = (int)strtonum(name, 0, 255, &errstr);
                    207:        if (errstr != NULL) {
                    208:                /* Shouldn't happen */
                    209:                error("Invalid routing domain \"%s\": %s", name, errstr);
                    210:                return -1;
                    211:        }
                    212:        if (setsockopt(fd, SOL_SOCKET, SO_RTABLE,
                    213:            &rtable, sizeof(rtable)) == -1) {
                    214:                error("Failed to set routing domain %d on fd %d: %s",
                    215:                    rtable, fd, strerror(errno));
                    216:                return -1;
                    217:        }
                    218:        return 0;
                    219: #else
                    220:        return -1;
                    221: #endif
                    222: }
                    223:
1.1       christos  224: /* Characters considered whitespace in strsep calls. */
                    225: #define WHITESPACE " \t\r\n"
                    226: #define QUOTE  "\""
                    227:
                    228: /* return next token in configuration line */
1.16.2.2! pgoyette  229: static char *
        !           230: strdelim_internal(char **s, int split_equals)
1.1       christos  231: {
                    232:        char *old;
                    233:        int wspace = 0;
                    234:
                    235:        if (*s == NULL)
                    236:                return NULL;
                    237:
                    238:        old = *s;
                    239:
1.16.2.2! pgoyette  240:        *s = strpbrk(*s,
        !           241:            split_equals ? WHITESPACE QUOTE "=" : WHITESPACE QUOTE);
1.1       christos  242:        if (*s == NULL)
                    243:                return (old);
                    244:
                    245:        if (*s[0] == '\"') {
                    246:                memmove(*s, *s + 1, strlen(*s)); /* move nul too */
                    247:                /* Find matching quote */
                    248:                if ((*s = strpbrk(*s, QUOTE)) == NULL) {
                    249:                        return (NULL);          /* no matching quote */
                    250:                } else {
                    251:                        *s[0] = '\0';
1.4       adam      252:                        *s += strspn(*s + 1, WHITESPACE) + 1;
1.1       christos  253:                        return (old);
                    254:                }
                    255:        }
                    256:
                    257:        /* Allow only one '=' to be skipped */
1.16.2.2! pgoyette  258:        if (split_equals && *s[0] == '=')
1.1       christos  259:                wspace = 1;
                    260:        *s[0] = '\0';
                    261:
                    262:        /* Skip any extra whitespace after first token */
                    263:        *s += strspn(*s + 1, WHITESPACE) + 1;
1.16.2.2! pgoyette  264:        if (split_equals && *s[0] == '=' && !wspace)
1.1       christos  265:                *s += strspn(*s + 1, WHITESPACE) + 1;
                    266:
                    267:        return (old);
                    268: }
                    269:
1.16.2.2! pgoyette  270: /*
        !           271:  * Return next token in configuration line; splts on whitespace or a
        !           272:  * single '=' character.
        !           273:  */
        !           274: char *
        !           275: strdelim(char **s)
        !           276: {
        !           277:        return strdelim_internal(s, 1);
        !           278: }
        !           279:
        !           280: /*
        !           281:  * Return next token in configuration line; splts on whitespace only.
        !           282:  */
        !           283: char *
        !           284: strdelimw(char **s)
        !           285: {
        !           286:        return strdelim_internal(s, 0);
        !           287: }
        !           288:
1.1       christos  289: struct passwd *
                    290: pwcopy(struct passwd *pw)
                    291: {
                    292:        struct passwd *copy = xcalloc(1, sizeof(*copy));
                    293:
                    294:        copy->pw_name = xstrdup(pw->pw_name);
                    295:        copy->pw_passwd = xstrdup(pw->pw_passwd);
                    296:        copy->pw_gecos = xstrdup(pw->pw_gecos);
                    297:        copy->pw_uid = pw->pw_uid;
                    298:        copy->pw_gid = pw->pw_gid;
                    299:        copy->pw_expire = pw->pw_expire;
                    300:        copy->pw_change = pw->pw_change;
                    301:        copy->pw_class = xstrdup(pw->pw_class);
                    302:        copy->pw_dir = xstrdup(pw->pw_dir);
                    303:        copy->pw_shell = xstrdup(pw->pw_shell);
                    304:        return copy;
                    305: }
                    306:
                    307: /*
                    308:  * Convert ASCII string to TCP/IP port number.
                    309:  * Port must be >=0 and <=65535.
                    310:  * Return -1 if invalid.
                    311:  */
                    312: int
                    313: a2port(const char *s)
                    314: {
                    315:        long long port;
                    316:        const char *errstr;
                    317:
                    318:        port = strtonum(s, 0, 65535, &errstr);
                    319:        if (errstr != NULL)
                    320:                return -1;
                    321:        return (int)port;
                    322: }
                    323:
                    324: int
                    325: a2tun(const char *s, int *remote)
                    326: {
                    327:        const char *errstr = NULL;
                    328:        char *sp, *ep;
                    329:        int tun;
                    330:
                    331:        if (remote != NULL) {
                    332:                *remote = SSH_TUNID_ANY;
                    333:                sp = xstrdup(s);
                    334:                if ((ep = strchr(sp, ':')) == NULL) {
1.8       christos  335:                        free(sp);
1.1       christos  336:                        return (a2tun(s, NULL));
                    337:                }
                    338:                ep[0] = '\0'; ep++;
                    339:                *remote = a2tun(ep, NULL);
                    340:                tun = a2tun(sp, NULL);
1.8       christos  341:                free(sp);
1.1       christos  342:                return (*remote == SSH_TUNID_ERR ? *remote : tun);
                    343:        }
                    344:
                    345:        if (strcasecmp(s, "any") == 0)
                    346:                return (SSH_TUNID_ANY);
                    347:
                    348:        tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
                    349:        if (errstr != NULL)
                    350:                return (SSH_TUNID_ERR);
                    351:
                    352:        return (tun);
                    353: }
                    354:
                    355: #define SECONDS                1
                    356: #define MINUTES                (SECONDS * 60)
                    357: #define HOURS          (MINUTES * 60)
                    358: #define DAYS           (HOURS * 24)
                    359: #define WEEKS          (DAYS * 7)
                    360:
                    361: /*
                    362:  * Convert a time string into seconds; format is
                    363:  * a sequence of:
                    364:  *      time[qualifier]
                    365:  *
                    366:  * Valid time qualifiers are:
                    367:  *      <none>  seconds
                    368:  *      s|S     seconds
                    369:  *      m|M     minutes
                    370:  *      h|H     hours
                    371:  *      d|D     days
                    372:  *      w|W     weeks
                    373:  *
                    374:  * Examples:
                    375:  *      90m     90 minutes
                    376:  *      1h30m   90 minutes
                    377:  *      2d      2 days
                    378:  *      1w      1 week
                    379:  *
                    380:  * Return -1 if time string is invalid.
                    381:  */
                    382: long
                    383: convtime(const char *s)
                    384: {
1.15      christos  385:        long total, secs, multiplier = 1;
1.1       christos  386:        const char *p;
                    387:        char *endp;
                    388:
                    389:        errno = 0;
                    390:        total = 0;
                    391:        p = s;
                    392:
                    393:        if (p == NULL || *p == '\0')
                    394:                return -1;
                    395:
                    396:        while (*p) {
                    397:                secs = strtol(p, &endp, 10);
                    398:                if (p == endp ||
                    399:                    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
                    400:                    secs < 0)
                    401:                        return -1;
                    402:
                    403:                switch (*endp++) {
                    404:                case '\0':
                    405:                        endp--;
                    406:                        break;
                    407:                case 's':
                    408:                case 'S':
                    409:                        break;
                    410:                case 'm':
                    411:                case 'M':
1.15      christos  412:                        multiplier = MINUTES;
1.1       christos  413:                        break;
                    414:                case 'h':
                    415:                case 'H':
1.15      christos  416:                        multiplier = HOURS;
1.1       christos  417:                        break;
                    418:                case 'd':
                    419:                case 'D':
1.15      christos  420:                        multiplier = DAYS;
1.1       christos  421:                        break;
                    422:                case 'w':
                    423:                case 'W':
1.15      christos  424:                        multiplier = WEEKS;
1.1       christos  425:                        break;
                    426:                default:
                    427:                        return -1;
                    428:                }
1.15      christos  429:                if (secs >= LONG_MAX / multiplier)
                    430:                        return -1;
                    431:                secs *= multiplier;
                    432:                if  (total >= LONG_MAX - secs)
                    433:                        return -1;
1.1       christos  434:                total += secs;
                    435:                if (total < 0)
                    436:                        return -1;
                    437:                p = endp;
                    438:        }
                    439:
                    440:        return total;
                    441: }
                    442:
                    443: /*
                    444:  * Returns a standardized host+port identifier string.
                    445:  * Caller must free returned string.
                    446:  */
                    447: char *
                    448: put_host_port(const char *host, u_short port)
                    449: {
                    450:        char *hoststr;
                    451:
                    452:        if (port == 0 || port == SSH_DEFAULT_PORT)
                    453:                return(xstrdup(host));
                    454:        if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
                    455:                fatal("put_host_port: asprintf: %s", strerror(errno));
                    456:        debug3("put_host_port: %s", hoststr);
                    457:        return hoststr;
                    458: }
                    459:
                    460: /*
                    461:  * Search for next delimiter between hostnames/addresses and ports.
                    462:  * Argument may be modified (for termination).
                    463:  * Returns *cp if parsing succeeds.
1.16.2.1  pgoyette  464:  * *cp is set to the start of the next field, if one was found.
                    465:  * The delimiter char, if present, is stored in delim.
1.1       christos  466:  * If this is the last field, *cp is set to NULL.
                    467:  */
1.16.2.1  pgoyette  468: static char *
                    469: hpdelim2(char **cp, char *delim)
1.1       christos  470: {
                    471:        char *s, *old;
                    472:
                    473:        if (cp == NULL || *cp == NULL)
                    474:                return NULL;
                    475:
                    476:        old = s = *cp;
                    477:        if (*s == '[') {
                    478:                if ((s = strchr(s, ']')) == NULL)
                    479:                        return NULL;
                    480:                else
                    481:                        s++;
                    482:        } else if ((s = strpbrk(s, ":/")) == NULL)
                    483:                s = *cp + strlen(*cp); /* skip to end (see first case below) */
                    484:
                    485:        switch (*s) {
                    486:        case '\0':
                    487:                *cp = NULL;     /* no more fields*/
                    488:                break;
                    489:
                    490:        case ':':
                    491:        case '/':
1.16.2.1  pgoyette  492:                if (delim != NULL)
                    493:                        *delim = *s;
1.1       christos  494:                *s = '\0';      /* terminate */
                    495:                *cp = s + 1;
                    496:                break;
                    497:
                    498:        default:
                    499:                return NULL;
                    500:        }
                    501:
                    502:        return old;
                    503: }
                    504:
                    505: char *
1.16.2.1  pgoyette  506: hpdelim(char **cp)
                    507: {
                    508:        return hpdelim2(cp, NULL);
                    509: }
                    510:
                    511: char *
1.1       christos  512: cleanhostname(char *host)
                    513: {
                    514:        if (*host == '[' && host[strlen(host) - 1] == ']') {
                    515:                host[strlen(host) - 1] = '\0';
                    516:                return (host + 1);
                    517:        } else
                    518:                return host;
                    519: }
                    520:
                    521: char *
                    522: colon(char *cp)
                    523: {
                    524:        int flag = 0;
                    525:
                    526:        if (*cp == ':')         /* Leading colon is part of file name. */
1.4       adam      527:                return NULL;
1.1       christos  528:        if (*cp == '[')
                    529:                flag = 1;
                    530:
                    531:        for (; *cp; ++cp) {
                    532:                if (*cp == '@' && *(cp+1) == '[')
                    533:                        flag = 1;
                    534:                if (*cp == ']' && *(cp+1) == ':' && flag)
                    535:                        return (cp+1);
                    536:                if (*cp == ':' && !flag)
                    537:                        return (cp);
                    538:                if (*cp == '/')
1.4       adam      539:                        return NULL;
1.1       christos  540:        }
1.4       adam      541:        return NULL;
1.1       christos  542: }
                    543:
1.13      christos  544: /*
1.16.2.1  pgoyette  545:  * Parse a [user@]host:[path] string.
                    546:  * Caller must free returned user, host and path.
                    547:  * Any of the pointer return arguments may be NULL (useful for syntax checking).
                    548:  * If user was not specified then *userp will be set to NULL.
                    549:  * If host was not specified then *hostp will be set to NULL.
                    550:  * If path was not specified then *pathp will be set to ".".
                    551:  * Returns 0 on success, -1 on failure.
                    552:  */
                    553: int
                    554: parse_user_host_path(const char *s, char **userp, char **hostp,
                    555:     const char **pathp)
                    556: {
                    557:        char *user = NULL, *host = NULL, *path = NULL;
                    558:        char *tmp, *sdup;
                    559:        int ret = -1;
                    560:
                    561:        if (userp != NULL)
                    562:                *userp = NULL;
                    563:        if (hostp != NULL)
                    564:                *hostp = NULL;
                    565:        if (pathp != NULL)
                    566:                *pathp = NULL;
                    567:
                    568:        sdup = xstrdup(s);
                    569:
                    570:        /* Check for remote syntax: [user@]host:[path] */
                    571:        if ((tmp = colon(sdup)) == NULL)
                    572:                goto out;
                    573:
                    574:        /* Extract optional path */
                    575:        *tmp++ = '\0';
                    576:        if (*tmp == '\0')
                    577:                tmp = __UNCONST(".");
                    578:        path = xstrdup(tmp);
                    579:
                    580:        /* Extract optional user and mandatory host */
                    581:        tmp = strrchr(sdup, '@');
                    582:        if (tmp != NULL) {
                    583:                *tmp++ = '\0';
                    584:                host = xstrdup(cleanhostname(tmp));
                    585:                if (*sdup != '\0')
                    586:                        user = xstrdup(sdup);
                    587:        } else {
                    588:                host = xstrdup(cleanhostname(sdup));
                    589:                user = NULL;
                    590:        }
                    591:
                    592:        /* Success */
                    593:        if (userp != NULL) {
                    594:                *userp = user;
                    595:                user = NULL;
                    596:        }
                    597:        if (hostp != NULL) {
                    598:                *hostp = host;
                    599:                host = NULL;
                    600:        }
                    601:        if (pathp != NULL) {
                    602:                *pathp = path;
                    603:                path = NULL;
                    604:        }
                    605:        ret = 0;
                    606: out:
                    607:        free(sdup);
                    608:        free(user);
                    609:        free(host);
                    610:        free(path);
                    611:        return ret;
                    612: }
                    613:
                    614: /*
1.13      christos  615:  * Parse a [user@]host[:port] string.
                    616:  * Caller must free returned user and host.
                    617:  * Any of the pointer return arguments may be NULL (useful for syntax checking).
                    618:  * If user was not specified then *userp will be set to NULL.
                    619:  * If port was not specified then *portp will be -1.
                    620:  * Returns 0 on success, -1 on failure.
                    621:  */
                    622: int
                    623: parse_user_host_port(const char *s, char **userp, char **hostp, int *portp)
                    624: {
                    625:        char *sdup, *cp, *tmp;
                    626:        char *user = NULL, *host = NULL;
                    627:        int port = -1, ret = -1;
                    628:
                    629:        if (userp != NULL)
                    630:                *userp = NULL;
                    631:        if (hostp != NULL)
                    632:                *hostp = NULL;
                    633:        if (portp != NULL)
                    634:                *portp = -1;
                    635:
                    636:        if ((sdup = tmp = strdup(s)) == NULL)
                    637:                return -1;
                    638:        /* Extract optional username */
1.16.2.1  pgoyette  639:        if ((cp = strrchr(tmp, '@')) != NULL) {
1.13      christos  640:                *cp = '\0';
                    641:                if (*tmp == '\0')
                    642:                        goto out;
                    643:                if ((user = strdup(tmp)) == NULL)
                    644:                        goto out;
                    645:                tmp = cp + 1;
                    646:        }
                    647:        /* Extract mandatory hostname */
                    648:        if ((cp = hpdelim(&tmp)) == NULL || *cp == '\0')
                    649:                goto out;
                    650:        host = xstrdup(cleanhostname(cp));
                    651:        /* Convert and verify optional port */
                    652:        if (tmp != NULL && *tmp != '\0') {
                    653:                if ((port = a2port(tmp)) <= 0)
                    654:                        goto out;
                    655:        }
                    656:        /* Success */
                    657:        if (userp != NULL) {
                    658:                *userp = user;
                    659:                user = NULL;
                    660:        }
                    661:        if (hostp != NULL) {
                    662:                *hostp = host;
                    663:                host = NULL;
                    664:        }
                    665:        if (portp != NULL)
                    666:                *portp = port;
                    667:        ret = 0;
                    668:  out:
                    669:        free(sdup);
                    670:        free(user);
                    671:        free(host);
                    672:        return ret;
                    673: }
                    674:
1.16.2.1  pgoyette  675: /*
                    676:  * Converts a two-byte hex string to decimal.
                    677:  * Returns the decimal value or -1 for invalid input.
                    678:  */
                    679: static int
                    680: hexchar(const char *s)
                    681: {
                    682:        unsigned char result[2];
                    683:        int i;
                    684:
                    685:        for (i = 0; i < 2; i++) {
                    686:                if (s[i] >= '0' && s[i] <= '9')
                    687:                        result[i] = (unsigned char)(s[i] - '0');
                    688:                else if (s[i] >= 'a' && s[i] <= 'f')
                    689:                        result[i] = (unsigned char)(s[i] - 'a') + 10;
                    690:                else if (s[i] >= 'A' && s[i] <= 'F')
                    691:                        result[i] = (unsigned char)(s[i] - 'A') + 10;
                    692:                else
                    693:                        return -1;
                    694:        }
                    695:        return (result[0] << 4) | result[1];
                    696: }
                    697:
                    698: /*
                    699:  * Decode an url-encoded string.
                    700:  * Returns a newly allocated string on success or NULL on failure.
                    701:  */
                    702: static char *
                    703: urldecode(const char *src)
                    704: {
                    705:        char *ret, *dst;
                    706:        int ch;
                    707:
                    708:        ret = xmalloc(strlen(src) + 1);
                    709:        for (dst = ret; *src != '\0'; src++) {
                    710:                switch (*src) {
                    711:                case '+':
                    712:                        *dst++ = ' ';
                    713:                        break;
                    714:                case '%':
                    715:                        if (!isxdigit((unsigned char)src[1]) ||
                    716:                            !isxdigit((unsigned char)src[2]) ||
                    717:                            (ch = hexchar(src + 1)) == -1) {
                    718:                                free(ret);
                    719:                                return NULL;
                    720:                        }
                    721:                        *dst++ = ch;
                    722:                        src += 2;
                    723:                        break;
                    724:                default:
                    725:                        *dst++ = *src;
                    726:                        break;
                    727:                }
                    728:        }
                    729:        *dst = '\0';
                    730:
                    731:        return ret;
                    732: }
                    733:
                    734: /*
                    735:  * Parse an (scp|ssh|sftp)://[user@]host[:port][/path] URI.
                    736:  * See https://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04
                    737:  * Either user or path may be url-encoded (but not host or port).
                    738:  * Caller must free returned user, host and path.
                    739:  * Any of the pointer return arguments may be NULL (useful for syntax checking)
                    740:  * but the scheme must always be specified.
                    741:  * If user was not specified then *userp will be set to NULL.
                    742:  * If port was not specified then *portp will be -1.
                    743:  * If path was not specified then *pathp will be set to NULL.
                    744:  * Returns 0 on success, 1 if non-uri/wrong scheme, -1 on error/invalid uri.
                    745:  */
                    746: int
                    747: parse_uri(const char *scheme, const char *uri, char **userp, char **hostp,
                    748:     int *portp, const char **pathp)
                    749: {
                    750:        char *uridup, *cp, *tmp, ch;
                    751:        char *user = NULL, *host = NULL, *path = NULL;
                    752:        int port = -1, ret = -1;
                    753:        size_t len;
                    754:
                    755:        len = strlen(scheme);
                    756:        if (strncmp(uri, scheme, len) != 0 || strncmp(uri + len, "://", 3) != 0)
                    757:                return 1;
                    758:        uri += len + 3;
                    759:
                    760:        if (userp != NULL)
                    761:                *userp = NULL;
                    762:        if (hostp != NULL)
                    763:                *hostp = NULL;
                    764:        if (portp != NULL)
                    765:                *portp = -1;
                    766:        if (pathp != NULL)
                    767:                *pathp = NULL;
                    768:
                    769:        uridup = tmp = xstrdup(uri);
                    770:
                    771:        /* Extract optional ssh-info (username + connection params) */
                    772:        if ((cp = strchr(tmp, '@')) != NULL) {
                    773:                char *delim;
                    774:
                    775:                *cp = '\0';
                    776:                /* Extract username and connection params */
                    777:                if ((delim = strchr(tmp, ';')) != NULL) {
                    778:                        /* Just ignore connection params for now */
                    779:                        *delim = '\0';
                    780:                }
                    781:                if (*tmp == '\0') {
                    782:                        /* Empty username */
                    783:                        goto out;
                    784:                }
                    785:                if ((user = urldecode(tmp)) == NULL)
                    786:                        goto out;
                    787:                tmp = cp + 1;
                    788:        }
                    789:
                    790:        /* Extract mandatory hostname */
                    791:        if ((cp = hpdelim2(&tmp, &ch)) == NULL || *cp == '\0')
                    792:                goto out;
                    793:        host = xstrdup(cleanhostname(cp));
                    794:        if (!valid_domain(host, 0, NULL))
                    795:                goto out;
                    796:
                    797:        if (tmp != NULL && *tmp != '\0') {
                    798:                if (ch == ':') {
                    799:                        /* Convert and verify port. */
                    800:                        if ((cp = strchr(tmp, '/')) != NULL)
                    801:                                *cp = '\0';
                    802:                        if ((port = a2port(tmp)) <= 0)
                    803:                                goto out;
                    804:                        tmp = cp ? cp + 1 : NULL;
                    805:                }
                    806:                if (tmp != NULL && *tmp != '\0') {
                    807:                        /* Extract optional path */
                    808:                        if ((path = urldecode(tmp)) == NULL)
                    809:                                goto out;
                    810:                }
                    811:        }
                    812:
                    813:        /* Success */
                    814:        if (userp != NULL) {
                    815:                *userp = user;
                    816:                user = NULL;
                    817:        }
                    818:        if (hostp != NULL) {
                    819:                *hostp = host;
                    820:                host = NULL;
                    821:        }
                    822:        if (portp != NULL)
                    823:                *portp = port;
                    824:        if (pathp != NULL) {
                    825:                *pathp = path;
                    826:                path = NULL;
                    827:        }
                    828:        ret = 0;
                    829:  out:
                    830:        free(uridup);
                    831:        free(user);
                    832:        free(host);
                    833:        free(path);
                    834:        return ret;
                    835: }
                    836:
1.1       christos  837: /* function to assist building execv() arguments */
                    838: void
1.5       christos  839: addargs(arglist *args, const char *fmt, ...)
1.1       christos  840: {
                    841:        va_list ap;
                    842:        char *cp;
                    843:        u_int nalloc;
                    844:        int r;
                    845:
                    846:        va_start(ap, fmt);
                    847:        r = vasprintf(&cp, fmt, ap);
                    848:        va_end(ap);
                    849:        if (r == -1)
                    850:                fatal("addargs: argument too long");
                    851:
                    852:        nalloc = args->nalloc;
                    853:        if (args->list == NULL) {
                    854:                nalloc = 32;
                    855:                args->num = 0;
                    856:        } else if (args->num+2 >= nalloc)
                    857:                nalloc *= 2;
                    858:
1.16      christos  859:        args->list = xrecallocarray(args->list, args->nalloc, nalloc, sizeof(char *));
1.1       christos  860:        args->nalloc = nalloc;
                    861:        args->list[args->num++] = cp;
                    862:        args->list[args->num] = NULL;
                    863: }
                    864:
                    865: void
1.5       christos  866: replacearg(arglist *args, u_int which, const char *fmt, ...)
1.1       christos  867: {
                    868:        va_list ap;
                    869:        char *cp;
                    870:        int r;
                    871:
                    872:        va_start(ap, fmt);
                    873:        r = vasprintf(&cp, fmt, ap);
                    874:        va_end(ap);
                    875:        if (r == -1)
                    876:                fatal("replacearg: argument too long");
                    877:
                    878:        if (which >= args->num)
                    879:                fatal("replacearg: tried to replace invalid arg %d >= %d",
                    880:                    which, args->num);
1.8       christos  881:        free(args->list[which]);
1.1       christos  882:        args->list[which] = cp;
                    883: }
                    884:
                    885: void
                    886: freeargs(arglist *args)
                    887: {
                    888:        u_int i;
                    889:
                    890:        if (args->list != NULL) {
                    891:                for (i = 0; i < args->num; i++)
1.8       christos  892:                        free(args->list[i]);
                    893:                free(args->list);
1.1       christos  894:                args->nalloc = args->num = 0;
                    895:                args->list = NULL;
                    896:        }
                    897: }
                    898:
                    899: /*
                    900:  * Expands tildes in the file name.  Returns data allocated by xmalloc.
                    901:  * Warning: this calls getpw*.
                    902:  */
                    903: char *
                    904: tilde_expand_filename(const char *filename, uid_t uid)
                    905: {
1.8       christos  906:        const char *path, *sep;
                    907:        char user[128], *ret, *homedir;
1.1       christos  908:        struct passwd *pw;
                    909:        u_int len, slash;
                    910:
                    911:        if (*filename != '~')
                    912:                return (xstrdup(filename));
                    913:        filename++;
                    914:
                    915:        path = strchr(filename, '/');
                    916:        if (path != NULL && path > filename) {          /* ~user/path */
                    917:                slash = path - filename;
                    918:                if (slash > sizeof(user) - 1)
                    919:                        fatal("tilde_expand_filename: ~username too long");
                    920:                memcpy(user, filename, slash);
                    921:                user[slash] = '\0';
                    922:                if ((pw = getpwnam(user)) == NULL)
                    923:                        fatal("tilde_expand_filename: No such user %s", user);
1.2       christos  924:                homedir = pw->pw_dir;
                    925:        } else {
                    926:                if ((pw = getpwuid(uid)) == NULL)       /* ~/path */
                    927:                        fatal("tilde_expand_filename: No such uid %ld",
                    928:                            (long)uid);
                    929:                homedir = pw->pw_dir;
                    930:        }
1.1       christos  931:
                    932:        /* Make sure directory has a trailing '/' */
1.2       christos  933:        len = strlen(homedir);
1.8       christos  934:        if (len == 0 || homedir[len - 1] != '/')
                    935:                sep = "/";
                    936:        else
                    937:                sep = "";
1.1       christos  938:
                    939:        /* Skip leading '/' from specified path */
                    940:        if (path != NULL)
                    941:                filename = path + 1;
1.8       christos  942:
1.10      christos  943:        if (xasprintf(&ret, "%s%s%s", homedir, sep, filename) >= PATH_MAX)
1.1       christos  944:                fatal("tilde_expand_filename: Path too long");
                    945:
1.8       christos  946:        return (ret);
1.1       christos  947: }
                    948:
                    949: /*
                    950:  * Expand a string with a set of %[char] escapes. A number of escapes may be
                    951:  * specified as (char *escape_chars, char *replacement) pairs. The list must
                    952:  * be terminated by a NULL escape_char. Returns replaced string in memory
                    953:  * allocated by xmalloc.
                    954:  */
                    955: char *
                    956: percent_expand(const char *string, ...)
                    957: {
                    958: #define EXPAND_MAX_KEYS        16
1.4       adam      959:        u_int num_keys, i, j;
1.1       christos  960:        struct {
                    961:                const char *key;
                    962:                const char *repl;
                    963:        } keys[EXPAND_MAX_KEYS];
                    964:        char buf[4096];
                    965:        va_list ap;
                    966:
                    967:        /* Gather keys */
                    968:        va_start(ap, string);
                    969:        for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
                    970:                keys[num_keys].key = va_arg(ap, char *);
                    971:                if (keys[num_keys].key == NULL)
                    972:                        break;
                    973:                keys[num_keys].repl = va_arg(ap, char *);
                    974:                if (keys[num_keys].repl == NULL)
1.4       adam      975:                        fatal("%s: NULL replacement", __func__);
1.1       christos  976:        }
1.4       adam      977:        if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
                    978:                fatal("%s: too many keys", __func__);
1.1       christos  979:        va_end(ap);
                    980:
                    981:        /* Expand string */
                    982:        *buf = '\0';
                    983:        for (i = 0; *string != '\0'; string++) {
                    984:                if (*string != '%') {
                    985:  append:
                    986:                        buf[i++] = *string;
                    987:                        if (i >= sizeof(buf))
1.4       adam      988:                                fatal("%s: string too long", __func__);
1.1       christos  989:                        buf[i] = '\0';
                    990:                        continue;
                    991:                }
                    992:                string++;
1.4       adam      993:                /* %% case */
1.1       christos  994:                if (*string == '%')
                    995:                        goto append;
1.12      christos  996:                if (*string == '\0')
                    997:                        fatal("%s: invalid format", __func__);
1.1       christos  998:                for (j = 0; j < num_keys; j++) {
                    999:                        if (strchr(keys[j].key, *string) != NULL) {
                   1000:                                i = strlcat(buf, keys[j].repl, sizeof(buf));
                   1001:                                if (i >= sizeof(buf))
1.4       adam     1002:                                        fatal("%s: string too long", __func__);
1.1       christos 1003:                                break;
                   1004:                        }
                   1005:                }
                   1006:                if (j >= num_keys)
1.4       adam     1007:                        fatal("%s: unknown key %%%c", __func__, *string);
1.1       christos 1008:        }
                   1009:        return (xstrdup(buf));
                   1010: #undef EXPAND_MAX_KEYS
                   1011: }
                   1012:
                   1013: int
1.16.2.1  pgoyette 1014: tun_open(int tun, int mode, char **ifname)
1.1       christos 1015: {
                   1016:        struct ifreq ifr;
1.12      christos 1017:        char name[100];
                   1018:        int fd = -1, sock;
                   1019:        const char *tunbase = "tun";
                   1020:
1.16.2.1  pgoyette 1021:        if (ifname != NULL)
                   1022:                *ifname = NULL;
                   1023:
1.12      christos 1024:        if (mode == SSH_TUNMODE_ETHERNET)
                   1025:                tunbase = "tap";
1.1       christos 1026:
                   1027:        /* Open the tunnel device */
                   1028:        if (tun <= SSH_TUNID_MAX) {
1.12      christos 1029:                snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
                   1030:                fd = open(name, O_RDWR);
1.1       christos 1031:        } else if (tun == SSH_TUNID_ANY) {
                   1032:                for (tun = 100; tun >= 0; tun--) {
1.12      christos 1033:                        snprintf(name, sizeof(name), "/dev/%s%d",
                   1034:                            tunbase, tun);
                   1035:                        if ((fd = open(name, O_RDWR)) >= 0)
1.1       christos 1036:                                break;
                   1037:                }
                   1038:        } else {
                   1039:                debug("%s: invalid tunnel %u", __func__, tun);
1.12      christos 1040:                return -1;
1.1       christos 1041:        }
                   1042:
                   1043:        if (fd < 0) {
1.12      christos 1044:                debug("%s: %s open: %s", __func__, name, strerror(errno));
                   1045:                return -1;
1.1       christos 1046:        }
                   1047:
                   1048:
1.12      christos 1049: #ifdef TUNSIFHEAD
1.2       christos 1050:        /* Turn on tunnel headers */
1.12      christos 1051:        int flag = 1;
1.2       christos 1052:        if (mode != SSH_TUNMODE_ETHERNET &&
                   1053:            ioctl(fd, TUNSIFHEAD, &flag) == -1) {
                   1054:                debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd,
                   1055:                    strerror(errno));
                   1056:                close(fd);
                   1057:                return -1;
                   1058:        }
1.12      christos 1059: #endif
1.2       christos 1060:
                   1061:        debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd);
1.12      christos 1062:        /* Bring interface up if it is not already */
1.3       jnemeth  1063:        snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
1.1       christos 1064:        if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
                   1065:                goto failed;
                   1066:
1.12      christos 1067:        if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
                   1068:                debug("%s: get interface %s flags: %s", __func__,
                   1069:                    ifr.ifr_name, strerror(errno));
1.1       christos 1070:                goto failed;
1.12      christos 1071:        }
1.1       christos 1072:
1.12      christos 1073:        if (!(ifr.ifr_flags & IFF_UP)) {
                   1074:                ifr.ifr_flags |= IFF_UP;
                   1075:                if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
                   1076:                        debug("%s: activate interface %s: %s", __func__,
                   1077:                            ifr.ifr_name, strerror(errno));
                   1078:                        goto failed;
                   1079:                }
                   1080:        }
1.1       christos 1081:
1.16.2.1  pgoyette 1082:        if (ifname != NULL)
                   1083:                *ifname = xstrdup(ifr.ifr_name);
                   1084:
1.1       christos 1085:        close(sock);
1.12      christos 1086:        return fd;
1.1       christos 1087:
                   1088:  failed:
                   1089:        if (fd >= 0)
                   1090:                close(fd);
                   1091:        if (sock >= 0)
                   1092:                close(sock);
1.2       christos 1093:        debug("%s: failed to set %s mode %d: %s", __func__, ifr.ifr_name,
1.1       christos 1094:            mode, strerror(errno));
1.12      christos 1095:        return -1;
1.1       christos 1096: }
                   1097:
                   1098: void
                   1099: sanitise_stdfd(void)
                   1100: {
                   1101:        int nullfd, dupfd;
                   1102:
                   1103:        if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
                   1104:                fprintf(stderr, "Couldn't open /dev/null: %s\n",
                   1105:                    strerror(errno));
                   1106:                exit(1);
                   1107:        }
1.13      christos 1108:        while (++dupfd <= STDERR_FILENO) {
                   1109:                /* Only populate closed fds. */
                   1110:                if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) {
                   1111:                        if (dup2(nullfd, dupfd) == -1) {
                   1112:                                fprintf(stderr, "dup2: %s\n", strerror(errno));
                   1113:                                exit(1);
                   1114:                        }
1.1       christos 1115:                }
                   1116:        }
1.13      christos 1117:        if (nullfd > STDERR_FILENO)
1.1       christos 1118:                close(nullfd);
                   1119: }
                   1120:
                   1121: char *
                   1122: tohex(const void *vp, size_t l)
                   1123: {
                   1124:        const u_char *p = (const u_char *)vp;
                   1125:        char b[3], *r;
                   1126:        size_t i, hl;
                   1127:
                   1128:        if (l > 65536)
                   1129:                return xstrdup("tohex: length > 65536");
                   1130:
                   1131:        hl = l * 2 + 1;
                   1132:        r = xcalloc(1, hl);
                   1133:        for (i = 0; i < l; i++) {
                   1134:                snprintf(b, sizeof(b), "%02x", p[i]);
                   1135:                strlcat(r, b, hl);
                   1136:        }
                   1137:        return (r);
                   1138: }
                   1139:
                   1140: u_int64_t
                   1141: get_u64(const void *vp)
                   1142: {
                   1143:        const u_char *p = (const u_char *)vp;
                   1144:        u_int64_t v;
                   1145:
                   1146:        v  = (u_int64_t)p[0] << 56;
                   1147:        v |= (u_int64_t)p[1] << 48;
                   1148:        v |= (u_int64_t)p[2] << 40;
                   1149:        v |= (u_int64_t)p[3] << 32;
                   1150:        v |= (u_int64_t)p[4] << 24;
                   1151:        v |= (u_int64_t)p[5] << 16;
                   1152:        v |= (u_int64_t)p[6] << 8;
                   1153:        v |= (u_int64_t)p[7];
                   1154:
                   1155:        return (v);
                   1156: }
                   1157:
                   1158: u_int32_t
                   1159: get_u32(const void *vp)
                   1160: {
                   1161:        const u_char *p = (const u_char *)vp;
                   1162:        u_int32_t v;
                   1163:
                   1164:        v  = (u_int32_t)p[0] << 24;
                   1165:        v |= (u_int32_t)p[1] << 16;
                   1166:        v |= (u_int32_t)p[2] << 8;
                   1167:        v |= (u_int32_t)p[3];
                   1168:
                   1169:        return (v);
                   1170: }
                   1171:
1.9       christos 1172: u_int32_t
                   1173: get_u32_le(const void *vp)
                   1174: {
                   1175:        const u_char *p = (const u_char *)vp;
                   1176:        u_int32_t v;
                   1177:
                   1178:        v  = (u_int32_t)p[0];
                   1179:        v |= (u_int32_t)p[1] << 8;
                   1180:        v |= (u_int32_t)p[2] << 16;
                   1181:        v |= (u_int32_t)p[3] << 24;
                   1182:
                   1183:        return (v);
                   1184: }
                   1185:
1.1       christos 1186: u_int16_t
                   1187: get_u16(const void *vp)
                   1188: {
                   1189:        const u_char *p = (const u_char *)vp;
                   1190:        u_int16_t v;
                   1191:
                   1192:        v  = (u_int16_t)p[0] << 8;
                   1193:        v |= (u_int16_t)p[1];
                   1194:
                   1195:        return (v);
                   1196: }
                   1197:
                   1198: void
                   1199: put_u64(void *vp, u_int64_t v)
                   1200: {
                   1201:        u_char *p = (u_char *)vp;
                   1202:
                   1203:        p[0] = (u_char)(v >> 56) & 0xff;
                   1204:        p[1] = (u_char)(v >> 48) & 0xff;
                   1205:        p[2] = (u_char)(v >> 40) & 0xff;
                   1206:        p[3] = (u_char)(v >> 32) & 0xff;
                   1207:        p[4] = (u_char)(v >> 24) & 0xff;
                   1208:        p[5] = (u_char)(v >> 16) & 0xff;
                   1209:        p[6] = (u_char)(v >> 8) & 0xff;
                   1210:        p[7] = (u_char)v & 0xff;
                   1211: }
                   1212:
                   1213: void
                   1214: put_u32(void *vp, u_int32_t v)
                   1215: {
                   1216:        u_char *p = (u_char *)vp;
                   1217:
                   1218:        p[0] = (u_char)(v >> 24) & 0xff;
                   1219:        p[1] = (u_char)(v >> 16) & 0xff;
                   1220:        p[2] = (u_char)(v >> 8) & 0xff;
                   1221:        p[3] = (u_char)v & 0xff;
                   1222: }
                   1223:
1.9       christos 1224: void
                   1225: put_u32_le(void *vp, u_int32_t v)
                   1226: {
                   1227:        u_char *p = (u_char *)vp;
                   1228:
                   1229:        p[0] = (u_char)v & 0xff;
                   1230:        p[1] = (u_char)(v >> 8) & 0xff;
                   1231:        p[2] = (u_char)(v >> 16) & 0xff;
                   1232:        p[3] = (u_char)(v >> 24) & 0xff;
                   1233: }
1.1       christos 1234:
                   1235: void
                   1236: put_u16(void *vp, u_int16_t v)
                   1237: {
                   1238:        u_char *p = (u_char *)vp;
                   1239:
                   1240:        p[0] = (u_char)(v >> 8) & 0xff;
                   1241:        p[1] = (u_char)v & 0xff;
                   1242: }
                   1243:
                   1244: void
                   1245: ms_subtract_diff(struct timeval *start, int *ms)
                   1246: {
                   1247:        struct timeval diff, finish;
                   1248:
1.16.2.1  pgoyette 1249:        monotime_tv(&finish);
                   1250:        timersub(&finish, start, &diff);
1.1       christos 1251:        *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
                   1252: }
                   1253:
                   1254: void
                   1255: ms_to_timeval(struct timeval *tv, int ms)
                   1256: {
                   1257:        if (ms < 0)
                   1258:                ms = 0;
                   1259:        tv->tv_sec = ms / 1000;
                   1260:        tv->tv_usec = (ms % 1000) * 1000;
                   1261: }
                   1262:
1.16.2.1  pgoyette 1263: void
                   1264: monotime_ts(struct timespec *ts)
                   1265: {
                   1266:        if (clock_gettime(CLOCK_MONOTONIC, ts) != 0)
                   1267:                fatal("clock_gettime: %s", strerror(errno));
                   1268: }
                   1269:
                   1270: void
                   1271: monotime_tv(struct timeval *tv)
                   1272: {
                   1273:        struct timespec ts;
                   1274:
                   1275:        monotime_ts(&ts);
                   1276:        tv->tv_sec = ts.tv_sec;
                   1277:        tv->tv_usec = ts.tv_nsec / 1000;
                   1278: }
                   1279:
1.8       christos 1280: time_t
                   1281: monotime(void)
                   1282: {
                   1283:        struct timespec ts;
                   1284:
1.16.2.1  pgoyette 1285:        monotime_ts(&ts);
1.8       christos 1286:        return (ts.tv_sec);
                   1287: }
                   1288:
1.13      christos 1289: double
                   1290: monotime_double(void)
                   1291: {
                   1292:        struct timespec ts;
                   1293:
1.16.2.1  pgoyette 1294:        monotime_ts(&ts);
                   1295:        return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
1.13      christos 1296: }
                   1297:
1.5       christos 1298: void
                   1299: bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
                   1300: {
                   1301:        bw->buflen = buflen;
                   1302:        bw->rate = kbps;
                   1303:        bw->thresh = bw->rate;
                   1304:        bw->lamt = 0;
                   1305:        timerclear(&bw->bwstart);
                   1306:        timerclear(&bw->bwend);
                   1307: }
                   1308:
                   1309: /* Callback from read/write loop to insert bandwidth-limiting delays */
                   1310: void
                   1311: bandwidth_limit(struct bwlimit *bw, size_t read_len)
                   1312: {
                   1313:        u_int64_t waitlen;
                   1314:        struct timespec ts, rm;
                   1315:
                   1316:        if (!timerisset(&bw->bwstart)) {
1.16.2.1  pgoyette 1317:                monotime_tv(&bw->bwstart);
1.5       christos 1318:                return;
                   1319:        }
                   1320:
                   1321:        bw->lamt += read_len;
                   1322:        if (bw->lamt < bw->thresh)
                   1323:                return;
                   1324:
1.16.2.1  pgoyette 1325:        monotime_tv(&bw->bwend);
1.5       christos 1326:        timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
                   1327:        if (!timerisset(&bw->bwend))
                   1328:                return;
                   1329:
                   1330:        bw->lamt *= 8;
                   1331:        waitlen = (double)1000000L * bw->lamt / bw->rate;
                   1332:
                   1333:        bw->bwstart.tv_sec = waitlen / 1000000L;
                   1334:        bw->bwstart.tv_usec = waitlen % 1000000L;
                   1335:
                   1336:        if (timercmp(&bw->bwstart, &bw->bwend, >)) {
                   1337:                timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
                   1338:
                   1339:                /* Adjust the wait time */
                   1340:                if (bw->bwend.tv_sec) {
                   1341:                        bw->thresh /= 2;
                   1342:                        if (bw->thresh < bw->buflen / 4)
                   1343:                                bw->thresh = bw->buflen / 4;
                   1344:                } else if (bw->bwend.tv_usec < 10000) {
                   1345:                        bw->thresh *= 2;
                   1346:                        if (bw->thresh > bw->buflen * 8)
                   1347:                                bw->thresh = bw->buflen * 8;
                   1348:                }
                   1349:
                   1350:                TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
                   1351:                while (nanosleep(&ts, &rm) == -1) {
                   1352:                        if (errno != EINTR)
                   1353:                                break;
                   1354:                        ts = rm;
                   1355:                }
                   1356:        }
                   1357:
                   1358:        bw->lamt = 0;
1.16.2.1  pgoyette 1359:        monotime_tv(&bw->bwstart);
1.5       christos 1360: }
                   1361:
                   1362: /* Make a template filename for mk[sd]temp() */
                   1363: void
                   1364: mktemp_proto(char *s, size_t len)
                   1365: {
                   1366:        const char *tmpdir;
                   1367:        int r;
                   1368:
                   1369:        if ((tmpdir = getenv("TMPDIR")) != NULL) {
                   1370:                r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
                   1371:                if (r > 0 && (size_t)r < len)
                   1372:                        return;
                   1373:        }
                   1374:        r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
                   1375:        if (r < 0 || (size_t)r >= len)
                   1376:                fatal("%s: template string too short", __func__);
                   1377: }
                   1378:
                   1379: static const struct {
                   1380:        const char *name;
                   1381:        int value;
                   1382: } ipqos[] = {
1.16      christos 1383:        { "none", INT_MAX },            /* can't use 0 here; that's CS0 */
1.5       christos 1384:        { "af11", IPTOS_DSCP_AF11 },
                   1385:        { "af12", IPTOS_DSCP_AF12 },
                   1386:        { "af13", IPTOS_DSCP_AF13 },
1.7       christos 1387:        { "af21", IPTOS_DSCP_AF21 },
1.5       christos 1388:        { "af22", IPTOS_DSCP_AF22 },
                   1389:        { "af23", IPTOS_DSCP_AF23 },
                   1390:        { "af31", IPTOS_DSCP_AF31 },
                   1391:        { "af32", IPTOS_DSCP_AF32 },
                   1392:        { "af33", IPTOS_DSCP_AF33 },
                   1393:        { "af41", IPTOS_DSCP_AF41 },
                   1394:        { "af42", IPTOS_DSCP_AF42 },
                   1395:        { "af43", IPTOS_DSCP_AF43 },
                   1396:        { "cs0", IPTOS_DSCP_CS0 },
                   1397:        { "cs1", IPTOS_DSCP_CS1 },
                   1398:        { "cs2", IPTOS_DSCP_CS2 },
                   1399:        { "cs3", IPTOS_DSCP_CS3 },
                   1400:        { "cs4", IPTOS_DSCP_CS4 },
                   1401:        { "cs5", IPTOS_DSCP_CS5 },
                   1402:        { "cs6", IPTOS_DSCP_CS6 },
                   1403:        { "cs7", IPTOS_DSCP_CS7 },
                   1404:        { "ef", IPTOS_DSCP_EF },
                   1405:        { "lowdelay", IPTOS_LOWDELAY },
                   1406:        { "throughput", IPTOS_THROUGHPUT },
                   1407:        { "reliability", IPTOS_RELIABILITY },
                   1408:        { NULL, -1 }
                   1409: };
                   1410:
                   1411: int
                   1412: parse_ipqos(const char *cp)
                   1413: {
                   1414:        u_int i;
                   1415:        char *ep;
                   1416:        long val;
                   1417:
                   1418:        if (cp == NULL)
                   1419:                return -1;
                   1420:        for (i = 0; ipqos[i].name != NULL; i++) {
                   1421:                if (strcasecmp(cp, ipqos[i].name) == 0)
                   1422:                        return ipqos[i].value;
                   1423:        }
                   1424:        /* Try parsing as an integer */
                   1425:        val = strtol(cp, &ep, 0);
                   1426:        if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
                   1427:                return -1;
                   1428:        return val;
                   1429: }
                   1430:
1.6       christos 1431: const char *
                   1432: iptos2str(int iptos)
                   1433: {
                   1434:        int i;
                   1435:        static char iptos_str[sizeof "0xff"];
                   1436:
                   1437:        for (i = 0; ipqos[i].name != NULL; i++) {
                   1438:                if (ipqos[i].value == iptos)
                   1439:                        return ipqos[i].name;
                   1440:        }
                   1441:        snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
                   1442:        return iptos_str;
                   1443: }
                   1444:
1.9       christos 1445: void
                   1446: lowercase(char *s)
                   1447: {
                   1448:        for (; *s; s++)
                   1449:                *s = tolower((u_char)*s);
                   1450: }
                   1451:
1.4       adam     1452: int
1.9       christos 1453: unix_listener(const char *path, int backlog, int unlink_first)
1.4       adam     1454: {
1.9       christos 1455:        struct sockaddr_un sunaddr;
                   1456:        int saved_errno, sock;
1.4       adam     1457:
1.9       christos 1458:        memset(&sunaddr, 0, sizeof(sunaddr));
                   1459:        sunaddr.sun_family = AF_UNIX;
1.16.2.1  pgoyette 1460:        if (strlcpy(sunaddr.sun_path, path,
                   1461:            sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
                   1462:                error("%s: path \"%s\" too long for Unix domain socket",
                   1463:                    __func__, path);
1.9       christos 1464:                errno = ENAMETOOLONG;
                   1465:                return -1;
                   1466:        }
                   1467:
                   1468:        sock = socket(PF_UNIX, SOCK_STREAM, 0);
                   1469:        if (sock < 0) {
                   1470:                saved_errno = errno;
1.16.2.1  pgoyette 1471:                error("%s: socket: %.100s", __func__, strerror(errno));
1.9       christos 1472:                errno = saved_errno;
                   1473:                return -1;
                   1474:        }
                   1475:        if (unlink_first == 1) {
                   1476:                if (unlink(path) != 0 && errno != ENOENT)
                   1477:                        error("unlink(%s): %.100s", path, strerror(errno));
                   1478:        }
                   1479:        if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
                   1480:                saved_errno = errno;
1.16.2.1  pgoyette 1481:                error("%s: cannot bind to path %s: %s",
                   1482:                    __func__, path, strerror(errno));
1.9       christos 1483:                close(sock);
                   1484:                errno = saved_errno;
                   1485:                return -1;
                   1486:        }
                   1487:        if (listen(sock, backlog) < 0) {
                   1488:                saved_errno = errno;
1.16.2.1  pgoyette 1489:                error("%s: cannot listen on path %s: %s",
                   1490:                    __func__, path, strerror(errno));
1.9       christos 1491:                close(sock);
                   1492:                unlink(path);
                   1493:                errno = saved_errno;
                   1494:                return -1;
                   1495:        }
                   1496:        return sock;
1.4       adam     1497: }
1.13      christos 1498:
                   1499: /*
                   1500:  * Compares two strings that maybe be NULL. Returns non-zero if strings
                   1501:  * are both NULL or are identical, returns zero otherwise.
                   1502:  */
                   1503: static int
                   1504: strcmp_maybe_null(const char *a, const char *b)
                   1505: {
                   1506:        if ((a == NULL && b != NULL) || (a != NULL && b == NULL))
                   1507:                return 0;
                   1508:        if (a != NULL && strcmp(a, b) != 0)
                   1509:                return 0;
                   1510:        return 1;
                   1511: }
                   1512:
                   1513: /*
                   1514:  * Compare two forwards, returning non-zero if they are identical or
                   1515:  * zero otherwise.
                   1516:  */
                   1517: int
                   1518: forward_equals(const struct Forward *a, const struct Forward *b)
                   1519: {
                   1520:        if (strcmp_maybe_null(a->listen_host, b->listen_host) == 0)
                   1521:                return 0;
                   1522:        if (a->listen_port != b->listen_port)
                   1523:                return 0;
                   1524:        if (strcmp_maybe_null(a->listen_path, b->listen_path) == 0)
                   1525:                return 0;
                   1526:        if (strcmp_maybe_null(a->connect_host, b->connect_host) == 0)
                   1527:                return 0;
                   1528:        if (a->connect_port != b->connect_port)
                   1529:                return 0;
                   1530:        if (strcmp_maybe_null(a->connect_path, b->connect_path) == 0)
                   1531:                return 0;
                   1532:        /* allocated_port and handle are not checked */
                   1533:        return 1;
                   1534: }
                   1535:
1.14      christos 1536: /* returns 1 if process is already daemonized, 0 otherwise */
                   1537: int
                   1538: daemonized(void)
                   1539: {
                   1540:        int fd;
                   1541:
                   1542:        if ((fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY)) >= 0) {
                   1543:                close(fd);
                   1544:                return 0;       /* have controlling terminal */
                   1545:        }
                   1546:        if (getppid() != 1)
                   1547:                return 0;       /* parent is not init */
                   1548:        if (getsid(0) != getpid())
                   1549:                return 0;       /* not session leader */
                   1550:        debug3("already daemonized");
                   1551:        return 1;
                   1552: }
1.16      christos 1553:
                   1554:
                   1555: /*
                   1556:  * Splits 's' into an argument vector. Handles quoted string and basic
                   1557:  * escape characters (\\, \", \'). Caller must free the argument vector
                   1558:  * and its members.
                   1559:  */
                   1560: int
                   1561: argv_split(const char *s, int *argcp, char ***argvp)
                   1562: {
                   1563:        int r = SSH_ERR_INTERNAL_ERROR;
                   1564:        int argc = 0, quote, i, j;
                   1565:        char *arg, **argv = xcalloc(1, sizeof(*argv));
                   1566:
                   1567:        *argvp = NULL;
                   1568:        *argcp = 0;
                   1569:
                   1570:        for (i = 0; s[i] != '\0'; i++) {
                   1571:                /* Skip leading whitespace */
                   1572:                if (s[i] == ' ' || s[i] == '\t')
                   1573:                        continue;
                   1574:
                   1575:                /* Start of a token */
                   1576:                quote = 0;
                   1577:                if (s[i] == '\\' &&
                   1578:                    (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
                   1579:                        i++;
                   1580:                else if (s[i] == '\'' || s[i] == '"')
                   1581:                        quote = s[i++];
                   1582:
                   1583:                argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
                   1584:                arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
                   1585:                argv[argc] = NULL;
                   1586:
                   1587:                /* Copy the token in, removing escapes */
                   1588:                for (j = 0; s[i] != '\0'; i++) {
                   1589:                        if (s[i] == '\\') {
                   1590:                                if (s[i + 1] == '\'' ||
                   1591:                                    s[i + 1] == '\"' ||
                   1592:                                    s[i + 1] == '\\') {
                   1593:                                        i++; /* Skip '\' */
                   1594:                                        arg[j++] = s[i];
                   1595:                                } else {
                   1596:                                        /* Unrecognised escape */
                   1597:                                        arg[j++] = s[i];
                   1598:                                }
                   1599:                        } else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
                   1600:                                break; /* done */
                   1601:                        else if (quote != 0 && s[i] == quote)
                   1602:                                break; /* done */
                   1603:                        else
                   1604:                                arg[j++] = s[i];
                   1605:                }
                   1606:                if (s[i] == '\0') {
                   1607:                        if (quote != 0) {
                   1608:                                /* Ran out of string looking for close quote */
                   1609:                                r = SSH_ERR_INVALID_FORMAT;
                   1610:                                goto out;
                   1611:                        }
                   1612:                        break;
                   1613:                }
                   1614:        }
                   1615:        /* Success */
                   1616:        *argcp = argc;
                   1617:        *argvp = argv;
                   1618:        argc = 0;
                   1619:        argv = NULL;
                   1620:        r = 0;
                   1621:  out:
                   1622:        if (argc != 0 && argv != NULL) {
                   1623:                for (i = 0; i < argc; i++)
                   1624:                        free(argv[i]);
                   1625:                free(argv);
                   1626:        }
                   1627:        return r;
                   1628: }
                   1629:
                   1630: /*
                   1631:  * Reassemble an argument vector into a string, quoting and escaping as
                   1632:  * necessary. Caller must free returned string.
                   1633:  */
                   1634: char *
                   1635: argv_assemble(int argc, char **argv)
                   1636: {
                   1637:        int i, j, ws, r;
                   1638:        char c, *ret;
                   1639:        struct sshbuf *buf, *arg;
                   1640:
                   1641:        if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
                   1642:                fatal("%s: sshbuf_new failed", __func__);
                   1643:
                   1644:        for (i = 0; i < argc; i++) {
                   1645:                ws = 0;
                   1646:                sshbuf_reset(arg);
                   1647:                for (j = 0; argv[i][j] != '\0'; j++) {
                   1648:                        r = 0;
                   1649:                        c = argv[i][j];
                   1650:                        switch (c) {
                   1651:                        case ' ':
                   1652:                        case '\t':
                   1653:                                ws = 1;
                   1654:                                r = sshbuf_put_u8(arg, c);
                   1655:                                break;
                   1656:                        case '\\':
                   1657:                        case '\'':
                   1658:                        case '"':
                   1659:                                if ((r = sshbuf_put_u8(arg, '\\')) != 0)
                   1660:                                        break;
                   1661:                                /* FALLTHROUGH */
                   1662:                        default:
                   1663:                                r = sshbuf_put_u8(arg, c);
                   1664:                                break;
                   1665:                        }
                   1666:                        if (r != 0)
                   1667:                                fatal("%s: sshbuf_put_u8: %s",
                   1668:                                    __func__, ssh_err(r));
                   1669:                }
                   1670:                if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
                   1671:                    (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
                   1672:                    (r = sshbuf_putb(buf, arg)) != 0 ||
                   1673:                    (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
                   1674:                        fatal("%s: buffer error: %s", __func__, ssh_err(r));
                   1675:        }
                   1676:        if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
                   1677:                fatal("%s: malloc failed", __func__);
                   1678:        memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
                   1679:        ret[sshbuf_len(buf)] = '\0';
                   1680:        sshbuf_free(buf);
                   1681:        sshbuf_free(arg);
                   1682:        return ret;
                   1683: }
                   1684:
                   1685: /* Returns 0 if pid exited cleanly, non-zero otherwise */
                   1686: int
                   1687: exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet)
                   1688: {
                   1689:        int status;
                   1690:
                   1691:        while (waitpid(pid, &status, 0) == -1) {
                   1692:                if (errno != EINTR) {
                   1693:                        error("%s: waitpid: %s", tag, strerror(errno));
                   1694:                        return -1;
                   1695:                }
                   1696:        }
                   1697:        if (WIFSIGNALED(status)) {
                   1698:                error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
                   1699:                return -1;
                   1700:        } else if (WEXITSTATUS(status) != 0) {
                   1701:                do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
                   1702:                    "%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
                   1703:                return -1;
                   1704:        }
                   1705:        return 0;
                   1706: }
                   1707:
                   1708: /*
                   1709:  * Check a given path for security. This is defined as all components
                   1710:  * of the path to the file must be owned by either the owner of
                   1711:  * of the file or root and no directories must be group or world writable.
                   1712:  *
                   1713:  * XXX Should any specific check be done for sym links ?
                   1714:  *
                   1715:  * Takes a file name, its stat information (preferably from fstat() to
                   1716:  * avoid races), the uid of the expected owner, their home directory and an
                   1717:  * error buffer plus max size as arguments.
                   1718:  *
                   1719:  * Returns 0 on success and -1 on failure
                   1720:  */
                   1721: int
                   1722: safe_path(const char *name, struct stat *stp, const char *pw_dir,
                   1723:     uid_t uid, char *err, size_t errlen)
                   1724: {
                   1725:        char buf[PATH_MAX], homedir[PATH_MAX];
                   1726:        char *cp;
                   1727:        int comparehome = 0;
                   1728:        struct stat st;
                   1729:
                   1730:        if (realpath(name, buf) == NULL) {
                   1731:                snprintf(err, errlen, "realpath %s failed: %s", name,
                   1732:                    strerror(errno));
                   1733:                return -1;
                   1734:        }
                   1735:        if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
                   1736:                comparehome = 1;
                   1737:
                   1738:        if (!S_ISREG(stp->st_mode)) {
                   1739:                snprintf(err, errlen, "%s is not a regular file", buf);
                   1740:                return -1;
                   1741:        }
                   1742:        if ((stp->st_uid != 0 && stp->st_uid != uid) ||
                   1743:            (stp->st_mode & 022) != 0) {
                   1744:                snprintf(err, errlen, "bad ownership or modes for file %s",
                   1745:                    buf);
                   1746:                return -1;
                   1747:        }
                   1748:
                   1749:        /* for each component of the canonical path, walking upwards */
                   1750:        for (;;) {
                   1751:                if ((cp = dirname(buf)) == NULL) {
                   1752:                        snprintf(err, errlen, "dirname() failed");
                   1753:                        return -1;
                   1754:                }
                   1755:                strlcpy(buf, cp, sizeof(buf));
                   1756:
                   1757:                if (stat(buf, &st) < 0 ||
                   1758:                    (st.st_uid != 0 && st.st_uid != uid) ||
                   1759:                    (st.st_mode & 022) != 0) {
                   1760:                        snprintf(err, errlen,
                   1761:                            "bad ownership or modes for directory %s", buf);
                   1762:                        return -1;
                   1763:                }
                   1764:
                   1765:                /* If are past the homedir then we can stop */
                   1766:                if (comparehome && strcmp(homedir, buf) == 0)
                   1767:                        break;
                   1768:
                   1769:                /*
                   1770:                 * dirname should always complete with a "/" path,
                   1771:                 * but we can be paranoid and check for "." too
                   1772:                 */
                   1773:                if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
                   1774:                        break;
                   1775:        }
                   1776:        return 0;
                   1777: }
                   1778:
                   1779: /*
                   1780:  * Version of safe_path() that accepts an open file descriptor to
                   1781:  * avoid races.
                   1782:  *
                   1783:  * Returns 0 on success and -1 on failure
                   1784:  */
                   1785: int
                   1786: safe_path_fd(int fd, const char *file, struct passwd *pw,
                   1787:     char *err, size_t errlen)
                   1788: {
                   1789:        struct stat st;
                   1790:
                   1791:        /* check the open file to avoid races */
                   1792:        if (fstat(fd, &st) < 0) {
                   1793:                snprintf(err, errlen, "cannot stat file %s: %s",
                   1794:                    file, strerror(errno));
                   1795:                return -1;
                   1796:        }
                   1797:        return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
                   1798: }
                   1799:
                   1800: /*
                   1801:  * Sets the value of the given variable in the environment.  If the variable
                   1802:  * already exists, its value is overridden.
                   1803:  */
                   1804: void
                   1805: child_set_env(char ***envp, u_int *envsizep, const char *name,
                   1806:        const char *value)
                   1807: {
                   1808:        char **env;
                   1809:        u_int envsize;
                   1810:        u_int i, namelen;
                   1811:
                   1812:        if (strchr(name, '=') != NULL) {
                   1813:                error("Invalid environment variable \"%.100s\"", name);
                   1814:                return;
                   1815:        }
                   1816:
                   1817:        /*
                   1818:         * Find the slot where the value should be stored.  If the variable
                   1819:         * already exists, we reuse the slot; otherwise we append a new slot
                   1820:         * at the end of the array, expanding if necessary.
                   1821:         */
                   1822:        env = *envp;
                   1823:        namelen = strlen(name);
                   1824:        for (i = 0; env[i]; i++)
                   1825:                if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
                   1826:                        break;
                   1827:        if (env[i]) {
                   1828:                /* Reuse the slot. */
                   1829:                free(env[i]);
                   1830:        } else {
                   1831:                /* New variable.  Expand if necessary. */
                   1832:                envsize = *envsizep;
                   1833:                if (i >= envsize - 1) {
                   1834:                        if (envsize >= 1000)
                   1835:                                fatal("child_set_env: too many env vars");
                   1836:                        envsize += 50;
                   1837:                        env = (*envp) = xreallocarray(env, envsize, sizeof(char *));
                   1838:                        *envsizep = envsize;
                   1839:                }
                   1840:                /* Need to set the NULL pointer at end of array beyond the new slot. */
                   1841:                env[i + 1] = NULL;
                   1842:        }
                   1843:
                   1844:        /* Allocate space and format the variable in the appropriate slot. */
1.16.2.1  pgoyette 1845:        /* XXX xasprintf */
1.16      christos 1846:        env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
                   1847:        snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
                   1848: }
                   1849:
1.16.2.1  pgoyette 1850: /*
                   1851:  * Check and optionally lowercase a domain name, also removes trailing '.'
                   1852:  * Returns 1 on success and 0 on failure, storing an error message in errstr.
                   1853:  */
                   1854: int
                   1855: valid_domain(char *name, int makelower, const char **errstr)
                   1856: {
                   1857:        size_t i, l = strlen(name);
                   1858:        u_char c, last = '\0';
                   1859:        static char errbuf[256];
                   1860:
                   1861:        if (l == 0) {
                   1862:                strlcpy(errbuf, "empty domain name", sizeof(errbuf));
                   1863:                goto bad;
                   1864:        }
                   1865:        if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) {
                   1866:                snprintf(errbuf, sizeof(errbuf), "domain name \"%.100s\" "
                   1867:                    "starts with invalid character", name);
                   1868:                goto bad;
                   1869:        }
                   1870:        for (i = 0; i < l; i++) {
                   1871:                c = tolower((u_char)name[i]);
                   1872:                if (makelower)
                   1873:                        name[i] = (char)c;
                   1874:                if (last == '.' && c == '.') {
                   1875:                        snprintf(errbuf, sizeof(errbuf), "domain name "
                   1876:                            "\"%.100s\" contains consecutive separators", name);
                   1877:                        goto bad;
                   1878:                }
                   1879:                if (c != '.' && c != '-' && !isalnum(c) &&
                   1880:                    c != '_') /* technically invalid, but common */ {
                   1881:                        snprintf(errbuf, sizeof(errbuf), "domain name "
                   1882:                            "\"%.100s\" contains invalid characters", name);
                   1883:                        goto bad;
                   1884:                }
                   1885:                last = c;
                   1886:        }
                   1887:        if (name[l - 1] == '.')
                   1888:                name[l - 1] = '\0';
                   1889:        if (errstr != NULL)
                   1890:                *errstr = NULL;
                   1891:        return 1;
                   1892: bad:
                   1893:        if (errstr != NULL)
                   1894:                *errstr = errbuf;
                   1895:        return 0;
                   1896: }
                   1897:
                   1898: const char *
                   1899: atoi_err(const char *nptr, int *val)
                   1900: {
                   1901:        const char *errstr = NULL;
                   1902:        long long num;
                   1903:
                   1904:        if (nptr == NULL || *nptr == '\0')
                   1905:                return "missing";
                   1906:        num = strtonum(nptr, 0, INT_MAX, &errstr);
                   1907:        if (errstr == NULL)
                   1908:                *val = (int)num;
                   1909:        return errstr;
                   1910: }
                   1911:
                   1912: int
                   1913: parse_absolute_time(const char *s, uint64_t *tp)
                   1914: {
                   1915:        struct tm tm;
                   1916:        time_t tt;
                   1917:        char buf[32];
                   1918:        const char *fmt;
                   1919:
                   1920:        *tp = 0;
                   1921:
                   1922:        /*
                   1923:         * POSIX strptime says "The application shall ensure that there
                   1924:         * is white-space or other non-alphanumeric characters between
                   1925:         * any two conversion specifications" so arrange things this way.
                   1926:         */
                   1927:        switch (strlen(s)) {
                   1928:        case 8: /* YYYYMMDD */
                   1929:                fmt = "%Y-%m-%d";
                   1930:                snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6);
                   1931:                break;
                   1932:        case 12: /* YYYYMMDDHHMM */
                   1933:                fmt = "%Y-%m-%dT%H:%M";
                   1934:                snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s",
                   1935:                    s, s + 4, s + 6, s + 8, s + 10);
                   1936:                break;
                   1937:        case 14: /* YYYYMMDDHHMMSS */
                   1938:                fmt = "%Y-%m-%dT%H:%M:%S";
                   1939:                snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s",
                   1940:                    s, s + 4, s + 6, s + 8, s + 10, s + 12);
                   1941:                break;
                   1942:        default:
                   1943:                return SSH_ERR_INVALID_FORMAT;
                   1944:        }
                   1945:
                   1946:        memset(&tm, 0, sizeof(tm));
                   1947:        if (strptime(buf, fmt, &tm) == NULL)
                   1948:                return SSH_ERR_INVALID_FORMAT;
                   1949:        if ((tt = mktime(&tm)) < 0)
                   1950:                return SSH_ERR_INVALID_FORMAT;
                   1951:        /* success */
                   1952:        *tp = (uint64_t)tt;
                   1953:        return 0;
                   1954: }
                   1955:
                   1956: void
                   1957: format_absolute_time(uint64_t t, char *buf, size_t len)
                   1958: {
                   1959:        time_t tt = t > INT_MAX ? INT_MAX : t; /* XXX revisit in 2038 :P */
                   1960:        struct tm tm;
                   1961:
                   1962:        localtime_r(&tt, &tm);
                   1963:        strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
                   1964: }

CVSweb <webmaster@jp.NetBSD.org>