hostfile.c revision 76262
157429Smarkm/* 257429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 357429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 457429Smarkm * All rights reserved 565674Skris * Functions for manipulating the known hosts files. 660576Skris * 765674Skris * As far as I am concerned, the code I have written for this software 865674Skris * can be used freely for any purpose. Any derived versions of this 965674Skris * software must be clearly marked as such, and if the derived work is 1065674Skris * incompatible with the protocol description in the RFC file, it must be 1165674Skris * called by a name other than "ssh" or "Secure Shell". 1260576Skris * 1360576Skris * 1465674Skris * Copyright (c) 1999,2000 Markus Friedl. All rights reserved. 1565674Skris * Copyright (c) 1999 Niels Provos. All rights reserved. 1665674Skris * 1765674Skris * Redistribution and use in source and binary forms, with or without 1865674Skris * modification, are permitted provided that the following conditions 1965674Skris * are met: 2065674Skris * 1. Redistributions of source code must retain the above copyright 2165674Skris * notice, this list of conditions and the following disclaimer. 2265674Skris * 2. Redistributions in binary form must reproduce the above copyright 2365674Skris * notice, this list of conditions and the following disclaimer in the 2465674Skris * documentation and/or other materials provided with the distribution. 2565674Skris * 2665674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2765674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2865674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2965674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3065674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3165674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3265674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3365674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3465674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3565674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3657429Smarkm */ 3757429Smarkm 3857429Smarkm#include "includes.h" 3976262SgreenRCSID("$OpenBSD: hostfile.c,v 1.26 2001/04/12 19:15:24 markus Exp $"); 4065674SkrisRCSID("$FreeBSD: head/crypto/openssh/hostfile.c 76262 2001-05-04 04:14:23Z green $"); 4157429Smarkm 4257429Smarkm#include "packet.h" 4358582Skris#include "match.h" 4458582Skris#include "key.h" 4558582Skris#include "hostfile.h" 4676262Sgreen#include "log.h" 4757429Smarkm 4857429Smarkm/* 4958582Skris * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the 5058582Skris * pointer over the key. Skips any whitespace at the beginning and at end. 5157429Smarkm */ 5257429Smarkm 5357429Smarkmint 5476262Sgreenhostfile_read_key(char **cpp, u_int *bitsp, Key *ret) 5557429Smarkm{ 5657429Smarkm char *cp; 5757429Smarkm 5857429Smarkm /* Skip leading whitespace. */ 5957429Smarkm for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) 6057429Smarkm ; 6157429Smarkm 6276262Sgreen if (key_read(ret, &cp) != 1) 6357429Smarkm return 0; 6457429Smarkm 6557429Smarkm /* Skip trailing whitespace. */ 6657429Smarkm for (; *cp == ' ' || *cp == '\t'; cp++) 6757429Smarkm ; 6857429Smarkm 6957429Smarkm /* Return results. */ 7057429Smarkm *cpp = cp; 7176262Sgreen *bitsp = key_size(ret); 7257429Smarkm return 1; 7357429Smarkm} 7457429Smarkm 7558582Skrisint 7676262Sgreenauth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n) 7758582Skris{ 7876262Sgreen Key *k = key_new(KEY_RSA1); 7958582Skris int ret = hostfile_read_key(cpp, bitsp, k); 8058582Skris BN_copy(e, k->rsa->e); 8158582Skris BN_copy(n, k->rsa->n); 8258582Skris key_free(k); 8358582Skris return ret; 8458582Skris} 8557429Smarkm 8657429Smarkmint 8758582Skrishostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum) 8857429Smarkm{ 8976262Sgreen if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) 9058582Skris return 1; 9158582Skris if (bits != BN_num_bits(key->rsa->n)) { 9260576Skris log("Warning: %s, line %d: keysize mismatch for host %s: " 9358582Skris "actual %d vs. announced %d.", 9458582Skris filename, linenum, host, BN_num_bits(key->rsa->n), bits); 9560576Skris log("Warning: replace %d with %d in %s, line %d.", 9658582Skris bits, BN_num_bits(key->rsa->n), filename, linenum); 9757429Smarkm } 9858582Skris return 1; 9957429Smarkm} 10057429Smarkm 10157429Smarkm/* 10257429Smarkm * Checks whether the given host (which must be in all lowercase) is already 10357429Smarkm * in the list of our known hosts. Returns HOST_OK if the host is known and 10457429Smarkm * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED 10557429Smarkm * if the host is known but used to have a different host key. 10657429Smarkm */ 10757429Smarkm 10857429SmarkmHostStatus 10976262Sgreencheck_host_in_hostfile(const char *filename, const char *host, Key *key, 11076262Sgreen Key *found, int *numret) 11157429Smarkm{ 11257429Smarkm FILE *f; 11357429Smarkm char line[8192]; 11457429Smarkm int linenum = 0; 11576262Sgreen u_int kbits; 11657429Smarkm char *cp, *cp2; 11757429Smarkm HostStatus end_return; 11857429Smarkm 11976262Sgreen debug3("check_host_in_hostfile: filename %s", filename); 12058582Skris if (key == NULL) 12158582Skris fatal("no key to look up"); 12257429Smarkm /* Open the file containing the list of known hosts. */ 12357429Smarkm f = fopen(filename, "r"); 12457429Smarkm if (!f) 12557429Smarkm return HOST_NEW; 12657429Smarkm 12757429Smarkm /* 12857429Smarkm * Return value when the loop terminates. This is set to 12957429Smarkm * HOST_CHANGED if we have seen a different key for the host and have 13057429Smarkm * not found the proper one. 13157429Smarkm */ 13257429Smarkm end_return = HOST_NEW; 13357429Smarkm 13476262Sgreen /* Go through the file. */ 13557429Smarkm while (fgets(line, sizeof(line), f)) { 13657429Smarkm cp = line; 13757429Smarkm linenum++; 13857429Smarkm 13957429Smarkm /* Skip any leading whitespace, comments and empty lines. */ 14057429Smarkm for (; *cp == ' ' || *cp == '\t'; cp++) 14157429Smarkm ; 14257429Smarkm if (!*cp || *cp == '#' || *cp == '\n') 14357429Smarkm continue; 14457429Smarkm 14557429Smarkm /* Find the end of the host name portion. */ 14657429Smarkm for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) 14757429Smarkm ; 14857429Smarkm 14957429Smarkm /* Check if the host name matches. */ 15076262Sgreen if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1) 15157429Smarkm continue; 15257429Smarkm 15357429Smarkm /* Got a match. Skip host name. */ 15457429Smarkm cp = cp2; 15557429Smarkm 15657429Smarkm /* 15757429Smarkm * Extract the key from the line. This will skip any leading 15857429Smarkm * whitespace. Ignore badly formatted lines. 15957429Smarkm */ 16058582Skris if (!hostfile_read_key(&cp, &kbits, found)) 16157429Smarkm continue; 16258582Skris if (!hostfile_check_key(kbits, found, host, filename, linenum)) 16358582Skris continue; 16457429Smarkm 16576262Sgreen if (numret != NULL) 16676262Sgreen *numret = linenum; 16776262Sgreen 16857429Smarkm /* Check if the current key is the same as the given key. */ 16958582Skris if (key_equal(key, found)) { 17057429Smarkm /* Ok, they match. */ 17176262Sgreen debug3("check_host_in_hostfile: match line %d", linenum); 17257429Smarkm fclose(f); 17357429Smarkm return HOST_OK; 17457429Smarkm } 17557429Smarkm /* 17657429Smarkm * They do not match. We will continue to go through the 17757429Smarkm * file; however, we note that we will not return that it is 17857429Smarkm * new. 17957429Smarkm */ 18057429Smarkm end_return = HOST_CHANGED; 18157429Smarkm } 18257429Smarkm /* Clear variables and close the file. */ 18357429Smarkm fclose(f); 18457429Smarkm 18557429Smarkm /* 18657429Smarkm * Return either HOST_NEW or HOST_CHANGED, depending on whether we 18757429Smarkm * saw a different key for the host. 18857429Smarkm */ 18957429Smarkm return end_return; 19057429Smarkm} 19157429Smarkm 19257429Smarkm/* 19357429Smarkm * Appends an entry to the host file. Returns false if the entry could not 19457429Smarkm * be appended. 19557429Smarkm */ 19657429Smarkm 19757429Smarkmint 19858582Skrisadd_host_to_hostfile(const char *filename, const char *host, Key *key) 19957429Smarkm{ 20057429Smarkm FILE *f; 20158582Skris int success = 0; 20258582Skris if (key == NULL) 20360576Skris return 1; /* XXX ? */ 20457429Smarkm f = fopen(filename, "a"); 20557429Smarkm if (!f) 20657429Smarkm return 0; 20758582Skris fprintf(f, "%s ", host); 20858582Skris if (key_write(key, f)) { 20958582Skris success = 1; 21058582Skris } else { 21160576Skris error("add_host_to_hostfile: saving key in %s failed", filename); 21257429Smarkm } 21360576Skris fprintf(f, "\n"); 21457429Smarkm fclose(f); 21558582Skris return success; 21657429Smarkm} 217