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

1.1       deraadt     1: /*
1.8       deraadt     2:  *
                      3:  * hostfile.c
                      4:  *
                      5:  * Author: Tatu Ylonen <ylo@cs.hut.fi>
                      6:  *
                      7:  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
                      8:  *                    All rights reserved
                      9:  *
                     10:  * Created: Thu Jun 29 07:10:56 1995 ylo
                     11:  *
                     12:  * Functions for manipulating the known hosts files.
                     13:  *
                     14:  */
1.1       deraadt    15:
                     16: #include "includes.h"
1.10      markus     17: RCSID("$OpenBSD: hostfile.c,v 1.9 1999/11/24 19:53:47 markus Exp $");
1.1       deraadt    18:
                     19: #include "packet.h"
                     20: #include "ssh.h"
                     21:
1.9       markus     22: /*
                     23:  * Reads a multiple-precision integer in hex from the buffer, and advances
                     24:  * the pointer.  The integer must already be initialized.  This function is
                     25:  * permitted to modify the buffer.  This leaves *cpp to point just beyond the
                     26:  * last processed (and maybe modified) character.  Note that this may modify
                     27:  * the buffer containing the number.
                     28:  */
1.1       deraadt    29:
1.2       provos     30: int
1.7       markus     31: auth_rsa_read_bignum(char **cpp, BIGNUM * value)
1.1       deraadt    32: {
1.7       markus     33:        char *cp = *cpp;
                     34:        int len, old;
1.1       deraadt    35:
1.7       markus     36:        /* Skip any leading whitespace. */
1.9       markus     37:        for (; *cp == ' ' || *cp == '\t'; cp++)
                     38:                ;
1.7       markus     39:
                     40:        /* Check that it begins with a hex digit. */
                     41:        if (*cp < '0' || *cp > '9')
                     42:                return 0;
                     43:
                     44:        /* Save starting position. */
                     45:        *cpp = cp;
                     46:
                     47:        /* Move forward until all hex digits skipped. */
1.9       markus     48:        for (; *cp >= '0' && *cp <= '9'; cp++)
                     49:                ;
1.7       markus     50:
                     51:        /* Compute the length of the hex number. */
                     52:        len = cp - *cpp;
                     53:
                     54:        /* Save the old terminating character, and replace it by \0. */
                     55:        old = *cp;
                     56:        *cp = 0;
                     57:
                     58:        /* Parse the number. */
                     59:        if (BN_dec2bn(&value, *cpp) == 0)
                     60:                return 0;
                     61:
                     62:        /* Restore old terminating character. */
                     63:        *cp = old;
                     64:
                     65:        /* Move beyond the number and return success. */
                     66:        *cpp = cp;
                     67:        return 1;
1.1       deraadt    68: }
                     69:
1.9       markus     70: /*
                     71:  * Parses an RSA key (number of bits, e, n) from a string.  Moves the pointer
                     72:  * over the key.  Skips any whitespace at the beginning and at end.
                     73:  */
1.1       deraadt    74:
1.2       provos     75: int
1.7       markus     76: auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
1.1       deraadt    77: {
1.7       markus     78:        unsigned int bits;
                     79:        char *cp;
                     80:
                     81:        /* Skip leading whitespace. */
1.9       markus     82:        for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
                     83:                ;
1.1       deraadt    84:
1.7       markus     85:        /* Get number of bits. */
                     86:        if (*cp < '0' || *cp > '9')
                     87:                return 0;       /* Bad bit count... */
                     88:        for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
                     89:                bits = 10 * bits + *cp - '0';
                     90:
                     91:        /* Get public exponent. */
                     92:        if (!auth_rsa_read_bignum(&cp, e))
                     93:                return 0;
                     94:
                     95:        /* Get public modulus. */
                     96:        if (!auth_rsa_read_bignum(&cp, n))
                     97:                return 0;
                     98:
                     99:        /* Skip trailing whitespace. */
1.9       markus    100:        for (; *cp == ' ' || *cp == '\t'; cp++)
                    101:                ;
1.7       markus    102:
                    103:        /* Return results. */
                    104:        *cpp = cp;
                    105:        *bitsp = bits;
                    106:        return 1;
1.1       deraadt   107: }
                    108:
1.9       markus    109: /*
                    110:  * Tries to match the host name (which must be in all lowercase) against the
                    111:  * comma-separated sequence of subpatterns (each possibly preceded by ! to
                    112:  * indicate negation).  Returns true if there is a positive match; zero
                    113:  * otherwise.
                    114:  */
1.1       deraadt   115:
1.2       provos    116: int
                    117: match_hostname(const char *host, const char *pattern, unsigned int len)
1.1       deraadt   118: {
1.7       markus    119:        char sub[1024];
                    120:        int negated;
                    121:        int got_positive;
                    122:        unsigned int i, subi;
                    123:
                    124:        got_positive = 0;
                    125:        for (i = 0; i < len;) {
                    126:                /* Check if the subpattern is negated. */
                    127:                if (pattern[i] == '!') {
                    128:                        negated = 1;
                    129:                        i++;
                    130:                } else
                    131:                        negated = 0;
                    132:
1.9       markus    133:                /*
                    134:                 * Extract the subpattern up to a comma or end.  Convert the
                    135:                 * subpattern to lowercase.
                    136:                 */
1.7       markus    137:                for (subi = 0;
1.9       markus    138:                     i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
1.7       markus    139:                     subi++, i++)
                    140:                        sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
                    141:                /* If subpattern too long, return failure (no match). */
                    142:                if (subi >= sizeof(sub) - 1)
                    143:                        return 0;
                    144:
1.9       markus    145:                /* If the subpattern was terminated by a comma, skip the comma. */
1.7       markus    146:                if (i < len && pattern[i] == ',')
                    147:                        i++;
                    148:
                    149:                /* Null-terminate the subpattern. */
                    150:                sub[subi] = '\0';
                    151:
                    152:                /* Try to match the subpattern against the host name. */
                    153:                if (match_pattern(host, sub)) {
                    154:                        if (negated)
1.9       markus    155:                                return 0;       /* Fail */
1.7       markus    156:                        else
                    157:                                got_positive = 1;
                    158:                }
1.1       deraadt   159:        }
1.7       markus    160:
1.9       markus    161:        /*
                    162:         * Return success if got a positive match.  If there was a negative
                    163:         * match, we have already returned zero and never get here.
                    164:         */
1.7       markus    165:        return got_positive;
1.1       deraadt   166: }
                    167:
1.9       markus    168: /*
                    169:  * Checks whether the given host (which must be in all lowercase) is already
                    170:  * in the list of our known hosts. Returns HOST_OK if the host is known and
                    171:  * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED
                    172:  * if the host is known but used to have a different host key.
                    173:  */
1.1       deraadt   174:
1.2       provos    175: HostStatus
1.5       markus    176: check_host_in_hostfile(const char *filename, const char *host,
1.7       markus    177:                       BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn)
1.1       deraadt   178: {
1.7       markus    179:        FILE *f;
                    180:        char line[8192];
                    181:        int linenum = 0;
                    182:        unsigned int bits, kbits, hostlen;
                    183:        char *cp, *cp2;
                    184:        HostStatus end_return;
                    185:
                    186:        /* Open the file containing the list of known hosts. */
                    187:        f = fopen(filename, "r");
                    188:        if (!f)
                    189:                return HOST_NEW;
                    190:
                    191:        /* Cache the length of the host name. */
                    192:        hostlen = strlen(host);
                    193:
1.9       markus    194:        /*
                    195:         * Return value when the loop terminates.  This is set to
                    196:         * HOST_CHANGED if we have seen a different key for the host and have
                    197:         * not found the proper one.
                    198:         */
1.7       markus    199:        end_return = HOST_NEW;
                    200:
                    201:        /* size of modulus 'n' */
                    202:        bits = BN_num_bits(n);
                    203:
                    204:        /* Go trough the file. */
                    205:        while (fgets(line, sizeof(line), f)) {
                    206:                cp = line;
                    207:                linenum++;
                    208:
1.9       markus    209:                /* Skip any leading whitespace, comments and empty lines. */
                    210:                for (; *cp == ' ' || *cp == '\t'; cp++)
                    211:                        ;
1.7       markus    212:                if (!*cp || *cp == '#' || *cp == '\n')
                    213:                        continue;
                    214:
                    215:                /* Find the end of the host name portion. */
1.9       markus    216:                for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
                    217:                        ;
1.7       markus    218:
                    219:                /* Check if the host name matches. */
                    220:                if (!match_hostname(host, cp, (unsigned int) (cp2 - cp)))
                    221:                        continue;
                    222:
                    223:                /* Got a match.  Skip host name. */
                    224:                cp = cp2;
                    225:
1.9       markus    226:                /*
                    227:                 * Extract the key from the line.  This will skip any leading
                    228:                 * whitespace.  Ignore badly formatted lines.
                    229:                 */
1.7       markus    230:                if (!auth_rsa_read_key(&cp, &kbits, ke, kn))
                    231:                        continue;
                    232:
                    233:                if (kbits != BN_num_bits(kn)) {
1.10      markus    234:                        error("Warning: %s, line %d: keysize mismatch for host %s: "
                    235:                              "actual %d vs. announced %d.",
                    236:                              filename, linenum, host, BN_num_bits(kn), kbits);
1.7       markus    237:                        error("Warning: replace %d with %d in %s, line %d.",
                    238:                              kbits, BN_num_bits(kn), filename, linenum);
                    239:                }
                    240:                /* Check if the current key is the same as the given key. */
                    241:                if (BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0) {
                    242:                        /* Ok, they match. */
                    243:                        fclose(f);
                    244:                        return HOST_OK;
                    245:                }
1.9       markus    246:                /*
                    247:                 * They do not match.  We will continue to go through the
                    248:                 * file; however, we note that we will not return that it is
                    249:                 * new.
                    250:                 */
1.7       markus    251:                end_return = HOST_CHANGED;
1.1       deraadt   252:        }
1.7       markus    253:        /* Clear variables and close the file. */
                    254:        fclose(f);
                    255:
1.9       markus    256:        /*
                    257:         * Return either HOST_NEW or HOST_CHANGED, depending on whether we
                    258:         * saw a different key for the host.
                    259:         */
1.7       markus    260:        return end_return;
1.1       deraadt   261: }
                    262:
1.9       markus    263: /*
                    264:  * Appends an entry to the host file.  Returns false if the entry could not
                    265:  * be appended.
                    266:  */
1.1       deraadt   267:
1.2       provos    268: int
                    269: add_host_to_hostfile(const char *filename, const char *host,
1.7       markus    270:                     BIGNUM * e, BIGNUM * n)
1.1       deraadt   271: {
1.7       markus    272:        FILE *f;
                    273:        char *buf;
                    274:        unsigned int bits;
                    275:
                    276:        /* Open the file for appending. */
                    277:        f = fopen(filename, "a");
                    278:        if (!f)
                    279:                return 0;
                    280:
                    281:        /* size of modulus 'n' */
                    282:        bits = BN_num_bits(n);
                    283:
                    284:        /* Print the host name and key to the file. */
                    285:        fprintf(f, "%s %u ", host, bits);
                    286:        buf = BN_bn2dec(e);
                    287:        if (buf == NULL) {
                    288:                error("add_host_to_hostfile: BN_bn2dec(e) failed");
                    289:                fclose(f);
                    290:                return 0;
                    291:        }
                    292:        fprintf(f, "%s ", buf);
                    293:        free(buf);
                    294:        buf = BN_bn2dec(n);
                    295:        if (buf == NULL) {
                    296:                error("add_host_to_hostfile: BN_bn2dec(n) failed");
                    297:                fclose(f);
                    298:                return 0;
                    299:        }
                    300:        fprintf(f, "%s\n", buf);
                    301:        free(buf);
                    302:
                    303:        /* Close the file. */
                    304:        fclose(f);
                    305:        return 1;
1.1       deraadt   306: }