[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.1.1.15

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

CVSweb <webmaster@jp.NetBSD.org>