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 * $FreeBSD$ 15 */ 16 17 #include "includes.h" 18 RCSID("$OpenBSD: hostfile.c,v 1.14 2000/03/23 22:15:33 markus Exp $"); 19 20 #include "packet.h" 21 #include "match.h" 22 #include "ssh.h" 23 #include <openssl/rsa.h> 24 #include <openssl/dsa.h> 25 #include "key.h" 26 #include "hostfile.h" 27 28 /* 29 * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the 30 * pointer over the key. Skips any whitespace at the beginning and at end. 31 */ 32 33 int 34 hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret) 35 { 36 unsigned int bits; 37 char *cp; 38 39 /* Skip leading whitespace. */ 40 for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) 41 ; 42 43 /* Get number of bits. */ 44 if (*cp < '0' || *cp > '9') 45 return 0; /* Bad bit count... */ 46 for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) 47 bits = 10 * bits + *cp - '0'; 48 49 if (!key_read(ret, bits, &cp)) 50 return 0; 51 52 /* Skip trailing whitespace. */ 53 for (; *cp == ' ' || *cp == '\t'; cp++) 54 ; 55 56 /* Return results. */ 57 *cpp = cp; 58 *bitsp = bits; 59 return 1; 60 } 61 62 int 63 auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) 64 { 65 Key *k = key_new(KEY_RSA); 66 int ret = hostfile_read_key(cpp, bitsp, k); 67 BN_copy(e, k->rsa->e); 68 BN_copy(n, k->rsa->n); 69 key_free(k); 70 return ret; 71 } 72 73 int 74 hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum) 75 { 76 if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) 77 return 1; 78 if (bits != BN_num_bits(key->rsa->n)) { 79 error("Warning: %s, line %d: keysize mismatch for host %s: " 80 "actual %d vs. announced %d.", 81 filename, linenum, host, BN_num_bits(key->rsa->n), bits); 82 error("Warning: replace %d with %d in %s, line %d.", 83 bits, BN_num_bits(key->rsa->n), filename, linenum); 84 } 85 return 1; 86 } 87 88 /* 89 * Checks whether the given host (which must be in all lowercase) is already 90 * in the list of our known hosts. Returns HOST_OK if the host is known and 91 * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED 92 * if the host is known but used to have a different host key. 93 */ 94 95 HostStatus 96 check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found) 97 { 98 FILE *f; 99 char line[8192]; 100 int linenum = 0; 101 unsigned int kbits, hostlen; 102 char *cp, *cp2; 103 HostStatus end_return; 104 105 if (key == NULL) 106 fatal("no key to look up"); 107 /* Open the file containing the list of known hosts. */ 108 f = fopen(filename, "r"); 109 if (!f) 110 return HOST_NEW; 111 112 /* Cache the length of the host name. */ 113 hostlen = strlen(host); 114 115 /* 116 * Return value when the loop terminates. This is set to 117 * HOST_CHANGED if we have seen a different key for the host and have 118 * not found the proper one. 119 */ 120 end_return = HOST_NEW; 121 122 /* Go trough the file. */ 123 while (fgets(line, sizeof(line), f)) { 124 cp = line; 125 linenum++; 126 127 /* Skip any leading whitespace, comments and empty lines. */ 128 for (; *cp == ' ' || *cp == '\t'; cp++) 129 ; 130 if (!*cp || *cp == '#' || *cp == '\n') 131 continue; 132 133 /* Find the end of the host name portion. */ 134 for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) 135 ; 136 137 /* Check if the host name matches. */ 138 if (!match_hostname(host, cp, (unsigned int) (cp2 - cp))) 139 continue; 140 141 /* Got a match. Skip host name. */ 142 cp = cp2; 143 144 /* 145 * Extract the key from the line. This will skip any leading 146 * whitespace. Ignore badly formatted lines. 147 */ 148 if (!hostfile_read_key(&cp, &kbits, found)) 149 continue; 150 if (!hostfile_check_key(kbits, found, host, filename, linenum)) 151 continue; 152 153 /* Check if the current key is the same as the given key. */ 154 if (key_equal(key, found)) { 155 /* Ok, they match. */ 156 fclose(f); 157 return HOST_OK; 158 } 159 /* 160 * They do not match. We will continue to go through the 161 * file; however, we note that we will not return that it is 162 * new. 163 */ 164 end_return = HOST_CHANGED; 165 } 166 /* Clear variables and close the file. */ 167 fclose(f); 168 169 /* 170 * Return either HOST_NEW or HOST_CHANGED, depending on whether we 171 * saw a different key for the host. 172 */ 173 return end_return; 174 } 175 176 /* 177 * Appends an entry to the host file. Returns false if the entry could not 178 * be appended. 179 */ 180 181 int 182 add_host_to_hostfile(const char *filename, const char *host, Key *key) 183 { 184 FILE *f; 185 int success = 0; 186 187 if (key == NULL) 188 return 1; 189 190 /* Open the file for appending. */ 191 f = fopen(filename, "a"); 192 if (!f) 193 return 0; 194 195 fprintf(f, "%s ", host); 196 if (key_write(key, f)) { 197 fprintf(f, "\n"); 198 success = 1; 199 } else { 200 error("add_host_to_hostfile: saving key failed"); 201 } 202 203 /* Close the file. */ 204 fclose(f); 205 return success; 206 } 207