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

1.1     ! deraadt     1: /*
        !             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: */
        !            15:
        !            16: #include "includes.h"
        !            17: RCSID("$Id: hostfile.c,v 1.2 1999/05/04 11:58:44 bg Exp $");
        !            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:
        !            28: int auth_rsa_read_mp_int(char **cpp, MP_INT *value)
        !            29: {
        !            30:   char *cp = *cpp;
        !            31:   int len, old;
        !            32:
        !            33:   /* Skip any leading whitespace. */
        !            34:   for (; *cp == ' ' || *cp == '\t'; cp++)
        !            35:     ;
        !            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:
        !            48:   /* Compute the length of the hex number. */
        !            49:   len = cp - *cpp;
        !            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 (mpz_set_str(value, *cpp, 10) != 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;
        !            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:
        !            70: int auth_rsa_read_key(char **cpp, unsigned int *bitsp, MP_INT *e, MP_INT *n)
        !            71: {
        !            72:   unsigned int bits;
        !            73:   char *cp;
        !            74:
        !            75:   /* Skip leading whitespace. */
        !            76:   for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
        !            77:     ;
        !            78:
        !            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_mp_int(&cp, e))
        !            87:     return 0;
        !            88:
        !            89:   /* Get public modulus. */
        !            90:   if (!auth_rsa_read_mp_int(&cp, n))
        !            91:     return 0;
        !            92:
        !            93:   /* Skip trailing whitespace. */
        !            94:   for (; *cp == ' ' || *cp == '\t'; cp++)
        !            95:     ;
        !            96:
        !            97:   /* Return results. */
        !            98:   *cpp = cp;
        !            99:   *bitsp = bits;
        !           100:   return 1;
        !           101: }
        !           102:
        !           103: /* Tries to match the host name (which must be in all lowercase) against the
        !           104:    comma-separated sequence of subpatterns (each possibly preceded by ! to
        !           105:    indicate negation).  Returns true if there is a positive match; zero
        !           106:    otherwise. */
        !           107:
        !           108: int match_hostname(const char *host, const char *pattern, unsigned int len)
        !           109: {
        !           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:     {
        !           118:       /* Check if the subpattern is negated. */
        !           119:       if (pattern[i] == '!')
        !           120:        {
        !           121:          negated = 1;
        !           122:          i++;
        !           123:        }
        !           124:       else
        !           125:        negated = 0;
        !           126:
        !           127:       /* Extract the subpattern up to a comma or end.  Convert the subpattern
        !           128:          to lowercase. */
        !           129:       for (subi = 0;
        !           130:           i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
        !           131:           subi++, i++)
        !           132:        sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
        !           133:       /* If subpattern too long, return failure (no match). */
        !           134:       if (subi >= sizeof(sub) - 1)
        !           135:        return 0;
        !           136:
        !           137:       /* If the subpattern was terminated by a comma, skip the comma. */
        !           138:       if (i < len && pattern[i] == ',')
        !           139:        i++;
        !           140:
        !           141:       /* Null-terminate the subpattern. */
        !           142:       sub[subi] = '\0';
        !           143:
        !           144:       /* Try to match the subpattern against the host name. */
        !           145:       if (match_pattern(host, sub))
        !           146:        if (negated)
        !           147:          return 0;  /* Fail if host matches any negated subpattern. */
        !           148:         else
        !           149:          got_positive = 1;
        !           150:     }
        !           151:
        !           152:   /* Return success if got a positive match.  If there was a negative match,
        !           153:      we have already returned zero and never get here. */
        !           154:   return got_positive;
        !           155: }
        !           156:
        !           157: /* Checks whether the given host (which must be in all lowercase) is
        !           158:    already in the list of our known hosts.
        !           159:    Returns HOST_OK if the host is known and has the specified key,
        !           160:    HOST_NEW if the host is not known, and HOST_CHANGED if the host is known
        !           161:    but used to have a different host key. */
        !           162:
        !           163: HostStatus check_host_in_hostfile(const char *filename,
        !           164:                                  const char *host, unsigned int bits,
        !           165:                                  MP_INT *e, MP_INT *n)
        !           166: {
        !           167:   FILE *f;
        !           168:   char line[8192];
        !           169:   MP_INT ke, kn;
        !           170:   unsigned int kbits, hostlen;
        !           171:   char *cp, *cp2;
        !           172:   HostStatus end_return;
        !           173:   struct stat st;
        !           174:
        !           175:   /* Open the file containing the list of known hosts. */
        !           176:   f = fopen(filename, "r");
        !           177:   if (!f)
        !           178:     {
        !           179:       if (stat(filename, &st) >= 0)
        !           180:        {
        !           181:          packet_send_debug("Could not open %.900s for reading.", filename);
        !           182:          packet_send_debug("If your home directory is on an NFS volume, it may need to be world-readable.");
        !           183:        }
        !           184:       return HOST_NEW;
        !           185:     }
        !           186:
        !           187:   /* Initialize mp-int variables. */
        !           188:   mpz_init(&ke);
        !           189:   mpz_init(&kn);
        !           190:
        !           191:   /* Cache the length of the host name. */
        !           192:   hostlen = strlen(host);
        !           193:
        !           194:   /* Return value when the loop terminates.  This is set to HOST_CHANGED if
        !           195:      we have seen a different key for the host and have not found the proper
        !           196:      one. */
        !           197:   end_return = HOST_NEW;
        !           198:
        !           199:   /* Go trough the file. */
        !           200:   while (fgets(line, sizeof(line), f))
        !           201:     {
        !           202:       cp = line;
        !           203:
        !           204:       /* Skip any leading whitespace. */
        !           205:       for (; *cp == ' ' || *cp == '\t'; cp++)
        !           206:        ;
        !           207:
        !           208:       /* Ignore comment lines and empty lines. */
        !           209:       if (!*cp || *cp == '#' || *cp == '\n')
        !           210:        continue;
        !           211:
        !           212:       /* Find the end of the host name portion. */
        !           213:       for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
        !           214:        ;
        !           215:
        !           216:       /* Check if the host name matches. */
        !           217:       if (!match_hostname(host, cp, (unsigned int)(cp2 - cp)))
        !           218:        continue;
        !           219:
        !           220:       /* Got a match.  Skip host name. */
        !           221:       cp = cp2;
        !           222:
        !           223:       /* Extract the key from the line.  This will skip any leading
        !           224:         whitespace.  Ignore badly formatted lines. */
        !           225:       if (!auth_rsa_read_key(&cp, &kbits, &ke, &kn))
        !           226:        continue;
        !           227:
        !           228:       /* Check if the current key is the same as the previous one. */
        !           229:       if (kbits == bits && mpz_cmp(&ke, e) == 0 && mpz_cmp(&kn, n) == 0)
        !           230:        {
        !           231:          /* Ok, they match. */
        !           232:          mpz_clear(&ke);
        !           233:          mpz_clear(&kn);
        !           234:          fclose(f);
        !           235:          return HOST_OK;
        !           236:        }
        !           237:
        !           238:       /* They do not match.  We will continue to go through the file; however,
        !           239:         we note that we will not return that it is new. */
        !           240:       end_return = HOST_CHANGED;
        !           241:     }
        !           242:   /* Clear variables and close the file. */
        !           243:   mpz_clear(&ke);
        !           244:   mpz_clear(&kn);
        !           245:   fclose(f);
        !           246:
        !           247:   /* Return either HOST_NEW or HOST_CHANGED, depending on whether we saw a
        !           248:      different key for the host. */
        !           249:   return end_return;
        !           250: }
        !           251:
        !           252: /* Appends an entry to the host file.  Returns false if the entry
        !           253:    could not be appended. */
        !           254:
        !           255: int add_host_to_hostfile(const char *filename, const char *host,
        !           256:                         unsigned int bits, MP_INT *e, MP_INT *n)
        !           257: {
        !           258:   FILE *f;
        !           259:
        !           260:   /* Open the file for appending. */
        !           261:   f = fopen(filename, "a");
        !           262:   if (!f)
        !           263:     return 0;
        !           264:
        !           265:   /* Print the host name and key to the file. */
        !           266:   fprintf(f, "%s %u ", host, bits);
        !           267:   mpz_out_str(f, 10, e);
        !           268:   fprintf(f, " ");
        !           269:   mpz_out_str(f, 10, n);
        !           270:   fprintf(f, "\n");
        !           271:
        !           272:   /* Close the file. */
        !           273:   fclose(f);
        !           274:   return 1;
        !           275: }