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

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