1511b41d2SMark Murray /* 2511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 3511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4511b41d2SMark Murray * All rights reserved 5511b41d2SMark Murray * Functions for manipulating the known hosts files. 6511b41d2SMark Murray * 7c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 8c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 9c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 10c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 11c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 12c2d3a559SKris Kennaway * 13c2d3a559SKris Kennaway * 14c2d3a559SKris Kennaway * Copyright (c) 1999,2000 Markus Friedl. All rights reserved. 15c2d3a559SKris Kennaway * Copyright (c) 1999 Niels Provos. All rights reserved. 16c2d3a559SKris Kennaway * 17c2d3a559SKris Kennaway * Redistribution and use in source and binary forms, with or without 18c2d3a559SKris Kennaway * modification, are permitted provided that the following conditions 19c2d3a559SKris Kennaway * are met: 20c2d3a559SKris Kennaway * 1. Redistributions of source code must retain the above copyright 21c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer. 22c2d3a559SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 23c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer in the 24c2d3a559SKris Kennaway * documentation and/or other materials provided with the distribution. 25c2d3a559SKris Kennaway * 26c2d3a559SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27c2d3a559SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28c2d3a559SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29c2d3a559SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30c2d3a559SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31c2d3a559SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32c2d3a559SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33c2d3a559SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34c2d3a559SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35c2d3a559SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36511b41d2SMark Murray */ 37511b41d2SMark Murray 38511b41d2SMark Murray #include "includes.h" 39ca3176e7SBrian Feldman RCSID("$OpenBSD: hostfile.c,v 1.26 2001/04/12 19:15:24 markus Exp $"); 40c2d3a559SKris Kennaway RCSID("$FreeBSD$"); 41511b41d2SMark Murray 42511b41d2SMark Murray #include "packet.h" 43a8f6863aSKris Kennaway #include "match.h" 44a8f6863aSKris Kennaway #include "key.h" 45a8f6863aSKris Kennaway #include "hostfile.h" 46ca3176e7SBrian Feldman #include "log.h" 47511b41d2SMark Murray 48511b41d2SMark Murray /* 49a8f6863aSKris Kennaway * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the 50a8f6863aSKris Kennaway * pointer over the key. Skips any whitespace at the beginning and at end. 51511b41d2SMark Murray */ 52511b41d2SMark Murray 53511b41d2SMark Murray int 54ca3176e7SBrian Feldman hostfile_read_key(char **cpp, u_int *bitsp, Key *ret) 55511b41d2SMark Murray { 56511b41d2SMark Murray char *cp; 57511b41d2SMark Murray 58511b41d2SMark Murray /* Skip leading whitespace. */ 59511b41d2SMark Murray for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) 60511b41d2SMark Murray ; 61511b41d2SMark Murray 62ca3176e7SBrian Feldman if (key_read(ret, &cp) != 1) 63511b41d2SMark Murray return 0; 64511b41d2SMark Murray 65511b41d2SMark Murray /* Skip trailing whitespace. */ 66511b41d2SMark Murray for (; *cp == ' ' || *cp == '\t'; cp++) 67511b41d2SMark Murray ; 68511b41d2SMark Murray 69511b41d2SMark Murray /* Return results. */ 70511b41d2SMark Murray *cpp = cp; 71ca3176e7SBrian Feldman *bitsp = key_size(ret); 72511b41d2SMark Murray return 1; 73511b41d2SMark Murray } 74511b41d2SMark Murray 75a8f6863aSKris Kennaway int 76ca3176e7SBrian Feldman auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n) 77a8f6863aSKris Kennaway { 78ca3176e7SBrian Feldman Key *k = key_new(KEY_RSA1); 79a8f6863aSKris Kennaway int ret = hostfile_read_key(cpp, bitsp, k); 80a8f6863aSKris Kennaway BN_copy(e, k->rsa->e); 81a8f6863aSKris Kennaway BN_copy(n, k->rsa->n); 82a8f6863aSKris Kennaway key_free(k); 83a8f6863aSKris Kennaway return ret; 84a8f6863aSKris Kennaway } 85511b41d2SMark Murray 86511b41d2SMark Murray int 87a8f6863aSKris Kennaway hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum) 88511b41d2SMark Murray { 89ca3176e7SBrian Feldman if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) 90a8f6863aSKris Kennaway return 1; 91a8f6863aSKris Kennaway if (bits != BN_num_bits(key->rsa->n)) { 92e8aafc91SKris Kennaway log("Warning: %s, line %d: keysize mismatch for host %s: " 93a8f6863aSKris Kennaway "actual %d vs. announced %d.", 94a8f6863aSKris Kennaway filename, linenum, host, BN_num_bits(key->rsa->n), bits); 95e8aafc91SKris Kennaway log("Warning: replace %d with %d in %s, line %d.", 96a8f6863aSKris Kennaway bits, BN_num_bits(key->rsa->n), filename, linenum); 97511b41d2SMark Murray } 98a8f6863aSKris Kennaway return 1; 99511b41d2SMark Murray } 100511b41d2SMark Murray 101511b41d2SMark Murray /* 102511b41d2SMark Murray * Checks whether the given host (which must be in all lowercase) is already 103511b41d2SMark Murray * in the list of our known hosts. Returns HOST_OK if the host is known and 104511b41d2SMark Murray * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED 105511b41d2SMark Murray * if the host is known but used to have a different host key. 106511b41d2SMark Murray */ 107511b41d2SMark Murray 108511b41d2SMark Murray HostStatus 109ca3176e7SBrian Feldman check_host_in_hostfile(const char *filename, const char *host, Key *key, 110ca3176e7SBrian Feldman Key *found, int *numret) 111511b41d2SMark Murray { 112511b41d2SMark Murray FILE *f; 113511b41d2SMark Murray char line[8192]; 114511b41d2SMark Murray int linenum = 0; 115ca3176e7SBrian Feldman u_int kbits; 116511b41d2SMark Murray char *cp, *cp2; 117511b41d2SMark Murray HostStatus end_return; 118511b41d2SMark Murray 119ca3176e7SBrian Feldman debug3("check_host_in_hostfile: filename %s", filename); 120a8f6863aSKris Kennaway if (key == NULL) 121a8f6863aSKris Kennaway fatal("no key to look up"); 122511b41d2SMark Murray /* Open the file containing the list of known hosts. */ 123511b41d2SMark Murray f = fopen(filename, "r"); 124511b41d2SMark Murray if (!f) 125511b41d2SMark Murray return HOST_NEW; 126511b41d2SMark Murray 127511b41d2SMark Murray /* 128511b41d2SMark Murray * Return value when the loop terminates. This is set to 129511b41d2SMark Murray * HOST_CHANGED if we have seen a different key for the host and have 130511b41d2SMark Murray * not found the proper one. 131511b41d2SMark Murray */ 132511b41d2SMark Murray end_return = HOST_NEW; 133511b41d2SMark Murray 134ca3176e7SBrian Feldman /* Go through the file. */ 135511b41d2SMark Murray while (fgets(line, sizeof(line), f)) { 136511b41d2SMark Murray cp = line; 137511b41d2SMark Murray linenum++; 138511b41d2SMark Murray 139511b41d2SMark Murray /* Skip any leading whitespace, comments and empty lines. */ 140511b41d2SMark Murray for (; *cp == ' ' || *cp == '\t'; cp++) 141511b41d2SMark Murray ; 142511b41d2SMark Murray if (!*cp || *cp == '#' || *cp == '\n') 143511b41d2SMark Murray continue; 144511b41d2SMark Murray 145511b41d2SMark Murray /* Find the end of the host name portion. */ 146511b41d2SMark Murray for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) 147511b41d2SMark Murray ; 148511b41d2SMark Murray 149511b41d2SMark Murray /* Check if the host name matches. */ 150ca3176e7SBrian Feldman if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1) 151511b41d2SMark Murray continue; 152511b41d2SMark Murray 153511b41d2SMark Murray /* Got a match. Skip host name. */ 154511b41d2SMark Murray cp = cp2; 155511b41d2SMark Murray 156511b41d2SMark Murray /* 157511b41d2SMark Murray * Extract the key from the line. This will skip any leading 158511b41d2SMark Murray * whitespace. Ignore badly formatted lines. 159511b41d2SMark Murray */ 160a8f6863aSKris Kennaway if (!hostfile_read_key(&cp, &kbits, found)) 161a8f6863aSKris Kennaway continue; 162a8f6863aSKris Kennaway if (!hostfile_check_key(kbits, found, host, filename, linenum)) 163511b41d2SMark Murray continue; 164511b41d2SMark Murray 165ca3176e7SBrian Feldman if (numret != NULL) 166ca3176e7SBrian Feldman *numret = linenum; 167ca3176e7SBrian Feldman 168511b41d2SMark Murray /* Check if the current key is the same as the given key. */ 169a8f6863aSKris Kennaway if (key_equal(key, found)) { 170511b41d2SMark Murray /* Ok, they match. */ 171ca3176e7SBrian Feldman debug3("check_host_in_hostfile: match line %d", linenum); 172511b41d2SMark Murray fclose(f); 173511b41d2SMark Murray return HOST_OK; 174511b41d2SMark Murray } 175511b41d2SMark Murray /* 176511b41d2SMark Murray * They do not match. We will continue to go through the 177511b41d2SMark Murray * file; however, we note that we will not return that it is 178511b41d2SMark Murray * new. 179511b41d2SMark Murray */ 180511b41d2SMark Murray end_return = HOST_CHANGED; 181511b41d2SMark Murray } 182511b41d2SMark Murray /* Clear variables and close the file. */ 183511b41d2SMark Murray fclose(f); 184511b41d2SMark Murray 185511b41d2SMark Murray /* 186511b41d2SMark Murray * Return either HOST_NEW or HOST_CHANGED, depending on whether we 187511b41d2SMark Murray * saw a different key for the host. 188511b41d2SMark Murray */ 189511b41d2SMark Murray return end_return; 190511b41d2SMark Murray } 191511b41d2SMark Murray 192511b41d2SMark Murray /* 193511b41d2SMark Murray * Appends an entry to the host file. Returns false if the entry could not 194511b41d2SMark Murray * be appended. 195511b41d2SMark Murray */ 196511b41d2SMark Murray 197511b41d2SMark Murray int 198a8f6863aSKris Kennaway add_host_to_hostfile(const char *filename, const char *host, Key *key) 199511b41d2SMark Murray { 200511b41d2SMark Murray FILE *f; 201a8f6863aSKris Kennaway int success = 0; 202a8f6863aSKris Kennaway if (key == NULL) 203e8aafc91SKris Kennaway return 1; /* XXX ? */ 204511b41d2SMark Murray f = fopen(filename, "a"); 205511b41d2SMark Murray if (!f) 206511b41d2SMark Murray return 0; 207a8f6863aSKris Kennaway fprintf(f, "%s ", host); 208a8f6863aSKris Kennaway if (key_write(key, f)) { 209a8f6863aSKris Kennaway success = 1; 210a8f6863aSKris Kennaway } else { 211e8aafc91SKris Kennaway error("add_host_to_hostfile: saving key in %s failed", filename); 212511b41d2SMark Murray } 213e8aafc91SKris Kennaway fprintf(f, "\n"); 214511b41d2SMark Murray fclose(f); 215a8f6863aSKris Kennaway return success; 216511b41d2SMark Murray } 217