1296853Sdes/* $OpenBSD: sshconnect2.c,v 1.239 2016/02/23 01:34:14 djm Exp $ */ 260573Skris/* 360573Skris * Copyright (c) 2000 Markus Friedl. All rights reserved. 4192595Sdes * Copyright (c) 2008 Damien Miller. All rights reserved. 560573Skris * 660573Skris * Redistribution and use in source and binary forms, with or without 760573Skris * modification, are permitted provided that the following conditions 860573Skris * are met: 960573Skris * 1. Redistributions of source code must retain the above copyright 1060573Skris * notice, this list of conditions and the following disclaimer. 1160573Skris * 2. Redistributions in binary form must reproduce the above copyright 1260573Skris * notice, this list of conditions and the following disclaimer in the 1360573Skris * documentation and/or other materials provided with the distribution. 1460573Skris * 1560573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1660573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1760573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1860573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1960573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2060573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2160573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2260573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2360573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2460573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2560573Skris */ 2660573Skris 2760573Skris#include "includes.h" 2860573Skris 29162856Sdes#include <sys/types.h> 30162856Sdes#include <sys/socket.h> 31162856Sdes#include <sys/wait.h> 32162856Sdes#include <sys/stat.h> 33162856Sdes 34162856Sdes#include <errno.h> 35204917Sdes#include <fcntl.h> 36181111Sdes#include <netdb.h> 37162856Sdes#include <pwd.h> 38162856Sdes#include <signal.h> 39162856Sdes#include <stdarg.h> 40162856Sdes#include <stdio.h> 41162856Sdes#include <string.h> 42162856Sdes#include <unistd.h> 43248619Sdes#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) 44181111Sdes#include <vis.h> 45181111Sdes#endif 46162856Sdes 47124211Sdes#include "openbsd-compat/sys-queue.h" 48124211Sdes 49162856Sdes#include "xmalloc.h" 5060573Skris#include "ssh.h" 5176262Sgreen#include "ssh2.h" 5260573Skris#include "buffer.h" 5360573Skris#include "packet.h" 5460573Skris#include "compat.h" 5576262Sgreen#include "cipher.h" 56162856Sdes#include "key.h" 5760573Skris#include "kex.h" 5860573Skris#include "myproposal.h" 5960573Skris#include "sshconnect.h" 6060573Skris#include "authfile.h" 6176262Sgreen#include "dh.h" 6276262Sgreen#include "authfd.h" 6376262Sgreen#include "log.h" 64295367Sdes#include "misc.h" 6576262Sgreen#include "readconf.h" 6676262Sgreen#include "match.h" 6769587Sgreen#include "dispatch.h" 6876262Sgreen#include "canohost.h" 6998684Sdes#include "msg.h" 7098684Sdes#include "pathnames.h" 71162856Sdes#include "uidswap.h" 72221420Sdes#include "hostfile.h" 73295367Sdes#include "ssherr.h" 7460573Skris 75124211Sdes#ifdef GSSAPI 76124211Sdes#include "ssh-gss.h" 77124211Sdes#endif 78124211Sdes 7960573Skris/* import */ 8060573Skrisextern char *client_version_string; 8160573Skrisextern char *server_version_string; 8260573Skrisextern Options options; 8360573Skris 8460573Skris/* 8560573Skris * SSH2 key exchange 8660573Skris */ 8760573Skris 8876262Sgreenu_char *session_id2 = NULL; 89124211Sdesu_int session_id2_len = 0; 9060573Skris 9176262Sgreenchar *xxx_host; 9276262Sgreenstruct sockaddr *xxx_hostaddr; 9376262Sgreen 9492559Sdesstatic int 95295367Sdesverify_host_key_callback(Key *hostkey, struct ssh *ssh) 9676262Sgreen{ 9792559Sdes if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) 9892559Sdes fatal("Host key verification failed."); 9976262Sgreen return 0; 10076262Sgreen} 10176262Sgreen 102221420Sdesstatic char * 103221420Sdesorder_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port) 104221420Sdes{ 105221420Sdes char *oavail, *avail, *first, *last, *alg, *hostname, *ret; 106221420Sdes size_t maxlen; 107221420Sdes struct hostkeys *hostkeys; 108221420Sdes int ktype; 109226046Sdes u_int i; 110221420Sdes 111221420Sdes /* Find all hostkeys for this hostname */ 112221420Sdes get_hostfile_hostname_ipaddr(host, hostaddr, port, &hostname, NULL); 113221420Sdes hostkeys = init_hostkeys(); 114226046Sdes for (i = 0; i < options.num_user_hostfiles; i++) 115226046Sdes load_hostkeys(hostkeys, hostname, options.user_hostfiles[i]); 116226046Sdes for (i = 0; i < options.num_system_hostfiles; i++) 117226046Sdes load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]); 118221420Sdes 119221420Sdes oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG); 120221420Sdes maxlen = strlen(avail) + 1; 121221420Sdes first = xmalloc(maxlen); 122221420Sdes last = xmalloc(maxlen); 123221420Sdes *first = *last = '\0'; 124221420Sdes 125221420Sdes#define ALG_APPEND(to, from) \ 126221420Sdes do { \ 127221420Sdes if (*to != '\0') \ 128221420Sdes strlcat(to, ",", maxlen); \ 129221420Sdes strlcat(to, from, maxlen); \ 130221420Sdes } while (0) 131221420Sdes 132221420Sdes while ((alg = strsep(&avail, ",")) && *alg != '\0') { 133295367Sdes if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) 134221420Sdes fatal("%s: unknown alg %s", __func__, alg); 135221420Sdes if (lookup_key_in_hostkeys_by_type(hostkeys, 136295367Sdes sshkey_type_plain(ktype), NULL)) 137221420Sdes ALG_APPEND(first, alg); 138221420Sdes else 139221420Sdes ALG_APPEND(last, alg); 140221420Sdes } 141221420Sdes#undef ALG_APPEND 142295367Sdes xasprintf(&ret, "%s%s%s", first, 143295367Sdes (*first == '\0' || *last == '\0') ? "" : ",", last); 144221420Sdes if (*first != '\0') 145221420Sdes debug3("%s: prefer hostkeyalgs: %s", __func__, first); 146221420Sdes 147255767Sdes free(first); 148255767Sdes free(last); 149255767Sdes free(hostname); 150255767Sdes free(oavail); 151221420Sdes free_hostkeys(hostkeys); 152221420Sdes 153221420Sdes return ret; 154221420Sdes} 155221420Sdes 15660573Skrisvoid 157221420Sdesssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) 15860573Skris{ 159295367Sdes char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 160296853Sdes char *s; 161295367Sdes struct kex *kex; 162295367Sdes int r; 16369587Sgreen 16476262Sgreen xxx_host = host; 16576262Sgreen xxx_hostaddr = hostaddr; 16676262Sgreen 167296853Sdes if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) 168296853Sdes fatal("%s: kex_names_cat", __func__); 169296853Sdes myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s); 17076262Sgreen myproposal[PROPOSAL_ENC_ALGS_CTOS] = 171295367Sdes compat_cipher_proposal(options.ciphers); 17276262Sgreen myproposal[PROPOSAL_ENC_ALGS_STOC] = 173295367Sdes compat_cipher_proposal(options.ciphers); 17469587Sgreen if (options.compression) { 17576262Sgreen myproposal[PROPOSAL_COMP_ALGS_CTOS] = 176149753Sdes myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib@openssh.com,zlib,none"; 17769587Sgreen } else { 17876262Sgreen myproposal[PROPOSAL_COMP_ALGS_CTOS] = 179149753Sdes myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com,zlib"; 18069587Sgreen } 181295367Sdes myproposal[PROPOSAL_MAC_ALGS_CTOS] = 182295367Sdes myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; 183295367Sdes if (options.hostkeyalgorithms != NULL) { 184295367Sdes if (kex_assemble_names(KEX_DEFAULT_PK_ALG, 185295367Sdes &options.hostkeyalgorithms) != 0) 186295367Sdes fatal("%s: kex_assemble_namelist", __func__); 18792559Sdes myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 188262566Sdes compat_pkalg_proposal(options.hostkeyalgorithms); 189295367Sdes } else { 190295367Sdes /* Enforce default */ 191295367Sdes options.hostkeyalgorithms = xstrdup(KEX_DEFAULT_PK_ALG); 192221420Sdes /* Prefer algorithms that we already have keys for */ 193221420Sdes myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 194262566Sdes compat_pkalg_proposal( 195262566Sdes order_hostkeyalgs(host, hostaddr, port)); 196221420Sdes } 19769587Sgreen 198255767Sdes if (options.rekey_limit || options.rekey_interval) 199255767Sdes packet_set_rekey_limits((u_int32_t)options.rekey_limit, 200255767Sdes (time_t)options.rekey_interval); 201124211Sdes 20276262Sgreen /* start key exchange */ 203295367Sdes if ((r = kex_setup(active_state, myproposal)) != 0) 204295367Sdes fatal("kex_setup: %s", ssh_err(r)); 205295367Sdes kex = active_state->kex; 206295367Sdes#ifdef WITH_OPENSSL 207113911Sdes kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 208137019Sdes kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 209113911Sdes kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 210162856Sdes kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 211295367Sdes# ifdef OPENSSL_HAS_ECC 212221420Sdes kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 213295367Sdes# endif 214295367Sdes#endif 215262566Sdes kex->kex[KEX_C25519_SHA256] = kexc25519_client; 21676262Sgreen kex->client_version_string=client_version_string; 21776262Sgreen kex->server_version_string=server_version_string; 21892559Sdes kex->verify_host_key=&verify_host_key_callback; 21969587Sgreen 220295367Sdes dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); 22169587Sgreen 222296853Sdes /* remove ext-info from the KEX proposals for rekeying */ 223296853Sdes myproposal[PROPOSAL_KEX_ALGS] = 224296853Sdes compat_kex_proposal(options.kex_algorithms); 225296853Sdes if ((r = kex_prop2buf(kex->my, myproposal)) != 0) 226296853Sdes fatal("kex_prop2buf: %s", ssh_err(r)); 227204917Sdes 22876262Sgreen session_id2 = kex->session_id; 22976262Sgreen session_id2_len = kex->session_id_len; 23069587Sgreen 23169587Sgreen#ifdef DEBUG_KEXDH 23269587Sgreen /* send 1st encrypted/maced/compressed message */ 23369587Sgreen packet_start(SSH2_MSG_IGNORE); 23469587Sgreen packet_put_cstring("markus"); 23569587Sgreen packet_send(); 23669587Sgreen packet_write_wait(); 23769587Sgreen#endif 23869587Sgreen} 23969587Sgreen 24069587Sgreen/* 24160573Skris * Authenticate user 24260573Skris */ 24369587Sgreen 244295367Sdestypedef struct cauthctxt Authctxt; 245295367Sdestypedef struct cauthmethod Authmethod; 246124211Sdestypedef struct identity Identity; 247124211Sdestypedef struct idlist Idlist; 24869587Sgreen 249124211Sdesstruct identity { 250124211Sdes TAILQ_ENTRY(identity) next; 251295367Sdes int agent_fd; /* >=0 if agent supports key */ 252295367Sdes struct sshkey *key; /* public/private key */ 253124211Sdes char *filename; /* comment for agent-only keys */ 254124211Sdes int tried; 255124211Sdes int isprivate; /* key points to the private key */ 256248619Sdes int userprovided; 257124211Sdes}; 258124211SdesTAILQ_HEAD(idlist, identity); 25969587Sgreen 260295367Sdesstruct cauthctxt { 26169587Sgreen const char *server_user; 26276262Sgreen const char *local_user; 26369587Sgreen const char *host; 26469587Sgreen const char *service; 265295367Sdes struct cauthmethod *method; 266215116Sdes sig_atomic_t success; 26776262Sgreen char *authlist; 268295367Sdes int attempt; 26976262Sgreen /* pubkey */ 270295367Sdes struct idlist keys; 271295367Sdes int agent_fd; 27276262Sgreen /* hostbased */ 27398684Sdes Sensitive *sensitive; 274295367Sdes char *oktypes, *ktypes; 275295367Sdes const char *active_ktype; 27692559Sdes /* kbd-interactive */ 27792559Sdes int info_req_seen; 278124211Sdes /* generic */ 279124211Sdes void *methoddata; 28069587Sgreen}; 281295367Sdes 282295367Sdesstruct cauthmethod { 28369587Sgreen char *name; /* string to compare against server's list */ 28469587Sgreen int (*userauth)(Authctxt *authctxt); 285192595Sdes void (*cleanup)(Authctxt *authctxt); 28669587Sgreen int *enabled; /* flag in option struct that enables method */ 28769587Sgreen int *batch_flag; /* flag in option struct that disables method */ 28869587Sgreen}; 28969587Sgreen 290296853Sdesint input_userauth_service_accept(int, u_int32_t, void *); 291296853Sdesint input_userauth_ext_info(int, u_int32_t, void *); 292295367Sdesint input_userauth_success(int, u_int32_t, void *); 293295367Sdesint input_userauth_success_unexpected(int, u_int32_t, void *); 294295367Sdesint input_userauth_failure(int, u_int32_t, void *); 295295367Sdesint input_userauth_banner(int, u_int32_t, void *); 296295367Sdesint input_userauth_error(int, u_int32_t, void *); 297295367Sdesint input_userauth_info_req(int, u_int32_t, void *); 298295367Sdesint input_userauth_pk_ok(int, u_int32_t, void *); 299295367Sdesint input_userauth_passwd_changereq(int, u_int32_t, void *); 30069587Sgreen 30192559Sdesint userauth_none(Authctxt *); 30292559Sdesint userauth_pubkey(Authctxt *); 30392559Sdesint userauth_passwd(Authctxt *); 30492559Sdesint userauth_kbdint(Authctxt *); 30592559Sdesint userauth_hostbased(Authctxt *); 30669587Sgreen 307124211Sdes#ifdef GSSAPI 308124211Sdesint userauth_gssapi(Authctxt *authctxt); 309295367Sdesint input_gssapi_response(int type, u_int32_t, void *); 310295367Sdesint input_gssapi_token(int type, u_int32_t, void *); 311295367Sdesint input_gssapi_hash(int type, u_int32_t, void *); 312295367Sdesint input_gssapi_error(int, u_int32_t, void *); 313295367Sdesint input_gssapi_errtok(int, u_int32_t, void *); 314124211Sdes#endif 315124211Sdes 31692559Sdesvoid userauth(Authctxt *, char *); 31776262Sgreen 318124211Sdesstatic int sign_and_send_pubkey(Authctxt *, Identity *); 319124211Sdesstatic void pubkey_prepare(Authctxt *); 320124211Sdesstatic void pubkey_cleanup(Authctxt *); 321296853Sdesstatic Key *load_identity_file(Identity *); 32276262Sgreen 32392559Sdesstatic Authmethod *authmethod_get(char *authlist); 32492559Sdesstatic Authmethod *authmethod_lookup(const char *name); 32592559Sdesstatic char *authmethods_get(void); 32669587Sgreen 32769587SgreenAuthmethod authmethods[] = { 328124211Sdes#ifdef GSSAPI 329126277Sdes {"gssapi-with-mic", 330124211Sdes userauth_gssapi, 331192595Sdes NULL, 332124211Sdes &options.gss_authentication, 333124211Sdes NULL}, 334124211Sdes#endif 33592559Sdes {"hostbased", 33692559Sdes userauth_hostbased, 337192595Sdes NULL, 33892559Sdes &options.hostbased_authentication, 33992559Sdes NULL}, 34069587Sgreen {"publickey", 34169587Sgreen userauth_pubkey, 342192595Sdes NULL, 34376262Sgreen &options.pubkey_authentication, 34469587Sgreen NULL}, 34592559Sdes {"keyboard-interactive", 34692559Sdes userauth_kbdint, 347192595Sdes NULL, 34892559Sdes &options.kbd_interactive_authentication, 34992559Sdes &options.batch_mode}, 35069587Sgreen {"password", 35169587Sgreen userauth_passwd, 352192595Sdes NULL, 35369587Sgreen &options.password_authentication, 35469587Sgreen &options.batch_mode}, 35569587Sgreen {"none", 35669587Sgreen userauth_none, 35769587Sgreen NULL, 358192595Sdes NULL, 35969587Sgreen NULL}, 360192595Sdes {NULL, NULL, NULL, NULL, NULL} 36169587Sgreen}; 36269587Sgreen 36369587Sgreenvoid 36476262Sgreenssh_userauth2(const char *local_user, const char *server_user, char *host, 36598684Sdes Sensitive *sensitive) 36669587Sgreen{ 367296853Sdes struct ssh *ssh = active_state; 36869587Sgreen Authctxt authctxt; 369296853Sdes int r; 37069587Sgreen 37192559Sdes if (options.challenge_response_authentication) 37276262Sgreen options.kbd_interactive_authentication = 1; 37376262Sgreen if (options.preferred_authentications == NULL) 37476262Sgreen options.preferred_authentications = authmethods_get(); 37576262Sgreen 37669587Sgreen /* setup authentication context */ 37792559Sdes memset(&authctxt, 0, sizeof(authctxt)); 378124211Sdes pubkey_prepare(&authctxt); 37969587Sgreen authctxt.server_user = server_user; 38076262Sgreen authctxt.local_user = local_user; 38169587Sgreen authctxt.host = host; 38269587Sgreen authctxt.service = "ssh-connection"; /* service name */ 38369587Sgreen authctxt.success = 0; 38469587Sgreen authctxt.method = authmethod_lookup("none"); 38576262Sgreen authctxt.authlist = NULL; 386124211Sdes authctxt.methoddata = NULL; 38798684Sdes authctxt.sensitive = sensitive; 388295367Sdes authctxt.active_ktype = authctxt.oktypes = authctxt.ktypes = NULL; 38992559Sdes authctxt.info_req_seen = 0; 390295367Sdes authctxt.agent_fd = -1; 39169587Sgreen if (authctxt.method == NULL) 39269587Sgreen fatal("ssh_userauth2: internal error: cannot send userauth none request"); 39369587Sgreen 394296853Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 || 395296853Sdes (r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 || 396296853Sdes (r = sshpkt_send(ssh)) != 0) 397296853Sdes fatal("%s: %s", __func__, ssh_err(r)); 39869587Sgreen 399296853Sdes ssh_dispatch_init(ssh, &input_userauth_error); 400296853Sdes ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info); 401296853Sdes ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept); 402296853Sdes ssh_dispatch_run(ssh, DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ 40369587Sgreen 404124211Sdes pubkey_cleanup(&authctxt); 405296853Sdes ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); 40669587Sgreen 407113911Sdes debug("Authentication succeeded (%s).", authctxt.method->name); 40869587Sgreen} 409124211Sdes 410296853Sdes/* ARGSUSED */ 411296853Sdesint 412296853Sdesinput_userauth_service_accept(int type, u_int32_t seqnr, void *ctxt) 413296853Sdes{ 414296853Sdes Authctxt *authctxt = ctxt; 415296853Sdes struct ssh *ssh = active_state; 416296853Sdes int r; 417296853Sdes 418296853Sdes if (ssh_packet_remaining(ssh) > 0) { 419296853Sdes char *reply; 420296853Sdes 421296853Sdes if ((r = sshpkt_get_cstring(ssh, &reply, NULL)) != 0) 422296853Sdes goto out; 423296853Sdes debug2("service_accept: %s", reply); 424296853Sdes free(reply); 425296853Sdes } else { 426296853Sdes debug2("buggy server: service_accept w/o service"); 427296853Sdes } 428296853Sdes if ((r = sshpkt_get_end(ssh)) != 0) 429296853Sdes goto out; 430296853Sdes debug("SSH2_MSG_SERVICE_ACCEPT received"); 431296853Sdes 432296853Sdes /* initial userauth request */ 433296853Sdes userauth_none(authctxt); 434296853Sdes 435296853Sdes ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error); 436296853Sdes ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); 437296853Sdes ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); 438296853Sdes ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); 439296853Sdes r = 0; 440296853Sdes out: 441296853Sdes return r; 442296853Sdes} 443296853Sdes 444296853Sdes/* ARGSUSED */ 445296853Sdesint 446296853Sdesinput_userauth_ext_info(int type, u_int32_t seqnr, void *ctxt) 447296853Sdes{ 448296853Sdes return kex_input_ext_info(type, seqnr, active_state); 449296853Sdes} 450296853Sdes 45169587Sgreenvoid 45276262Sgreenuserauth(Authctxt *authctxt, char *authlist) 45376262Sgreen{ 454192595Sdes if (authctxt->method != NULL && authctxt->method->cleanup != NULL) 455192595Sdes authctxt->method->cleanup(authctxt); 456192595Sdes 457255767Sdes free(authctxt->methoddata); 458255767Sdes authctxt->methoddata = NULL; 45976262Sgreen if (authlist == NULL) { 46076262Sgreen authlist = authctxt->authlist; 46176262Sgreen } else { 462255767Sdes free(authctxt->authlist); 46376262Sgreen authctxt->authlist = authlist; 46476262Sgreen } 46576262Sgreen for (;;) { 46676262Sgreen Authmethod *method = authmethod_get(authlist); 46776262Sgreen if (method == NULL) 46876262Sgreen fatal("Permission denied (%s).", authlist); 46976262Sgreen authctxt->method = method; 470124211Sdes 471124211Sdes /* reset the per method handler */ 472124211Sdes dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN, 473124211Sdes SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL); 474124211Sdes 475124211Sdes /* and try new method */ 47676262Sgreen if (method->userauth(authctxt) != 0) { 47776262Sgreen debug2("we sent a %s packet, wait for reply", method->name); 47876262Sgreen break; 47976262Sgreen } else { 48076262Sgreen debug2("we did not send a packet, disable method"); 48176262Sgreen method->enabled = NULL; 48276262Sgreen } 48376262Sgreen } 48476262Sgreen} 48599063Sdes 486192595Sdes/* ARGSUSED */ 487295367Sdesint 48892559Sdesinput_userauth_error(int type, u_int32_t seq, void *ctxt) 48969587Sgreen{ 49076262Sgreen fatal("input_userauth_error: bad message during authentication: " 491149753Sdes "type %d", type); 492295367Sdes return 0; 49369587Sgreen} 49499063Sdes 495192595Sdes/* ARGSUSED */ 496295367Sdesint 49792559Sdesinput_userauth_banner(int type, u_int32_t seq, void *ctxt) 49876262Sgreen{ 499181111Sdes char *msg, *raw, *lang; 500181111Sdes u_int len; 501126277Sdes 50276262Sgreen debug3("input_userauth_banner"); 503181111Sdes raw = packet_get_string(&len); 50476262Sgreen lang = packet_get_string(NULL); 505192595Sdes if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) { 506181111Sdes if (len > 65536) 507181111Sdes len = 65536; 508183336Sdes msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */ 509204917Sdes strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL|VIS_NOSLASH); 510126277Sdes fprintf(stderr, "%s", msg); 511255767Sdes free(msg); 512181111Sdes } 513255767Sdes free(raw); 514255767Sdes free(lang); 515295367Sdes return 0; 51676262Sgreen} 51799063Sdes 518192595Sdes/* ARGSUSED */ 519295367Sdesint 52092559Sdesinput_userauth_success(int type, u_int32_t seq, void *ctxt) 52169587Sgreen{ 52269587Sgreen Authctxt *authctxt = ctxt; 523204917Sdes 52469587Sgreen if (authctxt == NULL) 52569587Sgreen fatal("input_userauth_success: no authentication context"); 526255767Sdes free(authctxt->authlist); 527255767Sdes authctxt->authlist = NULL; 528204917Sdes if (authctxt->method != NULL && authctxt->method->cleanup != NULL) 529204917Sdes authctxt->method->cleanup(authctxt); 530255767Sdes free(authctxt->methoddata); 531255767Sdes authctxt->methoddata = NULL; 53269587Sgreen authctxt->success = 1; /* break out */ 533295367Sdes return 0; 53469587Sgreen} 53599063Sdes 536295367Sdesint 537204917Sdesinput_userauth_success_unexpected(int type, u_int32_t seq, void *ctxt) 538204917Sdes{ 539204917Sdes Authctxt *authctxt = ctxt; 540204917Sdes 541204917Sdes if (authctxt == NULL) 542204917Sdes fatal("%s: no authentication context", __func__); 543204917Sdes 544204917Sdes fatal("Unexpected authentication success during %s.", 545204917Sdes authctxt->method->name); 546295367Sdes return 0; 547204917Sdes} 548204917Sdes 549192595Sdes/* ARGSUSED */ 550295367Sdesint 55192559Sdesinput_userauth_failure(int type, u_int32_t seq, void *ctxt) 55269587Sgreen{ 55369587Sgreen Authctxt *authctxt = ctxt; 55469587Sgreen char *authlist = NULL; 55569587Sgreen int partial; 55669587Sgreen 55769587Sgreen if (authctxt == NULL) 55869587Sgreen fatal("input_userauth_failure: no authentication context"); 55969587Sgreen 56069587Sgreen authlist = packet_get_string(NULL); 56169587Sgreen partial = packet_get_char(); 56292559Sdes packet_check_eom(); 56369587Sgreen 564255767Sdes if (partial != 0) { 565124211Sdes logit("Authenticated with partial success."); 566255767Sdes /* reset state */ 567255767Sdes pubkey_cleanup(authctxt); 568255767Sdes pubkey_prepare(authctxt); 569255767Sdes } 570113911Sdes debug("Authentications that can continue: %s", authlist); 57169587Sgreen 57276262Sgreen userauth(authctxt, authlist); 573295367Sdes return 0; 57476262Sgreen} 575192595Sdes 576192595Sdes/* ARGSUSED */ 577295367Sdesint 57892559Sdesinput_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) 57976262Sgreen{ 58076262Sgreen Authctxt *authctxt = ctxt; 58176262Sgreen Key *key = NULL; 582124211Sdes Identity *id = NULL; 58376262Sgreen Buffer b; 58492559Sdes int pktype, sent = 0; 58592559Sdes u_int alen, blen; 58692559Sdes char *pkalg, *fp; 58792559Sdes u_char *pkblob; 58876262Sgreen 58976262Sgreen if (authctxt == NULL) 59076262Sgreen fatal("input_userauth_pk_ok: no authentication context"); 59176262Sgreen if (datafellows & SSH_BUG_PKOK) { 59276262Sgreen /* this is similar to SSH_BUG_PKAUTH */ 59376262Sgreen debug2("input_userauth_pk_ok: SSH_BUG_PKOK"); 59476262Sgreen pkblob = packet_get_string(&blen); 59576262Sgreen buffer_init(&b); 59676262Sgreen buffer_append(&b, pkblob, blen); 59776262Sgreen pkalg = buffer_get_string(&b, &alen); 59876262Sgreen buffer_free(&b); 59976262Sgreen } else { 60076262Sgreen pkalg = packet_get_string(&alen); 60176262Sgreen pkblob = packet_get_string(&blen); 60276262Sgreen } 60392559Sdes packet_check_eom(); 60476262Sgreen 605124211Sdes debug("Server accepts key: pkalg %s blen %u", pkalg, blen); 60676262Sgreen 607124211Sdes if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { 608124211Sdes debug("unknown pkalg %s", pkalg); 609124211Sdes goto done; 610124211Sdes } 611124211Sdes if ((key = key_from_blob(pkblob, blen)) == NULL) { 612124211Sdes debug("no key from blob. pkalg %s", pkalg); 613124211Sdes goto done; 614124211Sdes } 615124211Sdes if (key->type != pktype) { 616124211Sdes error("input_userauth_pk_ok: type mismatch " 617124211Sdes "for decoded key (received %d, expected %d)", 618124211Sdes key->type, pktype); 619124211Sdes goto done; 620124211Sdes } 621295367Sdes if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, 622295367Sdes SSH_FP_DEFAULT)) == NULL) 623295367Sdes goto done; 624124211Sdes debug2("input_userauth_pk_ok: fp %s", fp); 625255767Sdes free(fp); 626124211Sdes 627126277Sdes /* 628126277Sdes * search keys in the reverse order, because last candidate has been 629126277Sdes * moved to the end of the queue. this also avoids confusion by 630126277Sdes * duplicate keys 631126277Sdes */ 632137019Sdes TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { 633124211Sdes if (key_equal(key, id->key)) { 634124211Sdes sent = sign_and_send_pubkey(authctxt, id); 63569587Sgreen break; 63669587Sgreen } 637124211Sdes } 638124211Sdesdone: 63976262Sgreen if (key != NULL) 64076262Sgreen key_free(key); 641255767Sdes free(pkalg); 642255767Sdes free(pkblob); 64376262Sgreen 644106130Sdes /* try another method if we did not send a packet */ 64576262Sgreen if (sent == 0) 64676262Sgreen userauth(authctxt, NULL); 647295367Sdes return 0; 648124211Sdes} 64976262Sgreen 650124211Sdes#ifdef GSSAPI 651126277Sdesint 652124211Sdesuserauth_gssapi(Authctxt *authctxt) 653124211Sdes{ 654124211Sdes Gssctxt *gssctxt = NULL; 655126277Sdes static gss_OID_set gss_supported = NULL; 656149753Sdes static u_int mech = 0; 657124211Sdes OM_uint32 min; 658124211Sdes int ok = 0; 659124211Sdes 660124211Sdes /* Try one GSSAPI method at a time, rather than sending them all at 661124211Sdes * once. */ 662124211Sdes 663126277Sdes if (gss_supported == NULL) 664126277Sdes gss_indicate_mechs(&min, &gss_supported); 665124211Sdes 666124211Sdes /* Check to see if the mechanism is usable before we offer it */ 667126277Sdes while (mech < gss_supported->count && !ok) { 668124211Sdes /* My DER encoding requires length<128 */ 669126277Sdes if (gss_supported->elements[mech].length < 128 && 670162856Sdes ssh_gssapi_check_mechanism(&gssctxt, 671162856Sdes &gss_supported->elements[mech], authctxt->host)) { 672124211Sdes ok = 1; /* Mechanism works */ 673124211Sdes } else { 674124211Sdes mech++; 675124211Sdes } 676124211Sdes } 677124211Sdes 678149753Sdes if (!ok) 679149753Sdes return 0; 680124211Sdes 681124211Sdes authctxt->methoddata=(void *)gssctxt; 682124211Sdes 683124211Sdes packet_start(SSH2_MSG_USERAUTH_REQUEST); 684124211Sdes packet_put_cstring(authctxt->server_user); 685124211Sdes packet_put_cstring(authctxt->service); 686124211Sdes packet_put_cstring(authctxt->method->name); 687124211Sdes 688124211Sdes packet_put_int(1); 689124211Sdes 690126277Sdes packet_put_int((gss_supported->elements[mech].length) + 2); 691126277Sdes packet_put_char(SSH_GSS_OIDTYPE); 692126277Sdes packet_put_char(gss_supported->elements[mech].length); 693126277Sdes packet_put_raw(gss_supported->elements[mech].elements, 694126277Sdes gss_supported->elements[mech].length); 695124211Sdes 696124211Sdes packet_send(); 697124211Sdes 698124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response); 699124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); 700124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error); 701124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); 702124211Sdes 703124211Sdes mech++; /* Move along to next candidate */ 704124211Sdes 705124211Sdes return 1; 70669587Sgreen} 70769587Sgreen 708126277Sdesstatic OM_uint32 709126277Sdesprocess_gssapi_token(void *ctxt, gss_buffer_t recv_tok) 710126277Sdes{ 711126277Sdes Authctxt *authctxt = ctxt; 712126277Sdes Gssctxt *gssctxt = authctxt->methoddata; 713126277Sdes gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 714149753Sdes gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; 715149753Sdes gss_buffer_desc gssbuf; 716126277Sdes OM_uint32 status, ms, flags; 717126277Sdes Buffer b; 718126277Sdes 719126277Sdes status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, 720126277Sdes recv_tok, &send_tok, &flags); 721126277Sdes 722126277Sdes if (send_tok.length > 0) { 723126277Sdes if (GSS_ERROR(status)) 724126277Sdes packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); 725126277Sdes else 726126277Sdes packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); 727126277Sdes 728126277Sdes packet_put_string(send_tok.value, send_tok.length); 729126277Sdes packet_send(); 730126277Sdes gss_release_buffer(&ms, &send_tok); 731126277Sdes } 732126277Sdes 733126277Sdes if (status == GSS_S_COMPLETE) { 734126277Sdes /* send either complete or MIC, depending on mechanism */ 735126277Sdes if (!(flags & GSS_C_INTEG_FLAG)) { 736126277Sdes packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); 737126277Sdes packet_send(); 738126277Sdes } else { 739126277Sdes ssh_gssapi_buildmic(&b, authctxt->server_user, 740126277Sdes authctxt->service, "gssapi-with-mic"); 741126277Sdes 742126277Sdes gssbuf.value = buffer_ptr(&b); 743126277Sdes gssbuf.length = buffer_len(&b); 744126277Sdes 745126277Sdes status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic); 746126277Sdes 747126277Sdes if (!GSS_ERROR(status)) { 748126277Sdes packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC); 749126277Sdes packet_put_string(mic.value, mic.length); 750126277Sdes 751126277Sdes packet_send(); 752126277Sdes } 753126277Sdes 754126277Sdes buffer_free(&b); 755126277Sdes gss_release_buffer(&ms, &mic); 756126277Sdes } 757126277Sdes } 758126277Sdes 759126277Sdes return status; 760126277Sdes} 761126277Sdes 762192595Sdes/* ARGSUSED */ 763295367Sdesint 764124211Sdesinput_gssapi_response(int type, u_int32_t plen, void *ctxt) 765124211Sdes{ 766124211Sdes Authctxt *authctxt = ctxt; 767124211Sdes Gssctxt *gssctxt; 768124211Sdes int oidlen; 769124211Sdes char *oidv; 770124211Sdes 771124211Sdes if (authctxt == NULL) 772124211Sdes fatal("input_gssapi_response: no authentication context"); 773124211Sdes gssctxt = authctxt->methoddata; 774124211Sdes 775124211Sdes /* Setup our OID */ 776124211Sdes oidv = packet_get_string(&oidlen); 777124211Sdes 778126277Sdes if (oidlen <= 2 || 779126277Sdes oidv[0] != SSH_GSS_OIDTYPE || 780126277Sdes oidv[1] != oidlen - 2) { 781255767Sdes free(oidv); 782126277Sdes debug("Badly encoded mechanism OID received"); 783126277Sdes userauth(authctxt, NULL); 784295367Sdes return 0; 785124211Sdes } 786124211Sdes 787126277Sdes if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) 788126277Sdes fatal("Server returned different OID than expected"); 789126277Sdes 790124211Sdes packet_check_eom(); 791124211Sdes 792255767Sdes free(oidv); 793124211Sdes 794126277Sdes if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) { 795124211Sdes /* Start again with next method on list */ 796124211Sdes debug("Trying to start again"); 797124211Sdes userauth(authctxt, NULL); 798295367Sdes return 0; 799124211Sdes } 800295367Sdes return 0; 801124211Sdes} 802124211Sdes 803192595Sdes/* ARGSUSED */ 804295367Sdesint 805124211Sdesinput_gssapi_token(int type, u_int32_t plen, void *ctxt) 806124211Sdes{ 807124211Sdes Authctxt *authctxt = ctxt; 808124211Sdes gss_buffer_desc recv_tok; 809126277Sdes OM_uint32 status; 810124211Sdes u_int slen; 811124211Sdes 812124211Sdes if (authctxt == NULL) 813124211Sdes fatal("input_gssapi_response: no authentication context"); 814124211Sdes 815124211Sdes recv_tok.value = packet_get_string(&slen); 816124211Sdes recv_tok.length = slen; /* safe typecast */ 817124211Sdes 818124211Sdes packet_check_eom(); 819124211Sdes 820126277Sdes status = process_gssapi_token(ctxt, &recv_tok); 821124211Sdes 822255767Sdes free(recv_tok.value); 823124211Sdes 824124211Sdes if (GSS_ERROR(status)) { 825124211Sdes /* Start again with the next method in the list */ 826124211Sdes userauth(authctxt, NULL); 827295367Sdes return 0; 828124211Sdes } 829295367Sdes return 0; 830124211Sdes} 831124211Sdes 832192595Sdes/* ARGSUSED */ 833295367Sdesint 834124211Sdesinput_gssapi_errtok(int type, u_int32_t plen, void *ctxt) 835124211Sdes{ 836124211Sdes Authctxt *authctxt = ctxt; 837124211Sdes Gssctxt *gssctxt; 838124211Sdes gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 839124211Sdes gss_buffer_desc recv_tok; 840255767Sdes OM_uint32 ms; 841124211Sdes u_int len; 842124211Sdes 843124211Sdes if (authctxt == NULL) 844124211Sdes fatal("input_gssapi_response: no authentication context"); 845124211Sdes gssctxt = authctxt->methoddata; 846124211Sdes 847124211Sdes recv_tok.value = packet_get_string(&len); 848124211Sdes recv_tok.length = len; 849124211Sdes 850124211Sdes packet_check_eom(); 851124211Sdes 852124211Sdes /* Stick it into GSSAPI and see what it says */ 853255767Sdes (void)ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, 854149753Sdes &recv_tok, &send_tok, NULL); 855124211Sdes 856255767Sdes free(recv_tok.value); 857124211Sdes gss_release_buffer(&ms, &send_tok); 858124211Sdes 859124211Sdes /* Server will be returning a failed packet after this one */ 860295367Sdes return 0; 861124211Sdes} 862124211Sdes 863192595Sdes/* ARGSUSED */ 864295367Sdesint 865124211Sdesinput_gssapi_error(int type, u_int32_t plen, void *ctxt) 866124211Sdes{ 867124211Sdes char *msg; 868124211Sdes char *lang; 869124211Sdes 870255767Sdes /* maj */(void)packet_get_int(); 871255767Sdes /* min */(void)packet_get_int(); 872124211Sdes msg=packet_get_string(NULL); 873124211Sdes lang=packet_get_string(NULL); 874124211Sdes 875124211Sdes packet_check_eom(); 876124211Sdes 877157019Sdes debug("Server GSSAPI Error:\n%s", msg); 878255767Sdes free(msg); 879255767Sdes free(lang); 880295367Sdes return 0; 881124211Sdes} 882124211Sdes#endif /* GSSAPI */ 883124211Sdes 88460573Skrisint 88569587Sgreenuserauth_none(Authctxt *authctxt) 88660573Skris{ 88769587Sgreen /* initial userauth request */ 88869587Sgreen packet_start(SSH2_MSG_USERAUTH_REQUEST); 88969587Sgreen packet_put_cstring(authctxt->server_user); 89069587Sgreen packet_put_cstring(authctxt->service); 89169587Sgreen packet_put_cstring(authctxt->method->name); 89269587Sgreen packet_send(); 89369587Sgreen return 1; 89469587Sgreen} 89569587Sgreen 89669587Sgreenint 89769587Sgreenuserauth_passwd(Authctxt *authctxt) 89869587Sgreen{ 89960573Skris static int attempt = 0; 90098684Sdes char prompt[150]; 90160573Skris char *password; 902204917Sdes const char *host = options.host_key_alias ? options.host_key_alias : 903204917Sdes authctxt->host; 90460573Skris 90565668Skris if (attempt++ >= options.number_of_password_prompts) 90660573Skris return 0; 90760573Skris 90892559Sdes if (attempt != 1) 90965668Skris error("Permission denied, please try again."); 91065668Skris 91176262Sgreen snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", 912204917Sdes authctxt->server_user, host); 91360573Skris password = read_passphrase(prompt, 0); 91460573Skris packet_start(SSH2_MSG_USERAUTH_REQUEST); 91569587Sgreen packet_put_cstring(authctxt->server_user); 91669587Sgreen packet_put_cstring(authctxt->service); 91769587Sgreen packet_put_cstring(authctxt->method->name); 91860573Skris packet_put_char(0); 91993704Sdes packet_put_cstring(password); 920264377Sdes explicit_bzero(password, strlen(password)); 921255767Sdes free(password); 92292559Sdes packet_add_padding(64); 92360573Skris packet_send(); 92498684Sdes 92598684Sdes dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 92698684Sdes &input_userauth_passwd_changereq); 92798684Sdes 92860573Skris return 1; 92960573Skris} 930192595Sdes 93198684Sdes/* 93298684Sdes * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST 93398684Sdes */ 934192595Sdes/* ARGSUSED */ 935295367Sdesint 93698941Sdesinput_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) 93798684Sdes{ 93898684Sdes Authctxt *authctxt = ctxt; 93998684Sdes char *info, *lang, *password = NULL, *retype = NULL; 94098684Sdes char prompt[150]; 941204917Sdes const char *host = options.host_key_alias ? options.host_key_alias : 942204917Sdes authctxt->host; 94360573Skris 94498684Sdes debug2("input_userauth_passwd_changereq"); 94598684Sdes 94698684Sdes if (authctxt == NULL) 94798684Sdes fatal("input_userauth_passwd_changereq: " 94898684Sdes "no authentication context"); 94998684Sdes 95098684Sdes info = packet_get_string(NULL); 95198684Sdes lang = packet_get_string(NULL); 95298684Sdes if (strlen(info) > 0) 953124211Sdes logit("%s", info); 954255767Sdes free(info); 955255767Sdes free(lang); 95698684Sdes packet_start(SSH2_MSG_USERAUTH_REQUEST); 95798684Sdes packet_put_cstring(authctxt->server_user); 95898684Sdes packet_put_cstring(authctxt->service); 95998684Sdes packet_put_cstring(authctxt->method->name); 96098684Sdes packet_put_char(1); /* additional info */ 96198684Sdes snprintf(prompt, sizeof(prompt), 96298684Sdes "Enter %.30s@%.128s's old password: ", 963204917Sdes authctxt->server_user, host); 96498684Sdes password = read_passphrase(prompt, 0); 96598684Sdes packet_put_cstring(password); 966264377Sdes explicit_bzero(password, strlen(password)); 967255767Sdes free(password); 96898684Sdes password = NULL; 96998684Sdes while (password == NULL) { 97098684Sdes snprintf(prompt, sizeof(prompt), 97198684Sdes "Enter %.30s@%.128s's new password: ", 972204917Sdes authctxt->server_user, host); 97398684Sdes password = read_passphrase(prompt, RP_ALLOW_EOF); 97498684Sdes if (password == NULL) { 97598684Sdes /* bail out */ 976295367Sdes return 0; 97798684Sdes } 97898684Sdes snprintf(prompt, sizeof(prompt), 97998684Sdes "Retype %.30s@%.128s's new password: ", 980204917Sdes authctxt->server_user, host); 98198684Sdes retype = read_passphrase(prompt, 0); 98298684Sdes if (strcmp(password, retype) != 0) { 983264377Sdes explicit_bzero(password, strlen(password)); 984255767Sdes free(password); 985124211Sdes logit("Mismatch; try again, EOF to quit."); 98698684Sdes password = NULL; 98798684Sdes } 988264377Sdes explicit_bzero(retype, strlen(retype)); 989255767Sdes free(retype); 99098684Sdes } 99198684Sdes packet_put_cstring(password); 992264377Sdes explicit_bzero(password, strlen(password)); 993255767Sdes free(password); 99498684Sdes packet_add_padding(64); 99598684Sdes packet_send(); 99698684Sdes 99798684Sdes dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 99898684Sdes &input_userauth_passwd_changereq); 999295367Sdes return 0; 100098684Sdes} 100198684Sdes 1002296853Sdesstatic const char * 1003296853Sdesidentity_sign_encode(struct identity *id) 1004296853Sdes{ 1005296853Sdes struct ssh *ssh = active_state; 1006296853Sdes 1007296853Sdes if (id->key->type == KEY_RSA) { 1008296853Sdes switch (ssh->kex->rsa_sha2) { 1009296853Sdes case 256: 1010296853Sdes return "rsa-sha2-256"; 1011296853Sdes case 512: 1012296853Sdes return "rsa-sha2-512"; 1013296853Sdes } 1014296853Sdes } 1015296853Sdes return key_ssh_name(id->key); 1016296853Sdes} 1017296853Sdes 1018124211Sdesstatic int 1019295367Sdesidentity_sign(struct identity *id, u_char **sigp, size_t *lenp, 1020295367Sdes const u_char *data, size_t datalen, u_int compat) 102176262Sgreen{ 1022124211Sdes Key *prv; 1023124211Sdes int ret; 1024296853Sdes const char *alg; 102598684Sdes 1026296853Sdes alg = identity_sign_encode(id); 1027296853Sdes 1028124211Sdes /* the agent supports this key */ 1029296853Sdes if (id->agent_fd != -1) 1030295367Sdes return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, 1031296853Sdes data, datalen, alg, compat); 1032295367Sdes 1033124211Sdes /* 1034124211Sdes * we have already loaded the private key or 1035124211Sdes * the private key is stored in external hardware 1036124211Sdes */ 1037295367Sdes if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) 1038296853Sdes return (sshkey_sign(id->key, sigp, lenp, data, datalen, alg, 1039295367Sdes compat)); 1040124211Sdes /* load the private key from the file */ 1041296853Sdes if ((prv = load_identity_file(id)) == NULL) 1042296853Sdes return SSH_ERR_KEY_NOT_FOUND; 1043296853Sdes ret = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); 1044295367Sdes sshkey_free(prv); 1045124211Sdes return (ret); 104676262Sgreen} 104776262Sgreen 104892559Sdesstatic int 1049124211Sdessign_and_send_pubkey(Authctxt *authctxt, Identity *id) 105060573Skris{ 105160573Skris Buffer b; 1052296853Sdes Identity *private_id; 105376262Sgreen u_char *blob, *signature; 1054295367Sdes size_t slen; 1055296853Sdes u_int bloblen, skip = 0; 1056296853Sdes int matched, ret = -1, have_sig = 1; 1057215116Sdes char *fp; 105860573Skris 1059295367Sdes if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, 1060295367Sdes SSH_FP_DEFAULT)) == NULL) 1061295367Sdes return 0; 1062296853Sdes debug3("%s: %s %s", __func__, key_type(id->key), fp); 1063255767Sdes free(fp); 106460573Skris 1065124211Sdes if (key_to_blob(id->key, &blob, &bloblen) == 0) { 106676262Sgreen /* we cannot handle this key */ 106776262Sgreen debug3("sign_and_send_pubkey: cannot handle key"); 106876262Sgreen return 0; 106976262Sgreen } 107060573Skris /* data to be signed */ 107160573Skris buffer_init(&b); 107269587Sgreen if (datafellows & SSH_OLD_SESSIONID) { 107369587Sgreen buffer_append(&b, session_id2, session_id2_len); 107476262Sgreen skip = session_id2_len; 107569587Sgreen } else { 107665668Skris buffer_put_string(&b, session_id2, session_id2_len); 107765668Skris skip = buffer_len(&b); 107865668Skris } 107960573Skris buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 108069587Sgreen buffer_put_cstring(&b, authctxt->server_user); 108160573Skris buffer_put_cstring(&b, 108276262Sgreen datafellows & SSH_BUG_PKSERVICE ? 108360573Skris "ssh-userauth" : 108469587Sgreen authctxt->service); 108576262Sgreen if (datafellows & SSH_BUG_PKAUTH) { 108676262Sgreen buffer_put_char(&b, have_sig); 108776262Sgreen } else { 108876262Sgreen buffer_put_cstring(&b, authctxt->method->name); 108976262Sgreen buffer_put_char(&b, have_sig); 1090296853Sdes buffer_put_cstring(&b, identity_sign_encode(id)); 109176262Sgreen } 109260573Skris buffer_put_string(&b, blob, bloblen); 109360573Skris 1094296853Sdes /* 1095296853Sdes * If the key is an certificate, try to find a matching private key 1096296853Sdes * and use it to complete the signature. 1097296853Sdes * If no such private key exists, return failure and continue with 1098296853Sdes * other methods of authentication. 1099296853Sdes */ 1100296853Sdes if (key_is_cert(id->key)) { 1101296853Sdes matched = 0; 1102296853Sdes TAILQ_FOREACH(private_id, &authctxt->keys, next) { 1103296853Sdes if (sshkey_equal_public(id->key, private_id->key) && 1104296853Sdes id->key->type != private_id->key->type) { 1105296853Sdes id = private_id; 1106296853Sdes matched = 1; 1107296853Sdes break; 1108296853Sdes } 1109296853Sdes } 1110296853Sdes if (matched) { 1111296853Sdes debug2("%s: using private key \"%s\"%s for " 1112296853Sdes "certificate", __func__, id->filename, 1113296853Sdes id->agent_fd != -1 ? " from agent" : ""); 1114296853Sdes } else { 1115296853Sdes /* XXX maybe verbose/error? */ 1116296853Sdes debug("%s: no private key for certificate " 1117296853Sdes "\"%s\"", __func__, id->filename); 1118296853Sdes free(blob); 1119296853Sdes buffer_free(&b); 1120296853Sdes return 0; 1121296853Sdes } 1122296853Sdes } 1123296853Sdes 112460573Skris /* generate signature */ 1125124211Sdes ret = identity_sign(id, &signature, &slen, 1126295367Sdes buffer_ptr(&b), buffer_len(&b), datafellows); 1127295367Sdes if (ret != 0) { 1128296853Sdes if (ret != SSH_ERR_KEY_NOT_FOUND) 1129296853Sdes error("%s: signing failed: %s", __func__, ssh_err(ret)); 1130255767Sdes free(blob); 113165668Skris buffer_free(&b); 113265668Skris return 0; 113365668Skris } 113476262Sgreen#ifdef DEBUG_PK 113560573Skris buffer_dump(&b); 113660573Skris#endif 113776262Sgreen if (datafellows & SSH_BUG_PKSERVICE) { 113860573Skris buffer_clear(&b); 113960573Skris buffer_append(&b, session_id2, session_id2_len); 114076262Sgreen skip = session_id2_len; 114160573Skris buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 114269587Sgreen buffer_put_cstring(&b, authctxt->server_user); 114369587Sgreen buffer_put_cstring(&b, authctxt->service); 114469587Sgreen buffer_put_cstring(&b, authctxt->method->name); 114569587Sgreen buffer_put_char(&b, have_sig); 114676262Sgreen if (!(datafellows & SSH_BUG_PKAUTH)) 1147124211Sdes buffer_put_cstring(&b, key_ssh_name(id->key)); 114860573Skris buffer_put_string(&b, blob, bloblen); 114960573Skris } 1150255767Sdes free(blob); 115176262Sgreen 115260573Skris /* append signature */ 115360573Skris buffer_put_string(&b, signature, slen); 1154255767Sdes free(signature); 115560573Skris 115660573Skris /* skip session id and packet type */ 115765668Skris if (buffer_len(&b) < skip + 1) 115869587Sgreen fatal("userauth_pubkey: internal error"); 115965668Skris buffer_consume(&b, skip + 1); 116060573Skris 116160573Skris /* put remaining data from buffer into packet */ 116260573Skris packet_start(SSH2_MSG_USERAUTH_REQUEST); 116360573Skris packet_put_raw(buffer_ptr(&b), buffer_len(&b)); 116460573Skris buffer_free(&b); 116560573Skris packet_send(); 116665668Skris 116760573Skris return 1; 116860573Skris} 116960573Skris 117092559Sdesstatic int 1171124211Sdessend_pubkey_test(Authctxt *authctxt, Identity *id) 117269587Sgreen{ 117376262Sgreen u_char *blob; 117492559Sdes u_int bloblen, have_sig = 0; 117576262Sgreen 117676262Sgreen debug3("send_pubkey_test"); 117776262Sgreen 1178124211Sdes if (key_to_blob(id->key, &blob, &bloblen) == 0) { 117976262Sgreen /* we cannot handle this key */ 118076262Sgreen debug3("send_pubkey_test: cannot handle key"); 118176262Sgreen return 0; 118276262Sgreen } 118376262Sgreen /* register callback for USERAUTH_PK_OK message */ 118476262Sgreen dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); 118576262Sgreen 118676262Sgreen packet_start(SSH2_MSG_USERAUTH_REQUEST); 118776262Sgreen packet_put_cstring(authctxt->server_user); 118876262Sgreen packet_put_cstring(authctxt->service); 118976262Sgreen packet_put_cstring(authctxt->method->name); 119076262Sgreen packet_put_char(have_sig); 119176262Sgreen if (!(datafellows & SSH_BUG_PKAUTH)) 1192296853Sdes packet_put_cstring(identity_sign_encode(id)); 119376262Sgreen packet_put_string(blob, bloblen); 1194255767Sdes free(blob); 119576262Sgreen packet_send(); 119676262Sgreen return 1; 119769587Sgreen} 119869587Sgreen 119992559Sdesstatic Key * 1200296853Sdesload_identity_file(Identity *id) 120165668Skris{ 1202296853Sdes Key *private = NULL; 1203296853Sdes char prompt[300], *passphrase, *comment; 1204295367Sdes int r, perm_ok = 0, quit = 0, i; 120565668Skris struct stat st; 120665668Skris 1207296853Sdes if (stat(id->filename, &st) < 0) { 1208296853Sdes (id->userprovided ? logit : debug3)("no such identity: %s: %s", 1209296853Sdes id->filename, strerror(errno)); 121076262Sgreen return NULL; 121165668Skris } 1212295367Sdes snprintf(prompt, sizeof prompt, 1213296853Sdes "Enter passphrase for key '%.100s': ", id->filename); 1214295367Sdes for (i = 0; i <= options.number_of_password_prompts; i++) { 1215295367Sdes if (i == 0) 1216295367Sdes passphrase = ""; 1217295367Sdes else { 121869587Sgreen passphrase = read_passphrase(prompt, 0); 1219295367Sdes if (*passphrase == '\0') { 122069587Sgreen debug2("no passphrase given, try next key"); 1221295367Sdes free(passphrase); 1222295367Sdes break; 1223295367Sdes } 1224295367Sdes } 1225296853Sdes switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename, 1226296853Sdes passphrase, &private, &comment, &perm_ok))) { 1227295367Sdes case 0: 1228295367Sdes break; 1229295367Sdes case SSH_ERR_KEY_WRONG_PASSPHRASE: 1230295367Sdes if (options.batch_mode) { 123176262Sgreen quit = 1; 1232295367Sdes break; 123369587Sgreen } 1234295367Sdes if (i != 0) 1235295367Sdes debug2("bad passphrase given, try again..."); 1236295367Sdes break; 1237295367Sdes case SSH_ERR_SYSTEM_ERROR: 1238295367Sdes if (errno == ENOENT) { 1239295367Sdes debug2("Load key \"%s\": %s", 1240296853Sdes id->filename, ssh_err(r)); 1241295367Sdes quit = 1; 1242295367Sdes break; 1243295367Sdes } 1244295367Sdes /* FALLTHROUGH */ 1245295367Sdes default: 1246296853Sdes error("Load key \"%s\": %s", id->filename, ssh_err(r)); 1247295367Sdes quit = 1; 1248295367Sdes break; 1249295367Sdes } 1250296853Sdes if (!quit && private != NULL && id->agent_fd == -1 && 1251296853Sdes !(id->key && id->isprivate)) 1252296853Sdes maybe_add_key_to_agent(id->filename, private, comment, 1253296853Sdes passphrase); 1254295367Sdes if (i > 0) { 1255264377Sdes explicit_bzero(passphrase, strlen(passphrase)); 1256255767Sdes free(passphrase); 125769587Sgreen } 1258296853Sdes free(comment); 1259295367Sdes if (private != NULL || quit) 1260295367Sdes break; 126165668Skris } 126276262Sgreen return private; 126376262Sgreen} 126476262Sgreen 1265124211Sdes/* 1266124211Sdes * try keys in the following order: 1267296853Sdes * 1. certificates listed in the config file 1268296853Sdes * 2. other input certificates 1269296853Sdes * 3. agent keys that are found in the config file 1270296853Sdes * 4. other agent keys 1271296853Sdes * 5. keys that are only listed in the config file 1272124211Sdes */ 1273124211Sdesstatic void 1274124211Sdespubkey_prepare(Authctxt *authctxt) 127576262Sgreen{ 1276295367Sdes struct identity *id, *id2, *tmp; 1277295367Sdes struct idlist agent, files, *preferred; 1278295367Sdes struct sshkey *key; 1279296853Sdes int agent_fd = -1, i, r, found; 1280295367Sdes size_t j; 1281295367Sdes struct ssh_identitylist *idlist; 128276262Sgreen 1283124211Sdes TAILQ_INIT(&agent); /* keys from the agent */ 1284124211Sdes TAILQ_INIT(&files); /* keys from the config file */ 1285124211Sdes preferred = &authctxt->keys; 1286124211Sdes TAILQ_INIT(preferred); /* preferred order of keys */ 128792559Sdes 1288248619Sdes /* list of keys stored in the filesystem and PKCS#11 */ 1289124211Sdes for (i = 0; i < options.num_identity_files; i++) { 1290124211Sdes key = options.identity_keys[i]; 1291124211Sdes if (key && key->type == KEY_RSA1) 1292124211Sdes continue; 1293204917Sdes if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER) 1294204917Sdes continue; 1295124211Sdes options.identity_keys[i] = NULL; 1296162856Sdes id = xcalloc(1, sizeof(*id)); 1297296853Sdes id->agent_fd = -1; 1298124211Sdes id->key = key; 1299124211Sdes id->filename = xstrdup(options.identity_files[i]); 1300249016Sdes id->userprovided = options.identity_file_userprovided[i]; 1301124211Sdes TAILQ_INSERT_TAIL(&files, id, next); 1302124211Sdes } 1303248619Sdes /* Prefer PKCS11 keys that are explicitly listed */ 1304248619Sdes TAILQ_FOREACH_SAFE(id, &files, next, tmp) { 1305295367Sdes if (id->key == NULL || (id->key->flags & SSHKEY_FLAG_EXT) == 0) 1306248619Sdes continue; 1307248619Sdes found = 0; 1308248619Sdes TAILQ_FOREACH(id2, &files, next) { 1309248619Sdes if (id2->key == NULL || 1310295367Sdes (id2->key->flags & SSHKEY_FLAG_EXT) == 0) 1311248619Sdes continue; 1312295367Sdes if (sshkey_equal(id->key, id2->key)) { 1313248619Sdes TAILQ_REMOVE(&files, id, next); 1314248619Sdes TAILQ_INSERT_TAIL(preferred, id, next); 1315248619Sdes found = 1; 1316248619Sdes break; 1317248619Sdes } 1318248619Sdes } 1319248619Sdes /* If IdentitiesOnly set and key not found then don't use it */ 1320248619Sdes if (!found && options.identities_only) { 1321248619Sdes TAILQ_REMOVE(&files, id, next); 1322264377Sdes explicit_bzero(id, sizeof(*id)); 1323248619Sdes free(id); 1324248619Sdes } 1325248619Sdes } 1326296853Sdes /* list of certificates specified by user */ 1327296853Sdes for (i = 0; i < options.num_certificate_files; i++) { 1328296853Sdes key = options.certificates[i]; 1329296853Sdes if (!key_is_cert(key) || key->cert == NULL || 1330296853Sdes key->cert->type != SSH2_CERT_TYPE_USER) 1331296853Sdes continue; 1332296853Sdes id = xcalloc(1, sizeof(*id)); 1333296853Sdes id->agent_fd = -1; 1334296853Sdes id->key = key; 1335296853Sdes id->filename = xstrdup(options.certificate_files[i]); 1336296853Sdes id->userprovided = options.certificate_file_userprovided[i]; 1337296853Sdes TAILQ_INSERT_TAIL(preferred, id, next); 1338296853Sdes } 1339124211Sdes /* list of keys supported by the agent */ 1340295367Sdes if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { 1341295367Sdes if (r != SSH_ERR_AGENT_NOT_PRESENT) 1342295367Sdes debug("%s: ssh_get_authentication_socket: %s", 1343295367Sdes __func__, ssh_err(r)); 1344295367Sdes } else if ((r = ssh_fetch_identitylist(agent_fd, 2, &idlist)) != 0) { 1345295367Sdes if (r != SSH_ERR_AGENT_NO_IDENTITIES) 1346295367Sdes debug("%s: ssh_fetch_identitylist: %s", 1347295367Sdes __func__, ssh_err(r)); 1348296853Sdes close(agent_fd); 1349295367Sdes } else { 1350295367Sdes for (j = 0; j < idlist->nkeys; j++) { 1351124211Sdes found = 0; 1352124211Sdes TAILQ_FOREACH(id, &files, next) { 1353295367Sdes /* 1354295367Sdes * agent keys from the config file are 1355295367Sdes * preferred 1356295367Sdes */ 1357295367Sdes if (sshkey_equal(idlist->keys[j], id->key)) { 1358124211Sdes TAILQ_REMOVE(&files, id, next); 1359124211Sdes TAILQ_INSERT_TAIL(preferred, id, next); 1360295367Sdes id->agent_fd = agent_fd; 1361124211Sdes found = 1; 1362124211Sdes break; 1363124211Sdes } 1364124211Sdes } 1365128460Sdes if (!found && !options.identities_only) { 1366162856Sdes id = xcalloc(1, sizeof(*id)); 1367295367Sdes /* XXX "steals" key/comment from idlist */ 1368295367Sdes id->key = idlist->keys[j]; 1369295367Sdes id->filename = idlist->comments[j]; 1370295367Sdes idlist->keys[j] = NULL; 1371295367Sdes idlist->comments[j] = NULL; 1372295367Sdes id->agent_fd = agent_fd; 1373124211Sdes TAILQ_INSERT_TAIL(&agent, id, next); 1374124211Sdes } 1375124211Sdes } 1376295367Sdes ssh_free_identitylist(idlist); 1377124211Sdes /* append remaining agent keys */ 1378124211Sdes for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { 1379124211Sdes TAILQ_REMOVE(&agent, id, next); 1380124211Sdes TAILQ_INSERT_TAIL(preferred, id, next); 1381124211Sdes } 1382295367Sdes authctxt->agent_fd = agent_fd; 1383124211Sdes } 1384124211Sdes /* append remaining keys from the config file */ 1385124211Sdes for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { 1386124211Sdes TAILQ_REMOVE(&files, id, next); 1387124211Sdes TAILQ_INSERT_TAIL(preferred, id, next); 1388124211Sdes } 1389296853Sdes /* finally, filter by PubkeyAcceptedKeyTypes */ 1390296853Sdes TAILQ_FOREACH_SAFE(id, preferred, next, id2) { 1391296853Sdes if (id->key != NULL && 1392296853Sdes match_pattern_list(sshkey_ssh_name(id->key), 1393296853Sdes options.pubkey_key_types, 0) != 1) { 1394296853Sdes debug("Skipping %s key %s - " 1395296853Sdes "not in PubkeyAcceptedKeyTypes", 1396296853Sdes sshkey_ssh_name(id->key), id->filename); 1397296853Sdes TAILQ_REMOVE(preferred, id, next); 1398296853Sdes sshkey_free(id->key); 1399296853Sdes free(id->filename); 1400296853Sdes memset(id, 0, sizeof(*id)); 1401296853Sdes continue; 1402296853Sdes } 1403296853Sdes debug2("key: %s (%p)%s%s", id->filename, id->key, 1404296853Sdes id->userprovided ? ", explicit" : "", 1405296853Sdes id->agent_fd != -1 ? ", agent" : ""); 1406124211Sdes } 140765668Skris} 140865668Skris 1409124211Sdesstatic void 1410124211Sdespubkey_cleanup(Authctxt *authctxt) 141165668Skris{ 1412124211Sdes Identity *id; 141365668Skris 1414295367Sdes if (authctxt->agent_fd != -1) 1415295367Sdes ssh_close_authentication_socket(authctxt->agent_fd); 1416124211Sdes for (id = TAILQ_FIRST(&authctxt->keys); id; 1417124211Sdes id = TAILQ_FIRST(&authctxt->keys)) { 1418124211Sdes TAILQ_REMOVE(&authctxt->keys, id, next); 1419296853Sdes sshkey_free(id->key); 1420255767Sdes free(id->filename); 1421255767Sdes free(id); 142265668Skris } 142365668Skris} 142465668Skris 1425295367Sdesstatic int 1426295367Sdestry_identity(Identity *id) 1427295367Sdes{ 1428295367Sdes if (!id->key) 1429295367Sdes return (0); 1430295367Sdes if (key_type_plain(id->key->type) == KEY_RSA && 1431295367Sdes (datafellows & SSH_BUG_RSASIGMD5) != 0) { 1432295367Sdes debug("Skipped %s key %s for RSA/MD5 server", 1433295367Sdes key_type(id->key), id->filename); 1434295367Sdes return (0); 1435295367Sdes } 1436295367Sdes return (id->key->type != KEY_RSA1); 1437295367Sdes} 1438295367Sdes 143969587Sgreenint 144069587Sgreenuserauth_pubkey(Authctxt *authctxt) 144169587Sgreen{ 1442124211Sdes Identity *id; 144369587Sgreen int sent = 0; 144469587Sgreen 1445124211Sdes while ((id = TAILQ_FIRST(&authctxt->keys))) { 1446124211Sdes if (id->tried++) 1447124211Sdes return (0); 1448126277Sdes /* move key to the end of the queue */ 1449124211Sdes TAILQ_REMOVE(&authctxt->keys, id, next); 1450124211Sdes TAILQ_INSERT_TAIL(&authctxt->keys, id, next); 1451124211Sdes /* 1452124211Sdes * send a test message if we have the public key. for 1453124211Sdes * encrypted keys we cannot do this and have to load the 1454124211Sdes * private key instead 1455124211Sdes */ 1456262566Sdes if (id->key != NULL) { 1457295367Sdes if (try_identity(id)) { 1458262566Sdes debug("Offering %s public key: %s", 1459262566Sdes key_type(id->key), id->filename); 1460262566Sdes sent = send_pubkey_test(authctxt, id); 1461262566Sdes } 1462262566Sdes } else { 1463124211Sdes debug("Trying private key: %s", id->filename); 1464296853Sdes id->key = load_identity_file(id); 1465124211Sdes if (id->key != NULL) { 1466295367Sdes if (try_identity(id)) { 1467295367Sdes id->isprivate = 1; 1468262566Sdes sent = sign_and_send_pubkey( 1469262566Sdes authctxt, id); 1470262566Sdes } 1471124211Sdes key_free(id->key); 1472124211Sdes id->key = NULL; 147376262Sgreen } 147476262Sgreen } 1475124211Sdes if (sent) 1476124211Sdes return (sent); 147776262Sgreen } 1478124211Sdes return (0); 147969587Sgreen} 148069587Sgreen 148169587Sgreen/* 148269587Sgreen * Send userauth request message specifying keyboard-interactive method. 148369587Sgreen */ 148469587Sgreenint 148569587Sgreenuserauth_kbdint(Authctxt *authctxt) 148669587Sgreen{ 148769587Sgreen static int attempt = 0; 148869587Sgreen 148969587Sgreen if (attempt++ >= options.number_of_password_prompts) 149069587Sgreen return 0; 149192559Sdes /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */ 149292559Sdes if (attempt > 1 && !authctxt->info_req_seen) { 149392559Sdes debug3("userauth_kbdint: disable: no info_req_seen"); 149492559Sdes dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL); 149592559Sdes return 0; 149692559Sdes } 149769587Sgreen 149869587Sgreen debug2("userauth_kbdint"); 149969587Sgreen packet_start(SSH2_MSG_USERAUTH_REQUEST); 150069587Sgreen packet_put_cstring(authctxt->server_user); 150169587Sgreen packet_put_cstring(authctxt->service); 150269587Sgreen packet_put_cstring(authctxt->method->name); 150369587Sgreen packet_put_cstring(""); /* lang */ 150469587Sgreen packet_put_cstring(options.kbd_interactive_devices ? 150569587Sgreen options.kbd_interactive_devices : ""); 150669587Sgreen packet_send(); 150769587Sgreen 150869587Sgreen dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); 150969587Sgreen return 1; 151069587Sgreen} 151169587Sgreen 151269587Sgreen/* 151376262Sgreen * parse INFO_REQUEST, prompt user and send INFO_RESPONSE 151469587Sgreen */ 1515295367Sdesint 151692559Sdesinput_userauth_info_req(int type, u_int32_t seq, void *ctxt) 151760573Skris{ 151869587Sgreen Authctxt *authctxt = ctxt; 151976262Sgreen char *name, *inst, *lang, *prompt, *response; 152076262Sgreen u_int num_prompts, i; 152169587Sgreen int echo = 0; 152260573Skris 152369587Sgreen debug2("input_userauth_info_req"); 152469587Sgreen 152569587Sgreen if (authctxt == NULL) 152669587Sgreen fatal("input_userauth_info_req: no authentication context"); 152769587Sgreen 152892559Sdes authctxt->info_req_seen = 1; 152992559Sdes 153069587Sgreen name = packet_get_string(NULL); 153169587Sgreen inst = packet_get_string(NULL); 153269587Sgreen lang = packet_get_string(NULL); 153369587Sgreen if (strlen(name) > 0) 1534124211Sdes logit("%s", name); 153569587Sgreen if (strlen(inst) > 0) 1536124211Sdes logit("%s", inst); 1537255767Sdes free(name); 1538255767Sdes free(inst); 1539255767Sdes free(lang); 154069587Sgreen 154169587Sgreen num_prompts = packet_get_int(); 154269587Sgreen /* 154369587Sgreen * Begin to build info response packet based on prompts requested. 154469587Sgreen * We commit to providing the correct number of responses, so if 154569587Sgreen * further on we run into a problem that prevents this, we have to 154669587Sgreen * be sure and clean this up and send a correct error response. 154769587Sgreen */ 154869587Sgreen packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE); 154969587Sgreen packet_put_int(num_prompts); 155069587Sgreen 155192559Sdes debug2("input_userauth_info_req: num_prompts %d", num_prompts); 155269587Sgreen for (i = 0; i < num_prompts; i++) { 155369587Sgreen prompt = packet_get_string(NULL); 155469587Sgreen echo = packet_get_char(); 155569587Sgreen 155692559Sdes response = read_passphrase(prompt, echo ? RP_ECHO : 0); 155769587Sgreen 155893704Sdes packet_put_cstring(response); 1559264377Sdes explicit_bzero(response, strlen(response)); 1560255767Sdes free(response); 1561255767Sdes free(prompt); 156269587Sgreen } 156392559Sdes packet_check_eom(); /* done with parsing incoming message. */ 156469587Sgreen 156592559Sdes packet_add_padding(64); 156660573Skris packet_send(); 1567295367Sdes return 0; 156869587Sgreen} 156960573Skris 157098684Sdesstatic int 1571295367Sdesssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, 1572295367Sdes const u_char *data, size_t datalen) 157398684Sdes{ 1574295367Sdes struct sshbuf *b; 157598684Sdes struct stat st; 157698684Sdes pid_t pid; 1577295367Sdes int i, r, to[2], from[2], status, sock = packet_get_connection_in(); 1578295367Sdes u_char rversion = 0, version = 2; 1579295367Sdes void (*osigchld)(int); 158098684Sdes 1581295367Sdes *sigp = NULL; 1582295367Sdes *lenp = 0; 158398684Sdes 158498684Sdes if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { 1585295367Sdes error("%s: not installed: %s", __func__, strerror(errno)); 158698684Sdes return -1; 158798684Sdes } 1588295367Sdes if (fflush(stdout) != 0) { 1589295367Sdes error("%s: fflush: %s", __func__, strerror(errno)); 1590295367Sdes return -1; 1591295367Sdes } 159298684Sdes if (pipe(to) < 0) { 1593295367Sdes error("%s: pipe: %s", __func__, strerror(errno)); 159498684Sdes return -1; 159598684Sdes } 159698684Sdes if (pipe(from) < 0) { 1597295367Sdes error("%s: pipe: %s", __func__, strerror(errno)); 159898684Sdes return -1; 159998684Sdes } 160098684Sdes if ((pid = fork()) < 0) { 1601295367Sdes error("%s: fork: %s", __func__, strerror(errno)); 160298684Sdes return -1; 160398684Sdes } 1604295367Sdes osigchld = signal(SIGCHLD, SIG_DFL); 160598684Sdes if (pid == 0) { 1606204917Sdes /* keep the socket on exec */ 1607295367Sdes fcntl(sock, F_SETFD, 0); 1608162856Sdes permanently_drop_suid(getuid()); 160998684Sdes close(from[0]); 161098684Sdes if (dup2(from[1], STDOUT_FILENO) < 0) 1611295367Sdes fatal("%s: dup2: %s", __func__, strerror(errno)); 161298684Sdes close(to[1]); 161398684Sdes if (dup2(to[0], STDIN_FILENO) < 0) 1614295367Sdes fatal("%s: dup2: %s", __func__, strerror(errno)); 161598684Sdes close(from[1]); 161698684Sdes close(to[0]); 1617295367Sdes /* Close everything but stdio and the socket */ 1618295367Sdes for (i = STDERR_FILENO + 1; i < sock; i++) 1619295367Sdes close(i); 1620295367Sdes closefrom(sock + 1); 1621295367Sdes debug3("%s: [child] pid=%ld, exec %s", 1622295367Sdes __func__, (long)getpid(), _PATH_SSH_KEY_SIGN); 1623296853Sdes execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *)NULL); 1624295367Sdes fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN, 162598684Sdes strerror(errno)); 162698684Sdes } 162798684Sdes close(from[1]); 162898684Sdes close(to[0]); 162998684Sdes 1630295367Sdes if ((b = sshbuf_new()) == NULL) 1631295367Sdes fatal("%s: sshbuf_new failed", __func__); 1632295367Sdes /* send # of sock, data to be signed */ 1633295367Sdes if ((r = sshbuf_put_u32(b, sock) != 0) || 1634295367Sdes (r = sshbuf_put_string(b, data, datalen)) != 0) 1635295367Sdes fatal("%s: buffer error: %s", __func__, ssh_err(r)); 1636295367Sdes if (ssh_msg_send(to[1], version, b) == -1) 1637295367Sdes fatal("%s: couldn't send request", __func__); 1638295367Sdes sshbuf_reset(b); 1639295367Sdes r = ssh_msg_recv(from[0], b); 164098684Sdes close(from[0]); 164198684Sdes close(to[1]); 1642295367Sdes if (r < 0) { 1643295367Sdes error("%s: no reply", __func__); 1644295367Sdes goto fail; 1645295367Sdes } 164698684Sdes 1647295367Sdes errno = 0; 1648295367Sdes while (waitpid(pid, &status, 0) < 0) { 1649295367Sdes if (errno != EINTR) { 1650295367Sdes error("%s: waitpid %ld: %s", 1651295367Sdes __func__, (long)pid, strerror(errno)); 1652295367Sdes goto fail; 1653295367Sdes } 1654295367Sdes } 1655295367Sdes if (!WIFEXITED(status)) { 1656295367Sdes error("%s: exited abnormally", __func__); 1657295367Sdes goto fail; 1658295367Sdes } 1659295367Sdes if (WEXITSTATUS(status) != 0) { 1660295367Sdes error("%s: exited with status %d", 1661295367Sdes __func__, WEXITSTATUS(status)); 1662295367Sdes goto fail; 1663295367Sdes } 1664295367Sdes if ((r = sshbuf_get_u8(b, &rversion)) != 0) { 1665295367Sdes error("%s: buffer error: %s", __func__, ssh_err(r)); 1666295367Sdes goto fail; 1667295367Sdes } 1668295367Sdes if (rversion != version) { 1669295367Sdes error("%s: bad version", __func__); 1670295367Sdes goto fail; 1671295367Sdes } 1672295367Sdes if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) { 1673295367Sdes error("%s: buffer error: %s", __func__, ssh_err(r)); 1674295367Sdes fail: 1675295367Sdes signal(SIGCHLD, osigchld); 1676295367Sdes sshbuf_free(b); 167798684Sdes return -1; 167898684Sdes } 1679295367Sdes signal(SIGCHLD, osigchld); 1680295367Sdes sshbuf_free(b); 168198684Sdes 168298684Sdes return 0; 168398684Sdes} 168498684Sdes 168576262Sgreenint 168676262Sgreenuserauth_hostbased(Authctxt *authctxt) 168769587Sgreen{ 1688295367Sdes struct ssh *ssh = active_state; 1689295367Sdes struct sshkey *private = NULL; 1690295367Sdes struct sshbuf *b = NULL; 169176262Sgreen const char *service; 1692295367Sdes u_char *sig = NULL, *keyblob = NULL; 1693295367Sdes char *fp = NULL, *chost = NULL, *lname = NULL; 1694295367Sdes size_t siglen = 0, keylen = 0; 1695295367Sdes int i, r, success = 0; 169676262Sgreen 1697295367Sdes if (authctxt->ktypes == NULL) { 1698295367Sdes authctxt->oktypes = xstrdup(options.hostbased_key_types); 1699295367Sdes authctxt->ktypes = authctxt->oktypes; 1700295367Sdes } 1701295367Sdes 1702295367Sdes /* 1703295367Sdes * Work through each listed type pattern in HostbasedKeyTypes, 1704295367Sdes * trying each hostkey that matches the type in turn. 1705295367Sdes */ 1706295367Sdes for (;;) { 1707295367Sdes if (authctxt->active_ktype == NULL) 1708295367Sdes authctxt->active_ktype = strsep(&authctxt->ktypes, ","); 1709295367Sdes if (authctxt->active_ktype == NULL || 1710295367Sdes *authctxt->active_ktype == '\0') 1711295367Sdes break; 1712295367Sdes debug3("%s: trying key type %s", __func__, 1713295367Sdes authctxt->active_ktype); 1714295367Sdes 1715295367Sdes /* check for a useful key */ 1716295367Sdes private = NULL; 1717295367Sdes for (i = 0; i < authctxt->sensitive->nkeys; i++) { 1718295367Sdes if (authctxt->sensitive->keys[i] == NULL || 1719295367Sdes authctxt->sensitive->keys[i]->type == KEY_RSA1 || 1720295367Sdes authctxt->sensitive->keys[i]->type == KEY_UNSPEC) 1721295367Sdes continue; 1722295367Sdes if (match_pattern_list( 1723295367Sdes sshkey_ssh_name(authctxt->sensitive->keys[i]), 1724295367Sdes authctxt->active_ktype, 0) != 1) 1725295367Sdes continue; 172676262Sgreen /* we take and free the key */ 1727295367Sdes private = authctxt->sensitive->keys[i]; 1728295367Sdes authctxt->sensitive->keys[i] = NULL; 172976262Sgreen break; 173076262Sgreen } 1731295367Sdes /* Found one */ 1732295367Sdes if (private != NULL) 1733295367Sdes break; 1734295367Sdes /* No more keys of this type; advance */ 1735295367Sdes authctxt->active_ktype = NULL; 173669587Sgreen } 1737295367Sdes if (private == NULL) { 1738295367Sdes free(authctxt->oktypes); 1739295367Sdes authctxt->oktypes = authctxt->ktypes = NULL; 1740295367Sdes authctxt->active_ktype = NULL; 1741113911Sdes debug("No more client hostkeys for hostbased authentication."); 1742295367Sdes goto out; 174369587Sgreen } 1744295367Sdes 1745295367Sdes if ((fp = sshkey_fingerprint(private, options.fingerprint_hash, 1746295367Sdes SSH_FP_DEFAULT)) == NULL) { 1747295367Sdes error("%s: sshkey_fingerprint failed", __func__); 1748295367Sdes goto out; 174976262Sgreen } 1750295367Sdes debug("%s: trying hostkey %s %s", 1751295367Sdes __func__, sshkey_ssh_name(private), fp); 1752295367Sdes 175392559Sdes /* figure out a name for the client host */ 1754295367Sdes if ((lname = get_local_name(packet_get_connection_in())) == NULL) { 1755295367Sdes error("%s: cannot get local ipaddr/name", __func__); 1756295367Sdes goto out; 175792559Sdes } 175892559Sdes 1759295367Sdes /* XXX sshbuf_put_stringf? */ 1760295367Sdes xasprintf(&chost, "%s.", lname); 1761295367Sdes debug2("%s: chost %s", __func__, chost); 1762295367Sdes 176376262Sgreen service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : 176476262Sgreen authctxt->service; 1765295367Sdes 176676262Sgreen /* construct data */ 1767295367Sdes if ((b = sshbuf_new()) == NULL) { 1768295367Sdes error("%s: sshbuf_new failed", __func__); 1769295367Sdes goto out; 1770295367Sdes } 1771295367Sdes if ((r = sshkey_to_blob(private, &keyblob, &keylen)) != 0) { 1772295367Sdes error("%s: sshkey_to_blob: %s", __func__, ssh_err(r)); 1773295367Sdes goto out; 1774295367Sdes } 1775295367Sdes if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || 1776295367Sdes (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1777295367Sdes (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || 1778295367Sdes (r = sshbuf_put_cstring(b, service)) != 0 || 1779295367Sdes (r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 || 1780295367Sdes (r = sshbuf_put_cstring(b, key_ssh_name(private))) != 0 || 1781295367Sdes (r = sshbuf_put_string(b, keyblob, keylen)) != 0 || 1782295367Sdes (r = sshbuf_put_cstring(b, chost)) != 0 || 1783295367Sdes (r = sshbuf_put_cstring(b, authctxt->local_user)) != 0) { 1784295367Sdes error("%s: buffer error: %s", __func__, ssh_err(r)); 1785295367Sdes goto out; 1786295367Sdes } 1787295367Sdes 178876262Sgreen#ifdef DEBUG_PK 1789295367Sdes sshbuf_dump(b, stderr); 179076262Sgreen#endif 1791295367Sdes if (authctxt->sensitive->external_keysign) 1792295367Sdes r = ssh_keysign(private, &sig, &siglen, 1793295367Sdes sshbuf_ptr(b), sshbuf_len(b)); 1794295367Sdes else if ((r = sshkey_sign(private, &sig, &siglen, 1795296853Sdes sshbuf_ptr(b), sshbuf_len(b), NULL, datafellows)) != 0) 1796295367Sdes debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); 1797295367Sdes if (r != 0) { 1798295367Sdes error("sign using hostkey %s %s failed", 1799295367Sdes sshkey_ssh_name(private), fp); 1800295367Sdes goto out; 180176262Sgreen } 1802295367Sdes if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1803295367Sdes (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || 1804295367Sdes (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || 1805295367Sdes (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || 1806295367Sdes (r = sshpkt_put_cstring(ssh, key_ssh_name(private))) != 0 || 1807295367Sdes (r = sshpkt_put_string(ssh, keyblob, keylen)) != 0 || 1808295367Sdes (r = sshpkt_put_cstring(ssh, chost)) != 0 || 1809295367Sdes (r = sshpkt_put_cstring(ssh, authctxt->local_user)) != 0 || 1810295367Sdes (r = sshpkt_put_string(ssh, sig, siglen)) != 0 || 1811295367Sdes (r = sshpkt_send(ssh)) != 0) { 1812295367Sdes error("%s: packet error: %s", __func__, ssh_err(r)); 1813295367Sdes goto out; 1814295367Sdes } 1815295367Sdes success = 1; 1816295367Sdes 1817295367Sdes out: 1818295367Sdes if (sig != NULL) { 1819295367Sdes explicit_bzero(sig, siglen); 1820295367Sdes free(sig); 1821295367Sdes } 1822295367Sdes free(keyblob); 1823295367Sdes free(lname); 1824295367Sdes free(fp); 1825255767Sdes free(chost); 1826295367Sdes sshkey_free(private); 1827295367Sdes sshbuf_free(b); 182876262Sgreen 1829295367Sdes return success; 183069587Sgreen} 183169587Sgreen 183276262Sgreen/* find auth method */ 183376262Sgreen 183469587Sgreen/* 183569587Sgreen * given auth method name, if configurable options permit this method fill 183669587Sgreen * in auth_ident field and return true, otherwise return false. 183769587Sgreen */ 183892559Sdesstatic int 183969587Sgreenauthmethod_is_enabled(Authmethod *method) 184069587Sgreen{ 184169587Sgreen if (method == NULL) 184269587Sgreen return 0; 184369587Sgreen /* return false if options indicate this method is disabled */ 184469587Sgreen if (method->enabled == NULL || *method->enabled == 0) 184569587Sgreen return 0; 184669587Sgreen /* return false if batch mode is enabled but method needs interactive mode */ 184769587Sgreen if (method->batch_flag != NULL && *method->batch_flag != 0) 184869587Sgreen return 0; 184969587Sgreen return 1; 185069587Sgreen} 185169587Sgreen 185292559Sdesstatic Authmethod * 185369587Sgreenauthmethod_lookup(const char *name) 185469587Sgreen{ 185569587Sgreen Authmethod *method = NULL; 185669587Sgreen if (name != NULL) 185769587Sgreen for (method = authmethods; method->name != NULL; method++) 185869587Sgreen if (strcmp(name, method->name) == 0) 185969587Sgreen return method; 186069587Sgreen debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); 186169587Sgreen return NULL; 186269587Sgreen} 186369587Sgreen 186476262Sgreen/* XXX internal state */ 186576262Sgreenstatic Authmethod *current = NULL; 186676262Sgreenstatic char *supported = NULL; 186776262Sgreenstatic char *preferred = NULL; 186899063Sdes 186969587Sgreen/* 187069587Sgreen * Given the authentication method list sent by the server, return the 187169587Sgreen * next method we should try. If the server initially sends a nil list, 187276262Sgreen * use a built-in default list. 187376262Sgreen */ 187492559Sdesstatic Authmethod * 187569587Sgreenauthmethod_get(char *authlist) 187669587Sgreen{ 187776262Sgreen char *name = NULL; 187892559Sdes u_int next; 187976262Sgreen 188069587Sgreen /* Use a suitable default if we're passed a nil list. */ 188169587Sgreen if (authlist == NULL || strlen(authlist) == 0) 188276262Sgreen authlist = options.preferred_authentications; 188369587Sgreen 188476262Sgreen if (supported == NULL || strcmp(authlist, supported) != 0) { 188576262Sgreen debug3("start over, passed a different list %s", authlist); 1886255767Sdes free(supported); 188776262Sgreen supported = xstrdup(authlist); 188876262Sgreen preferred = options.preferred_authentications; 188976262Sgreen debug3("preferred %s", preferred); 189076262Sgreen current = NULL; 189176262Sgreen } else if (current != NULL && authmethod_is_enabled(current)) 189276262Sgreen return current; 189360573Skris 189476262Sgreen for (;;) { 189576262Sgreen if ((name = match_list(preferred, supported, &next)) == NULL) { 1896113911Sdes debug("No more authentication methods to try."); 189776262Sgreen current = NULL; 189876262Sgreen return NULL; 189976262Sgreen } 190076262Sgreen preferred += next; 190169587Sgreen debug3("authmethod_lookup %s", name); 190276262Sgreen debug3("remaining preferred: %s", preferred); 190376262Sgreen if ((current = authmethod_lookup(name)) != NULL && 190476262Sgreen authmethod_is_enabled(current)) { 190569587Sgreen debug3("authmethod_is_enabled %s", name); 1906113911Sdes debug("Next authentication method: %s", name); 1907255767Sdes free(name); 190876262Sgreen return current; 190960573Skris } 1910255767Sdes free(name); 191160573Skris } 191276262Sgreen} 191369587Sgreen 191492559Sdesstatic char * 191576262Sgreenauthmethods_get(void) 191676262Sgreen{ 191776262Sgreen Authmethod *method = NULL; 191892559Sdes Buffer b; 191992559Sdes char *list; 192069587Sgreen 192192559Sdes buffer_init(&b); 192276262Sgreen for (method = authmethods; method->name != NULL; method++) { 192376262Sgreen if (authmethod_is_enabled(method)) { 192492559Sdes if (buffer_len(&b) > 0) 192592559Sdes buffer_append(&b, ",", 1); 192692559Sdes buffer_append(&b, method->name, strlen(method->name)); 192776262Sgreen } 192876262Sgreen } 192992559Sdes buffer_append(&b, "\0", 1); 193092559Sdes list = xstrdup(buffer_ptr(&b)); 193192559Sdes buffer_free(&b); 193292559Sdes return list; 193360573Skris} 1934192595Sdes 1935