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

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