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

Annotation of src/usr.bin/ssh/hostfile.c, Revision 1.61

1.61    ! djm         1: /* $OpenBSD: hostfile.c,v 1.60 2015/01/18 21:40:23 djm Exp $ */
1.1       deraadt     2: /*
1.8       deraadt     3:  * Author: Tatu Ylonen <ylo@cs.hut.fi>
                      4:  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
                      5:  *                    All rights reserved
                      6:  * Functions for manipulating the known hosts files.
1.16      markus      7:  *
1.20      deraadt     8:  * As far as I am concerned, the code I have written for this software
                      9:  * can be used freely for any purpose.  Any derived versions of this
                     10:  * software must be clearly marked as such, and if the derived work is
                     11:  * incompatible with the protocol description in the RFC file, it must be
                     12:  * called by a name other than "ssh" or "Secure Shell".
                     13:  *
                     14:  *
1.28      markus     15:  * Copyright (c) 1999, 2000 Markus Friedl.  All rights reserved.
1.20      deraadt    16:  * Copyright (c) 1999 Niels Provos.  All rights reserved.
                     17:  *
                     18:  * Redistribution and use in source and binary forms, with or without
                     19:  * modification, are permitted provided that the following conditions
                     20:  * are met:
                     21:  * 1. Redistributions of source code must retain the above copyright
                     22:  *    notice, this list of conditions and the following disclaimer.
                     23:  * 2. Redistributions in binary form must reproduce the above copyright
                     24:  *    notice, this list of conditions and the following disclaimer in the
                     25:  *    documentation and/or other materials provided with the distribution.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     28:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     29:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     30:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     31:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     32:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     33:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     34:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     35:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     36:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.8       deraadt    37:  */
1.1       deraadt    38:
1.41      stevesk    39: #include <sys/types.h>
                     40:
                     41: #include <netinet/in.h>
1.33      djm        42:
1.60      djm        43: #include <errno.h>
1.33      djm        44: #include <resolv.h>
1.44      stevesk    45: #include <stdio.h>
1.43      stevesk    46: #include <stdlib.h>
1.42      stevesk    47: #include <string.h>
1.57      djm        48: #include <stdarg.h>
1.1       deraadt    49:
1.45      deraadt    50: #include "xmalloc.h"
1.14      markus     51: #include "match.h"
1.59      djm        52: #include "sshkey.h"
1.14      markus     53: #include "hostfile.h"
1.24      markus     54: #include "log.h"
1.49      djm        55: #include "misc.h"
1.59      djm        56: #include "ssherr.h"
1.53      djm        57: #include "digest.h"
1.54      markus     58: #include "hmac.h"
1.49      djm        59:
                     60: struct hostkeys {
                     61:        struct hostkey_entry *entries;
                     62:        u_int num_entries;
                     63: };
1.33      djm        64:
1.60      djm        65: /* XXX hmac is too easy to dictionary attack; use bcrypt? */
                     66:
1.33      djm        67: static int
1.52      djm        68: extract_salt(const char *s, u_int l, u_char *salt, size_t salt_len)
1.33      djm        69: {
                     70:        char *p, *b64salt;
                     71:        u_int b64len;
                     72:        int ret;
                     73:
                     74:        if (l < sizeof(HASH_MAGIC) - 1) {
                     75:                debug2("extract_salt: string too short");
                     76:                return (-1);
                     77:        }
                     78:        if (strncmp(s, HASH_MAGIC, sizeof(HASH_MAGIC) - 1) != 0) {
                     79:                debug2("extract_salt: invalid magic identifier");
                     80:                return (-1);
                     81:        }
                     82:        s += sizeof(HASH_MAGIC) - 1;
                     83:        l -= sizeof(HASH_MAGIC) - 1;
                     84:        if ((p = memchr(s, HASH_DELIM, l)) == NULL) {
                     85:                debug2("extract_salt: missing salt termination character");
                     86:                return (-1);
                     87:        }
                     88:
                     89:        b64len = p - s;
                     90:        /* Sanity check */
                     91:        if (b64len == 0 || b64len > 1024) {
                     92:                debug2("extract_salt: bad encoded salt length %u", b64len);
                     93:                return (-1);
                     94:        }
                     95:        b64salt = xmalloc(1 + b64len);
                     96:        memcpy(b64salt, s, b64len);
                     97:        b64salt[b64len] = '\0';
                     98:
                     99:        ret = __b64_pton(b64salt, salt, salt_len);
1.51      djm       100:        free(b64salt);
1.33      djm       101:        if (ret == -1) {
                    102:                debug2("extract_salt: salt decode error");
                    103:                return (-1);
                    104:        }
1.54      markus    105:        if (ret != (int)ssh_hmac_bytes(SSH_DIGEST_SHA1)) {
                    106:                debug2("extract_salt: expected salt len %zd, got %d",
                    107:                    ssh_hmac_bytes(SSH_DIGEST_SHA1), ret);
1.33      djm       108:                return (-1);
                    109:        }
1.34      deraadt   110:
1.33      djm       111:        return (0);
                    112: }
                    113:
                    114: char *
                    115: host_hash(const char *host, const char *name_from_hostfile, u_int src_len)
                    116: {
1.54      markus    117:        struct ssh_hmac_ctx *ctx;
1.52      djm       118:        u_char salt[256], result[256];
                    119:        char uu_salt[512], uu_result[512];
1.33      djm       120:        static char encoded[1024];
                    121:        u_int i, len;
                    122:
1.54      markus    123:        len = ssh_digest_bytes(SSH_DIGEST_SHA1);
1.33      djm       124:
                    125:        if (name_from_hostfile == NULL) {
                    126:                /* Create new salt */
                    127:                for (i = 0; i < len; i++)
                    128:                        salt[i] = arc4random();
                    129:        } else {
                    130:                /* Extract salt from known host entry */
                    131:                if (extract_salt(name_from_hostfile, src_len, salt,
                    132:                    sizeof(salt)) == -1)
                    133:                        return (NULL);
                    134:        }
                    135:
1.54      markus    136:        if ((ctx = ssh_hmac_start(SSH_DIGEST_SHA1)) == NULL ||
                    137:            ssh_hmac_init(ctx, salt, len) < 0 ||
                    138:            ssh_hmac_update(ctx, host, strlen(host)) < 0 ||
                    139:            ssh_hmac_final(ctx, result, sizeof(result)))
                    140:                fatal("%s: ssh_hmac failed", __func__);
                    141:        ssh_hmac_free(ctx);
1.33      djm       142:
1.34      deraadt   143:        if (__b64_ntop(salt, len, uu_salt, sizeof(uu_salt)) == -1 ||
1.33      djm       144:            __b64_ntop(result, len, uu_result, sizeof(uu_result)) == -1)
1.54      markus    145:                fatal("%s: __b64_ntop failed", __func__);
1.33      djm       146:
                    147:        snprintf(encoded, sizeof(encoded), "%s%s%c%s", HASH_MAGIC, uu_salt,
                    148:            HASH_DELIM, uu_result);
                    149:
                    150:        return (encoded);
                    151: }
1.1       deraadt   152:
1.9       markus    153: /*
1.14      markus    154:  * Parses an RSA (number of bits, e, n) or DSA key from a string.  Moves the
                    155:  * pointer over the key.  Skips any whitespace at the beginning and at end.
1.9       markus    156:  */
1.1       deraadt   157:
1.29      jakob     158: int
1.59      djm       159: hostfile_read_key(char **cpp, u_int *bitsp, struct sshkey *ret)
1.1       deraadt   160: {
1.7       markus    161:        char *cp;
1.59      djm       162:        int r;
1.7       markus    163:
                    164:        /* Skip leading whitespace. */
1.9       markus    165:        for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
                    166:                ;
1.1       deraadt   167:
1.59      djm       168:        if ((r = sshkey_read(ret, &cp)) != 0)
1.7       markus    169:                return 0;
                    170:
                    171:        /* Skip trailing whitespace. */
1.9       markus    172:        for (; *cp == ' ' || *cp == '\t'; cp++)
                    173:                ;
1.7       markus    174:
                    175:        /* Return results. */
                    176:        *cpp = cp;
1.59      djm       177:        if (bitsp != NULL)
                    178:                *bitsp = sshkey_size(ret);
1.7       markus    179:        return 1;
1.14      markus    180: }
1.1       deraadt   181:
1.27      itojun    182: static int
1.59      djm       183: hostfile_check_key(int bits, const struct sshkey *key, const char *host,
1.49      djm       184:     const char *filename, u_long linenum)
1.1       deraadt   185: {
1.56      markus    186: #ifdef WITH_SSH1
1.21      markus    187:        if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
1.14      markus    188:                return 1;
                    189:        if (bits != BN_num_bits(key->rsa->n)) {
1.49      djm       190:                logit("Warning: %s, line %lu: keysize mismatch for host %s: "
1.14      markus    191:                    "actual %d vs. announced %d.",
                    192:                    filename, linenum, host, BN_num_bits(key->rsa->n), bits);
1.49      djm       193:                logit("Warning: replace %d with %d in %s, line %lu.",
1.14      markus    194:                    bits, BN_num_bits(key->rsa->n), filename, linenum);
1.1       deraadt   195:        }
1.56      markus    196: #endif
1.14      markus    197:        return 1;
1.1       deraadt   198: }
                    199:
1.49      djm       200: static HostkeyMarker
1.48      djm       201: check_markers(char **cpp)
                    202: {
                    203:        char marker[32], *sp, *cp = *cpp;
                    204:        int ret = MRK_NONE;
                    205:
                    206:        while (*cp == '@') {
                    207:                /* Only one marker is allowed */
                    208:                if (ret != MRK_NONE)
                    209:                        return MRK_ERROR;
                    210:                /* Markers are terminated by whitespace */
                    211:                if ((sp = strchr(cp, ' ')) == NULL &&
                    212:                    (sp = strchr(cp, '\t')) == NULL)
                    213:                        return MRK_ERROR;
                    214:                /* Extract marker for comparison */
                    215:                if (sp <= cp + 1 || sp >= cp + sizeof(marker))
                    216:                        return MRK_ERROR;
                    217:                memcpy(marker, cp, sp - cp);
                    218:                marker[sp - cp] = '\0';
                    219:                if (strcmp(marker, CA_MARKER) == 0)
                    220:                        ret = MRK_CA;
                    221:                else if (strcmp(marker, REVOKE_MARKER) == 0)
                    222:                        ret = MRK_REVOKE;
                    223:                else
                    224:                        return MRK_ERROR;
                    225:
                    226:                /* Skip past marker and any whitespace that follows it */
                    227:                cp = sp;
                    228:                for (; *cp == ' ' || *cp == '\t'; cp++)
                    229:                        ;
                    230:        }
                    231:        *cpp = cp;
                    232:        return ret;
                    233: }
                    234:
1.49      djm       235: struct hostkeys *
                    236: init_hostkeys(void)
                    237: {
                    238:        struct hostkeys *ret = xcalloc(1, sizeof(*ret));
                    239:
                    240:        ret->entries = NULL;
                    241:        return ret;
                    242: }
1.1       deraadt   243:
1.61    ! djm       244: struct load_callback_ctx {
        !           245:        const char *host;
        !           246:        u_long num_loaded;
        !           247:        struct hostkeys *hostkeys;
        !           248: };
        !           249:
        !           250: static int
        !           251: record_hostkey(struct hostkey_foreach_line *l, void *_ctx)
1.1       deraadt   252: {
1.61    ! djm       253:        struct load_callback_ctx *ctx = (struct load_callback_ctx *)_ctx;
        !           254:        struct hostkeys *hostkeys = ctx->hostkeys;
        !           255:        struct hostkey_entry *tmp;
        !           256:
        !           257:        if (l->status == HKF_STATUS_INVALID) {
        !           258:                error("%s:%ld: parse error in hostkeys file",
        !           259:                    l->path, l->linenum);
        !           260:                return 0;
        !           261:        }
1.7       markus    262:
1.61    ! djm       263:        debug3("%s: found %skey type %s in file %s:%lu", __func__,
        !           264:            l->marker == MRK_NONE ? "" :
        !           265:            (l->marker == MRK_CA ? "ca " : "revoked "),
        !           266:            sshkey_type(l->key), l->path, l->linenum);
        !           267:        if ((tmp = reallocarray(hostkeys->entries,
        !           268:            hostkeys->num_entries + 1, sizeof(*hostkeys->entries))) == NULL)
        !           269:                return SSH_ERR_ALLOC_FAIL;
        !           270:        hostkeys->entries = tmp;
        !           271:        hostkeys->entries[hostkeys->num_entries].host = xstrdup(ctx->host);
        !           272:        hostkeys->entries[hostkeys->num_entries].file = xstrdup(l->path);
        !           273:        hostkeys->entries[hostkeys->num_entries].line = l->linenum;
        !           274:        hostkeys->entries[hostkeys->num_entries].key = l->key;
        !           275:        l->key = NULL; /* steal it */
        !           276:        hostkeys->entries[hostkeys->num_entries].marker = l->marker;
        !           277:        hostkeys->num_entries++;
        !           278:        ctx->num_loaded++;
1.7       markus    279:
1.61    ! djm       280:        return 0;
        !           281: }
1.47      djm       282:
1.61    ! djm       283: void
        !           284: load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path)
        !           285: {
        !           286:        int r;
        !           287:        struct load_callback_ctx ctx;
1.7       markus    288:
1.61    ! djm       289:        ctx.host = host;
        !           290:        ctx.num_loaded = 0;
        !           291:        ctx.hostkeys = hostkeys;
        !           292:
        !           293:        if ((r = hostkeys_foreach(path, record_hostkey, &ctx, host,
        !           294:            HKF_WANT_MATCH_HOST|HKF_WANT_PARSE_KEY)) != 0) {
        !           295:                if (r != SSH_ERR_SYSTEM_ERROR && errno != ENOENT)
        !           296:                        debug("%s: hostkeys_foreach failed for %s: %s",
        !           297:                            __func__, path, ssh_err(r));
        !           298:        }
        !           299:        if (ctx.num_loaded != 0)
        !           300:                debug3("%s: loaded %lu keys from %s", __func__,
        !           301:                    ctx.num_loaded, host);
1.58      djm       302: }
1.49      djm       303:
                    304: void
                    305: free_hostkeys(struct hostkeys *hostkeys)
                    306: {
                    307:        u_int i;
                    308:
                    309:        for (i = 0; i < hostkeys->num_entries; i++) {
1.51      djm       310:                free(hostkeys->entries[i].host);
                    311:                free(hostkeys->entries[i].file);
1.59      djm       312:                sshkey_free(hostkeys->entries[i].key);
1.55      tedu      313:                explicit_bzero(hostkeys->entries + i, sizeof(*hostkeys->entries));
1.49      djm       314:        }
1.51      djm       315:        free(hostkeys->entries);
1.55      tedu      316:        explicit_bzero(hostkeys, sizeof(*hostkeys));
1.51      djm       317:        free(hostkeys);
1.49      djm       318: }
                    319:
                    320: static int
1.59      djm       321: check_key_not_revoked(struct hostkeys *hostkeys, struct sshkey *k)
1.49      djm       322: {
1.59      djm       323:        int is_cert = sshkey_is_cert(k);
1.49      djm       324:        u_int i;
1.7       markus    325:
1.49      djm       326:        for (i = 0; i < hostkeys->num_entries; i++) {
                    327:                if (hostkeys->entries[i].marker != MRK_REVOKE)
1.30      markus    328:                        continue;
1.59      djm       329:                if (sshkey_equal_public(k, hostkeys->entries[i].key))
1.49      djm       330:                        return -1;
                    331:                if (is_cert &&
1.59      djm       332:                    sshkey_equal_public(k->cert->signature_key,
1.49      djm       333:                    hostkeys->entries[i].key))
                    334:                        return -1;
                    335:        }
                    336:        return 0;
                    337: }
                    338:
                    339: /*
                    340:  * Match keys against a specified key, or look one up by key type.
                    341:  *
                    342:  * If looking for a keytype (key == NULL) and one is found then return
                    343:  * HOST_FOUND, otherwise HOST_NEW.
                    344:  *
                    345:  * If looking for a key (key != NULL):
                    346:  *  1. If the key is a cert and a matching CA is found, return HOST_OK
                    347:  *  2. If the key is not a cert and a matching key is found, return HOST_OK
                    348:  *  3. If no key matches but a key with a different type is found, then
                    349:  *     return HOST_CHANGED
                    350:  *  4. If no matching keys are found, then return HOST_NEW.
                    351:  *
                    352:  * Finally, check any found key is not revoked.
                    353:  */
                    354: static HostStatus
                    355: check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
1.59      djm       356:     struct sshkey *k, int keytype, const struct hostkey_entry **found)
1.49      djm       357: {
                    358:        u_int i;
                    359:        HostStatus end_return = HOST_NEW;
1.59      djm       360:        int want_cert = sshkey_is_cert(k);
1.49      djm       361:        HostkeyMarker want_marker = want_cert ? MRK_CA : MRK_NONE;
                    362:        int proto = (k ? k->type : keytype) == KEY_RSA1 ? 1 : 2;
                    363:
                    364:        if (found != NULL)
                    365:                *found = NULL;
1.30      markus    366:
1.49      djm       367:        for (i = 0; i < hostkeys->num_entries; i++) {
                    368:                if (proto == 1 && hostkeys->entries[i].key->type != KEY_RSA1)
                    369:                        continue;
                    370:                if (proto == 2 && hostkeys->entries[i].key->type == KEY_RSA1)
1.30      markus    371:                        continue;
1.49      djm       372:                if (hostkeys->entries[i].marker != want_marker)
                    373:                        continue;
                    374:                if (k == NULL) {
                    375:                        if (hostkeys->entries[i].key->type != keytype)
                    376:                                continue;
                    377:                        end_return = HOST_FOUND;
                    378:                        if (found != NULL)
                    379:                                *found = hostkeys->entries + i;
                    380:                        k = hostkeys->entries[i].key;
                    381:                        break;
                    382:                }
                    383:                if (want_cert) {
1.59      djm       384:                        if (sshkey_equal_public(k->cert->signature_key,
1.49      djm       385:                            hostkeys->entries[i].key)) {
                    386:                                /* A matching CA exists */
                    387:                                end_return = HOST_OK;
                    388:                                if (found != NULL)
                    389:                                        *found = hostkeys->entries + i;
                    390:                                break;
1.48      djm       391:                        }
1.49      djm       392:                } else {
1.59      djm       393:                        if (sshkey_equal(k, hostkeys->entries[i].key)) {
1.49      djm       394:                                end_return = HOST_OK;
                    395:                                if (found != NULL)
                    396:                                        *found = hostkeys->entries + i;
                    397:                                break;
1.48      djm       398:                        }
1.49      djm       399:                        /* A non-maching key exists */
                    400:                        end_return = HOST_CHANGED;
                    401:                        if (found != NULL)
                    402:                                *found = hostkeys->entries + i;
1.48      djm       403:                }
1.1       deraadt   404:        }
1.49      djm       405:        if (check_key_not_revoked(hostkeys, k) != 0) {
                    406:                end_return = HOST_REVOKED;
                    407:                if (found != NULL)
                    408:                        *found = NULL;
                    409:        }
1.7       markus    410:        return end_return;
1.30      markus    411: }
1.58      djm       412:
1.30      markus    413: HostStatus
1.59      djm       414: check_key_in_hostkeys(struct hostkeys *hostkeys, struct sshkey *key,
1.49      djm       415:     const struct hostkey_entry **found)
1.30      markus    416: {
                    417:        if (key == NULL)
                    418:                fatal("no key to look up");
1.49      djm       419:        return check_hostkeys_by_key_or_type(hostkeys, key, 0, found);
1.30      markus    420: }
                    421:
                    422: int
1.49      djm       423: lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype,
                    424:     const struct hostkey_entry **found)
1.30      markus    425: {
1.49      djm       426:        return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype,
                    427:            found) == HOST_FOUND);
1.1       deraadt   428: }
                    429:
1.9       markus    430: /*
                    431:  * Appends an entry to the host file.  Returns false if the entry could not
                    432:  * be appended.
                    433:  */
1.2       provos    434: int
1.59      djm       435: add_host_to_hostfile(const char *filename, const char *host,
                    436:     const struct sshkey *key, int store_hash)
1.1       deraadt   437: {
1.7       markus    438:        FILE *f;
1.59      djm       439:        int r, success = 0;
1.35      dtucker   440:        char *hashed_host = NULL;
1.33      djm       441:
1.14      markus    442:        if (key == NULL)
1.17      markus    443:                return 1;       /* XXX ? */
1.7       markus    444:        f = fopen(filename, "a");
                    445:        if (!f)
                    446:                return 0;
1.33      djm       447:
                    448:        if (store_hash) {
                    449:                if ((hashed_host = host_hash(host, NULL, 0)) == NULL) {
1.61    ! djm       450:                        error("%s: host_hash failed", __func__);
1.33      djm       451:                        fclose(f);
                    452:                        return 0;
                    453:                }
                    454:        }
                    455:        fprintf(f, "%s ", store_hash ? hashed_host : host);
                    456:
1.59      djm       457:        if ((r = sshkey_write(key, f)) != 0) {
                    458:                error("%s: saving key in %s failed: %s",
                    459:                    __func__, filename, ssh_err(r));
                    460:        } else
1.14      markus    461:                success = 1;
1.60      djm       462:        fputc('\n', f);
1.7       markus    463:        fclose(f);
1.14      markus    464:        return success;
1.60      djm       465: }
                    466:
                    467: static int
                    468: match_maybe_hashed(const char *host, const char *names, int *was_hashed)
                    469: {
                    470:        int hashed = *names == HASH_DELIM;
                    471:        const char *hashed_host;
                    472:        size_t nlen = strlen(names);
                    473:
                    474:        if (was_hashed != NULL)
                    475:                *was_hashed = hashed;
                    476:        if (hashed) {
                    477:                if ((hashed_host = host_hash(host, names, nlen)) == NULL)
                    478:                        return -1;
                    479:                return nlen == strlen(hashed_host) &&
                    480:                    strncmp(hashed_host, names, nlen) == 0;
                    481:        }
                    482:        return match_hostname(host, names, nlen) == 1;
                    483: }
                    484:
                    485: int
                    486: hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
                    487:     const char *host, u_int options)
                    488: {
                    489:        FILE *f;
                    490:        char line[8192], oline[8192];
                    491:        u_long linenum = 0;
                    492:        char *cp, *cp2;
                    493:        u_int kbits;
                    494:        int s, r = 0;
                    495:        struct hostkey_foreach_line lineinfo;
                    496:
                    497:        memset(&lineinfo, 0, sizeof(lineinfo));
                    498:        if (host == NULL && (options & HKF_WANT_MATCH_HOST) != 0)
                    499:                return SSH_ERR_INVALID_ARGUMENT;
                    500:        if ((f = fopen(path, "r")) == NULL)
                    501:                return SSH_ERR_SYSTEM_ERROR;
                    502:
                    503:        debug3("%s: reading file \"%s\"", __func__, path);
                    504:        while (read_keyfile_line(f, path, line, sizeof(line), &linenum) == 0) {
                    505:                line[strcspn(line, "\n")] = '\0';
                    506:                strlcpy(oline, line, sizeof(oline));
                    507:
                    508:                sshkey_free(lineinfo.key);
                    509:                memset(&lineinfo, 0, sizeof(lineinfo));
                    510:                lineinfo.path = path;
                    511:                lineinfo.linenum = linenum;
                    512:                lineinfo.line = oline;
                    513:                lineinfo.status = HKF_STATUS_OK;
                    514:
                    515:                /* Skip any leading whitespace, comments and empty lines. */
                    516:                for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
                    517:                        ;
                    518:                if (!*cp || *cp == '#' || *cp == '\n') {
                    519:                        if ((options & HKF_WANT_MATCH_HOST) == 0) {
                    520:                                lineinfo.status = HKF_STATUS_COMMENT;
                    521:                                if ((r = callback(&lineinfo, ctx)) != 0)
                    522:                                        break;
                    523:                        }
                    524:                        continue;
                    525:                }
                    526:
                    527:                if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) {
                    528:                        verbose("%s: invalid marker at %s:%lu",
                    529:                            __func__, path, linenum);
                    530:                        if ((options & HKF_WANT_MATCH_HOST) == 0)
                    531:                                goto bad;
                    532:                        continue;
                    533:                }
                    534:
                    535:                /* Find the end of the host name portion. */
                    536:                for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
                    537:                        ;
                    538:                lineinfo.hosts = cp;
                    539:                *cp2++ = '\0';
                    540:
                    541:                /* Check if the host name matches. */
                    542:                if (host != NULL) {
                    543:                        s = match_maybe_hashed(host, lineinfo.hosts,
                    544:                            &lineinfo.was_hashed);
                    545:                        if (s == 1)
                    546:                                lineinfo.status = HKF_STATUS_HOST_MATCHED;
                    547:                        else if ((options & HKF_WANT_MATCH_HOST) != 0)
                    548:                                continue;
                    549:                        else if (s == -1) {
                    550:                                debug2("%s: %s:%ld: bad host hash \"%.32s\"",
                    551:                                    __func__, path, linenum, lineinfo.hosts);
                    552:                                goto bad;
                    553:                        }
                    554:                }
                    555:
                    556:                /* Got a match.  Skip host name and any following whitespace */
                    557:                for (; *cp2 == ' ' || *cp2 == '\t'; cp2++)
                    558:                        ;
                    559:                if (*cp2 == '\0' || *cp2 == '#') {
                    560:                        debug2("%s:%ld: truncated before key", path, linenum);
                    561:                        goto bad;
                    562:                }
                    563:                lineinfo.rawkey = cp = cp2;
                    564:
                    565:                if ((options & HKF_WANT_PARSE_KEY) != 0) {
                    566:                        /*
                    567:                         * Extract the key from the line.  This will skip
                    568:                         * any leading whitespace.  Ignore badly formatted
                    569:                         * lines.
                    570:                         */
                    571:                        if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) {
                    572:                                error("%s: sshkey_new failed", __func__);
                    573:                                return SSH_ERR_ALLOC_FAIL;
                    574:                        }
                    575:                        if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) {
                    576: #ifdef WITH_SSH1
                    577:                                sshkey_free(lineinfo.key);
                    578:                                lineinfo.key = sshkey_new(KEY_RSA1);
                    579:                                if (lineinfo.key  == NULL) {
                    580:                                        error("%s: sshkey_new fail", __func__);
                    581:                                        return SSH_ERR_ALLOC_FAIL;
                    582:                                }
                    583:                                if (!hostfile_read_key(&cp, &kbits,
                    584:                                    lineinfo.key))
                    585:                                        goto bad;
                    586: #else
                    587:                                goto bad;
                    588: #endif
                    589:                        }
                    590:                        if (!hostfile_check_key(kbits, lineinfo.key, host,
                    591:                            path, linenum)) {
                    592:  bad:
                    593:                                lineinfo.status = HKF_STATUS_INVALID;
                    594:                                if ((r = callback(&lineinfo, ctx)) != 0)
                    595:                                        break;
                    596:                                continue;
                    597:                        }
                    598:                }
                    599:                if ((r = callback(&lineinfo, ctx)) != 0)
                    600:                        break;
                    601:        }
                    602:        sshkey_free(lineinfo.key);
                    603:        fclose(f);
                    604:        return r;
1.1       deraadt   605: }