auth2-hostbased.c revision 262566
1139735Simp/* $OpenBSD: auth2-hostbased.c,v 1.17 2013/12/30 23:52:27 djm Exp $ */ 2129198Scognet/* 3129198Scognet * Copyright (c) 2000 Markus Friedl. All rights reserved. 4129198Scognet * 5129198Scognet * Redistribution and use in source and binary forms, with or without 6129198Scognet * modification, are permitted provided that the following conditions 7129198Scognet * are met: 8129198Scognet * 1. Redistributions of source code must retain the above copyright 9129198Scognet * notice, this list of conditions and the following disclaimer. 10129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 11129198Scognet * notice, this list of conditions and the following disclaimer in the 12129198Scognet * documentation and/or other materials provided with the distribution. 13129198Scognet * 14129198Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15129198Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16129198Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17129198Scognet * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18129198Scognet * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19129198Scognet * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20129198Scognet * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21129198Scognet * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22129198Scognet * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23129198Scognet * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24129198Scognet */ 25129198Scognet 26129198Scognet#include "includes.h" 27129198Scognet 28129198Scognet#include <sys/types.h> 29129198Scognet 30129198Scognet#include <pwd.h> 31129198Scognet#include <string.h> 32129198Scognet#include <stdarg.h> 33129198Scognet 34129198Scognet#include "xmalloc.h" 35129198Scognet#include "ssh2.h" 36129198Scognet#include "packet.h" 37129198Scognet#include "buffer.h" 38129198Scognet#include "log.h" 39129198Scognet#include "servconf.h" 40129198Scognet#include "compat.h" 41129198Scognet#include "key.h" 42129198Scognet#include "hostfile.h" 43129198Scognet#include "auth.h" 44129198Scognet#include "canohost.h" 45129198Scognet#ifdef GSSAPI 46129198Scognet#include "ssh-gss.h" 47129198Scognet#endif 48129198Scognet#include "monitor_wrap.h" 49140310Scognet#include "pathnames.h" 50146597Scognet 51129198Scognet/* import */ 52129198Scognetextern ServerOptions options; 53129198Scognetextern u_char *session_id2; 54129198Scognetextern u_int session_id2_len; 55129198Scognet 56129198Scognetstatic int 57129198Scognetuserauth_hostbased(Authctxt *authctxt) 58129198Scognet{ 59129198Scognet Buffer b; 60129198Scognet Key *key = NULL; 61129198Scognet char *pkalg, *cuser, *chost, *service; 62129198Scognet u_char *pkblob, *sig; 63129198Scognet u_int alen, blen, slen; 64129198Scognet int pktype; 65129198Scognet int authenticated = 0; 66129198Scognet 67129198Scognet if (!authctxt->valid) { 68129198Scognet debug2("userauth_hostbased: disabled because of invalid user"); 69129198Scognet return 0; 70129198Scognet } 71129198Scognet pkalg = packet_get_string(&alen); 72129198Scognet pkblob = packet_get_string(&blen); 73129198Scognet chost = packet_get_string(NULL); 74129198Scognet cuser = packet_get_string(NULL); 75129198Scognet sig = packet_get_string(&slen); 76129198Scognet 77129198Scognet debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d", 78129198Scognet cuser, chost, pkalg, slen); 79129198Scognet#ifdef DEBUG_PK 80129198Scognet debug("signature:"); 81129198Scognet buffer_init(&b); 82129198Scognet buffer_append(&b, sig, slen); 83129198Scognet buffer_dump(&b); 84129198Scognet buffer_free(&b); 85129198Scognet#endif 86135644Scognet pktype = key_type_from_name(pkalg); 87135644Scognet if (pktype == KEY_UNSPEC) { 88135644Scognet /* this is perfectly legal */ 89146597Scognet logit("userauth_hostbased: unsupported " 90135644Scognet "public key algorithm: %s", pkalg); 91135644Scognet goto done; 92129198Scognet } 93135644Scognet key = key_from_blob(pkblob, blen); 94135644Scognet if (key == NULL) { 95135644Scognet error("userauth_hostbased: cannot decode key: %s", pkalg); 96156191Scognet goto done; 97156191Scognet } 98147591Scognet if (key->type != pktype) { 99135644Scognet error("userauth_hostbased: type mismatch for decoded key " 100129198Scognet "(received %d, expected %d)", key->type, pktype); 101129198Scognet goto done; 102147591Scognet } 103147591Scognet if (key_type_plain(key->type) == KEY_RSA && 104147591Scognet (datafellows & SSH_BUG_RSASIGMD5) != 0) { 105146597Scognet error("Refusing RSA key because peer uses unsafe " 106146597Scognet "signature format"); 107146597Scognet goto done; 108146597Scognet } 109146597Scognet service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : 110146597Scognet authctxt->service; 111146597Scognet buffer_init(&b); 112147591Scognet buffer_put_string(&b, session_id2, session_id2_len); 113147591Scognet /* reconstruct packet */ 114147591Scognet buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 115147591Scognet buffer_put_cstring(&b, authctxt->user); 116147591Scognet buffer_put_cstring(&b, service); 117147591Scognet buffer_put_cstring(&b, "hostbased"); 118147591Scognet buffer_put_string(&b, pkalg, alen); 119147591Scognet buffer_put_string(&b, pkblob, blen); 120147591Scognet buffer_put_cstring(&b, chost); 121147591Scognet buffer_put_cstring(&b, cuser); 122147591Scognet#ifdef DEBUG_PK 123129198Scognet buffer_dump(&b); 124129198Scognet#endif 125129198Scognet 126129198Scognet pubkey_auth_info(authctxt, key, 127137758Scognet "client user \"%.100s\", client host \"%.100s\"", cuser, chost); 128140349Scognet 129137758Scognet /* test for allowed key and correct signature */ 130137760Scognet authenticated = 0; 131135644Scognet if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && 132129198Scognet PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), 133129198Scognet buffer_len(&b))) == 1) 134129198Scognet authenticated = 1; 135129198Scognet 136129198Scognet buffer_free(&b); 137129198Scognetdone: 138129198Scognet debug2("userauth_hostbased: authenticated %d", authenticated); 139129198Scognet if (key != NULL) 140129198Scognet key_free(key); 141129198Scognet free(pkalg); 142129198Scognet free(pkblob); 143129198Scognet free(cuser); 144129198Scognet free(chost); 145129198Scognet free(sig); 146129198Scognet return authenticated; 147129198Scognet} 148129198Scognet 149129198Scognet/* return 1 if given hostkey is allowed */ 150129198Scognetint 151129198Scognethostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, 152129198Scognet Key *key) 153129198Scognet{ 154129198Scognet const char *resolvedname, *ipaddr, *lookup, *reason; 155129198Scognet HostStatus host_status; 156129198Scognet int len; 157129198Scognet char *fp; 158129198Scognet 159129198Scognet if (auth_key_is_revoked(key)) 160129198Scognet return 0; 161129198Scognet 162129198Scognet resolvedname = get_canonical_hostname(options.use_dns); 163129198Scognet ipaddr = get_remote_ipaddr(); 164129198Scognet 165129198Scognet debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s", 166129198Scognet chost, resolvedname, ipaddr); 167129198Scognet 168129198Scognet if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') { 169129198Scognet debug2("stripping trailing dot from chost %s", chost); 170129198Scognet chost[len - 1] = '\0'; 171129198Scognet } 172129198Scognet 173129198Scognet if (options.hostbased_uses_name_from_packet_only) { 174129198Scognet if (auth_rhosts2(pw, cuser, chost, chost) == 0) 175129198Scognet return 0; 176129198Scognet lookup = chost; 177129198Scognet } else { 178129198Scognet if (strcasecmp(resolvedname, chost) != 0) 179129198Scognet logit("userauth_hostbased mismatch: " 180129198Scognet "client sends %s, but we resolve %s to %s", 181129198Scognet chost, ipaddr, resolvedname); 182129198Scognet if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0) 183129198Scognet return 0; 184129198Scognet lookup = resolvedname; 185129198Scognet } 186129198Scognet debug2("userauth_hostbased: access allowed by auth_rhosts2"); 187147591Scognet 188146597Scognet if (key_is_cert(key) && 189146597Scognet key_cert_check_authority(key, 1, 0, lookup, &reason)) { 190146597Scognet error("%s", reason); 191146597Scognet auth_debug_add("%s", reason); 192146597Scognet return 0; 193147591Scognet } 194150860Scognet 195150860Scognet host_status = check_key_in_hostfiles(pw, key, lookup, 196146597Scognet _PATH_SSH_SYSTEM_HOSTFILE, 197147591Scognet options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); 198147591Scognet 199147591Scognet /* backward compat if no key has been found. */ 200147591Scognet if (host_status == HOST_NEW) { 201147591Scognet host_status = check_key_in_hostfiles(pw, key, lookup, 202147591Scognet _PATH_SSH_SYSTEM_HOSTFILE2, 203146597Scognet options.ignore_user_known_hosts ? NULL : 204146597Scognet _PATH_SSH_USER_HOSTFILE2); 205146597Scognet } 206147591Scognet 207146597Scognet if (host_status == HOST_OK) { 208146597Scognet if (key_is_cert(key)) { 209146597Scognet fp = key_fingerprint(key->cert->signature_key, 210146597Scognet SSH_FP_MD5, SSH_FP_HEX); 211146597Scognet verbose("Accepted certificate ID \"%s\" signed by " 212146597Scognet "%s CA %s from %s@%s", key->cert->key_id, 213147591Scognet key_type(key->cert->signature_key), fp, 214146597Scognet cuser, lookup); 215146597Scognet } else { 216146597Scognet fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); 217146597Scognet verbose("Accepted %s public key %s from %s@%s", 218129198Scognet key_type(key), fp, cuser, lookup); 219129198Scognet } 220129198Scognet free(fp); 221135644Scognet } 222135644Scognet 223129198Scognet return (host_status == HOST_OK); 224129198Scognet} 225129198Scognet 226129198ScognetAuthmethod method_hostbased = { 227129198Scognet "hostbased", 228129198Scognet userauth_hostbased, 229129198Scognet &options.hostbased_authentication 230129198Scognet}; 231129198Scognet