1323124Sdes/* $OpenBSD: auth2-hostbased.c,v 1.26 2016/03/07 19:02:43 djm Exp $ */ 298675Sdes/* 398675Sdes * Copyright (c) 2000 Markus Friedl. All rights reserved. 498675Sdes * 598675Sdes * Redistribution and use in source and binary forms, with or without 698675Sdes * modification, are permitted provided that the following conditions 798675Sdes * are met: 898675Sdes * 1. Redistributions of source code must retain the above copyright 998675Sdes * notice, this list of conditions and the following disclaimer. 1098675Sdes * 2. Redistributions in binary form must reproduce the above copyright 1198675Sdes * notice, this list of conditions and the following disclaimer in the 1298675Sdes * documentation and/or other materials provided with the distribution. 1398675Sdes * 1498675Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1598675Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1698675Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1798675Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1898675Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1998675Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2098675Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2198675Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2298675Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2398675Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2498675Sdes */ 2598675Sdes 2698675Sdes#include "includes.h" 2798675Sdes 28162852Sdes#include <sys/types.h> 29162852Sdes 30162852Sdes#include <pwd.h> 31162852Sdes#include <string.h> 32162852Sdes#include <stdarg.h> 33162852Sdes 34162852Sdes#include "xmalloc.h" 3598675Sdes#include "ssh2.h" 3698675Sdes#include "packet.h" 3798675Sdes#include "buffer.h" 3898675Sdes#include "log.h" 39295367Sdes#include "misc.h" 4098675Sdes#include "servconf.h" 4198675Sdes#include "compat.h" 42162852Sdes#include "key.h" 43162852Sdes#include "hostfile.h" 4498675Sdes#include "auth.h" 4598675Sdes#include "canohost.h" 46162852Sdes#ifdef GSSAPI 47162852Sdes#include "ssh-gss.h" 48162852Sdes#endif 4998675Sdes#include "monitor_wrap.h" 5098675Sdes#include "pathnames.h" 51295367Sdes#include "match.h" 5298675Sdes 5398675Sdes/* import */ 5498675Sdesextern ServerOptions options; 5598675Sdesextern u_char *session_id2; 56124208Sdesextern u_int session_id2_len; 5798675Sdes 5898675Sdesstatic int 5998675Sdesuserauth_hostbased(Authctxt *authctxt) 6098675Sdes{ 6198675Sdes Buffer b; 6298675Sdes Key *key = NULL; 6398675Sdes char *pkalg, *cuser, *chost, *service; 6498675Sdes u_char *pkblob, *sig; 6598675Sdes u_int alen, blen, slen; 6698675Sdes int pktype; 6798675Sdes int authenticated = 0; 6898675Sdes 6998675Sdes if (!authctxt->valid) { 7098675Sdes debug2("userauth_hostbased: disabled because of invalid user"); 7198675Sdes return 0; 7298675Sdes } 7398675Sdes pkalg = packet_get_string(&alen); 7498675Sdes pkblob = packet_get_string(&blen); 7598675Sdes chost = packet_get_string(NULL); 7698675Sdes cuser = packet_get_string(NULL); 7798675Sdes sig = packet_get_string(&slen); 7898675Sdes 7998675Sdes debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d", 8098675Sdes cuser, chost, pkalg, slen); 8198675Sdes#ifdef DEBUG_PK 8298675Sdes debug("signature:"); 8398675Sdes buffer_init(&b); 8498675Sdes buffer_append(&b, sig, slen); 8598675Sdes buffer_dump(&b); 8698675Sdes buffer_free(&b); 8798675Sdes#endif 8898675Sdes pktype = key_type_from_name(pkalg); 8998675Sdes if (pktype == KEY_UNSPEC) { 9098675Sdes /* this is perfectly legal */ 91124208Sdes logit("userauth_hostbased: unsupported " 9298675Sdes "public key algorithm: %s", pkalg); 9398675Sdes goto done; 9498675Sdes } 9598675Sdes key = key_from_blob(pkblob, blen); 9698675Sdes if (key == NULL) { 9798675Sdes error("userauth_hostbased: cannot decode key: %s", pkalg); 9898675Sdes goto done; 9998675Sdes } 10098675Sdes if (key->type != pktype) { 10198675Sdes error("userauth_hostbased: type mismatch for decoded key " 10298675Sdes "(received %d, expected %d)", key->type, pktype); 10398675Sdes goto done; 10498675Sdes } 105262566Sdes if (key_type_plain(key->type) == KEY_RSA && 106262566Sdes (datafellows & SSH_BUG_RSASIGMD5) != 0) { 107262566Sdes error("Refusing RSA key because peer uses unsafe " 108262566Sdes "signature format"); 109262566Sdes goto done; 110262566Sdes } 111295367Sdes if (match_pattern_list(sshkey_ssh_name(key), 112295367Sdes options.hostbased_key_types, 0) != 1) { 113295367Sdes logit("%s: key type %s not in HostbasedAcceptedKeyTypes", 114295367Sdes __func__, sshkey_type(key)); 115295367Sdes goto done; 116295367Sdes } 117295367Sdes 11898675Sdes service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : 11998675Sdes authctxt->service; 12098675Sdes buffer_init(&b); 12198675Sdes buffer_put_string(&b, session_id2, session_id2_len); 12298675Sdes /* reconstruct packet */ 12398675Sdes buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 12498675Sdes buffer_put_cstring(&b, authctxt->user); 12598675Sdes buffer_put_cstring(&b, service); 12698675Sdes buffer_put_cstring(&b, "hostbased"); 12798675Sdes buffer_put_string(&b, pkalg, alen); 12898675Sdes buffer_put_string(&b, pkblob, blen); 12998675Sdes buffer_put_cstring(&b, chost); 13098675Sdes buffer_put_cstring(&b, cuser); 13198675Sdes#ifdef DEBUG_PK 13298675Sdes buffer_dump(&b); 13398675Sdes#endif 134255767Sdes 135255767Sdes pubkey_auth_info(authctxt, key, 136255767Sdes "client user \"%.100s\", client host \"%.100s\"", cuser, chost); 137255767Sdes 13898675Sdes /* test for allowed key and correct signature */ 13998675Sdes authenticated = 0; 14098675Sdes if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && 14198675Sdes PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), 14298675Sdes buffer_len(&b))) == 1) 14398675Sdes authenticated = 1; 14498675Sdes 145126274Sdes buffer_free(&b); 14698675Sdesdone: 14798675Sdes debug2("userauth_hostbased: authenticated %d", authenticated); 14898675Sdes if (key != NULL) 14998675Sdes key_free(key); 150255767Sdes free(pkalg); 151255767Sdes free(pkblob); 152255767Sdes free(cuser); 153255767Sdes free(chost); 154255767Sdes free(sig); 15598675Sdes return authenticated; 15698675Sdes} 15798675Sdes 15898675Sdes/* return 1 if given hostkey is allowed */ 15998675Sdesint 16098675Sdeshostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, 16198675Sdes Key *key) 16298675Sdes{ 163323124Sdes struct ssh *ssh = active_state; /* XXX */ 164215116Sdes const char *resolvedname, *ipaddr, *lookup, *reason; 16598675Sdes HostStatus host_status; 16698675Sdes int len; 167215116Sdes char *fp; 16898675Sdes 169204917Sdes if (auth_key_is_revoked(key)) 170204917Sdes return 0; 171204917Sdes 172323124Sdes resolvedname = auth_get_canonical_hostname(ssh, options.use_dns); 173323124Sdes ipaddr = ssh_remote_ipaddr(ssh); 17498675Sdes 175295367Sdes debug2("%s: chost %s resolvedname %s ipaddr %s", __func__, 17698675Sdes chost, resolvedname, ipaddr); 17798675Sdes 178181111Sdes if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') { 179181111Sdes debug2("stripping trailing dot from chost %s", chost); 180181111Sdes chost[len - 1] = '\0'; 181181111Sdes } 182181111Sdes 18398675Sdes if (options.hostbased_uses_name_from_packet_only) { 184295367Sdes if (auth_rhosts2(pw, cuser, chost, chost) == 0) { 185295367Sdes debug2("%s: auth_rhosts2 refused " 186295367Sdes "user \"%.100s\" host \"%.100s\" (from packet)", 187295367Sdes __func__, cuser, chost); 18898675Sdes return 0; 189295367Sdes } 19098675Sdes lookup = chost; 19198675Sdes } else { 19298675Sdes if (strcasecmp(resolvedname, chost) != 0) 193124208Sdes logit("userauth_hostbased mismatch: " 19498675Sdes "client sends %s, but we resolve %s to %s", 19598675Sdes chost, ipaddr, resolvedname); 196295367Sdes if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0) { 197295367Sdes debug2("%s: auth_rhosts2 refused " 198295367Sdes "user \"%.100s\" host \"%.100s\" addr \"%.100s\"", 199295367Sdes __func__, cuser, resolvedname, ipaddr); 20098675Sdes return 0; 201295367Sdes } 20298675Sdes lookup = resolvedname; 20398675Sdes } 204295367Sdes debug2("%s: access allowed by auth_rhosts2", __func__); 20598675Sdes 206215116Sdes if (key_is_cert(key) && 207215116Sdes key_cert_check_authority(key, 1, 0, lookup, &reason)) { 208215116Sdes error("%s", reason); 209215116Sdes auth_debug_add("%s", reason); 210215116Sdes return 0; 211215116Sdes } 212215116Sdes 21398675Sdes host_status = check_key_in_hostfiles(pw, key, lookup, 21498675Sdes _PATH_SSH_SYSTEM_HOSTFILE, 21598675Sdes options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); 21698675Sdes 21798675Sdes /* backward compat if no key has been found. */ 218215116Sdes if (host_status == HOST_NEW) { 21998675Sdes host_status = check_key_in_hostfiles(pw, key, lookup, 22098675Sdes _PATH_SSH_SYSTEM_HOSTFILE2, 22198675Sdes options.ignore_user_known_hosts ? NULL : 22298675Sdes _PATH_SSH_USER_HOSTFILE2); 223215116Sdes } 22498675Sdes 225215116Sdes if (host_status == HOST_OK) { 226215116Sdes if (key_is_cert(key)) { 227295367Sdes if ((fp = sshkey_fingerprint(key->cert->signature_key, 228295367Sdes options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 229295367Sdes fatal("%s: sshkey_fingerprint fail", __func__); 230215116Sdes verbose("Accepted certificate ID \"%s\" signed by " 231215116Sdes "%s CA %s from %s@%s", key->cert->key_id, 232215116Sdes key_type(key->cert->signature_key), fp, 233215116Sdes cuser, lookup); 234215116Sdes } else { 235295367Sdes if ((fp = sshkey_fingerprint(key, 236295367Sdes options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 237295367Sdes fatal("%s: sshkey_fingerprint fail", __func__); 238215116Sdes verbose("Accepted %s public key %s from %s@%s", 239215116Sdes key_type(key), fp, cuser, lookup); 240215116Sdes } 241255767Sdes free(fp); 242215116Sdes } 243215116Sdes 24498675Sdes return (host_status == HOST_OK); 24598675Sdes} 24698675Sdes 24798675SdesAuthmethod method_hostbased = { 24898675Sdes "hostbased", 24998675Sdes userauth_hostbased, 25098675Sdes &options.hostbased_authentication 25198675Sdes}; 252