1*50a69bb5SSascha Wildner /* $OpenBSD: sshconnect2.c,v 1.351 2021/07/23 05:24:02 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 2000 Markus Friedl. All rights reserved. 4cb5eb4f1SPeter Avalos * Copyright (c) 2008 Damien Miller. All rights reserved. 518de8d7fSPeter Avalos * 618de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 718de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 818de8d7fSPeter Avalos * are met: 918de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 1018de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 1118de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1218de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 1318de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 1418de8d7fSPeter Avalos * 1518de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1618de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1718de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1818de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1918de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2018de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2118de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2218de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2318de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2418de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2518de8d7fSPeter Avalos */ 2618de8d7fSPeter Avalos 2718de8d7fSPeter Avalos #include "includes.h" 2818de8d7fSPeter Avalos 2918de8d7fSPeter Avalos #include <sys/types.h> 3018de8d7fSPeter Avalos #include <sys/socket.h> 3118de8d7fSPeter Avalos #include <sys/wait.h> 3218de8d7fSPeter Avalos #include <sys/stat.h> 3318de8d7fSPeter Avalos 3418de8d7fSPeter Avalos #include <errno.h> 35856ea928SPeter Avalos #include <fcntl.h> 36*50a69bb5SSascha Wildner #include <limits.h> 3718de8d7fSPeter Avalos #include <netdb.h> 3818de8d7fSPeter Avalos #include <pwd.h> 3918de8d7fSPeter Avalos #include <signal.h> 4018de8d7fSPeter Avalos #include <stdio.h> 4118de8d7fSPeter Avalos #include <string.h> 420cbfa66cSDaniel Fojt #include <stdarg.h> 4318de8d7fSPeter Avalos #include <unistd.h> 4436e94dc5SPeter Avalos #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) 4518de8d7fSPeter Avalos #include <vis.h> 4618de8d7fSPeter Avalos #endif 4718de8d7fSPeter Avalos 4818de8d7fSPeter Avalos #include "openbsd-compat/sys-queue.h" 4918de8d7fSPeter Avalos 5018de8d7fSPeter Avalos #include "xmalloc.h" 5118de8d7fSPeter Avalos #include "ssh.h" 5218de8d7fSPeter Avalos #include "ssh2.h" 53664f4763Szrj #include "sshbuf.h" 5418de8d7fSPeter Avalos #include "packet.h" 5518de8d7fSPeter Avalos #include "compat.h" 5618de8d7fSPeter Avalos #include "cipher.h" 57664f4763Szrj #include "sshkey.h" 5818de8d7fSPeter Avalos #include "kex.h" 5918de8d7fSPeter Avalos #include "myproposal.h" 6018de8d7fSPeter Avalos #include "sshconnect.h" 6118de8d7fSPeter Avalos #include "authfile.h" 6218de8d7fSPeter Avalos #include "dh.h" 6318de8d7fSPeter Avalos #include "authfd.h" 6418de8d7fSPeter Avalos #include "log.h" 6518de8d7fSPeter Avalos #include "misc.h" 6636e94dc5SPeter Avalos #include "readconf.h" 6718de8d7fSPeter Avalos #include "match.h" 6818de8d7fSPeter Avalos #include "dispatch.h" 6918de8d7fSPeter Avalos #include "canohost.h" 7018de8d7fSPeter Avalos #include "msg.h" 7118de8d7fSPeter Avalos #include "pathnames.h" 7218de8d7fSPeter Avalos #include "uidswap.h" 739f304aafSPeter Avalos #include "hostfile.h" 74e9778795SPeter Avalos #include "ssherr.h" 75e9778795SPeter Avalos #include "utf8.h" 760cbfa66cSDaniel Fojt #include "ssh-sk.h" 770cbfa66cSDaniel Fojt #include "sk-api.h" 7818de8d7fSPeter Avalos 7918de8d7fSPeter Avalos #ifdef GSSAPI 8018de8d7fSPeter Avalos #include "ssh-gss.h" 8118de8d7fSPeter Avalos #endif 8218de8d7fSPeter Avalos 8318de8d7fSPeter Avalos /* import */ 8418de8d7fSPeter Avalos extern char *client_version_string; 8518de8d7fSPeter Avalos extern char *server_version_string; 8618de8d7fSPeter Avalos extern Options options; 8718de8d7fSPeter Avalos 8818de8d7fSPeter Avalos /* 8918de8d7fSPeter Avalos * SSH2 key exchange 9018de8d7fSPeter Avalos */ 9118de8d7fSPeter Avalos 92*50a69bb5SSascha Wildner static char *xxx_host; 93*50a69bb5SSascha Wildner static struct sockaddr *xxx_hostaddr; 94*50a69bb5SSascha Wildner static const struct ssh_conn_info *xxx_conn_info; 9518de8d7fSPeter Avalos 9618de8d7fSPeter Avalos static int 97ce74bacaSMatthew Dillon verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh) 9818de8d7fSPeter Avalos { 99*50a69bb5SSascha Wildner if (verify_host_key(xxx_host, xxx_hostaddr, hostkey, 100*50a69bb5SSascha Wildner xxx_conn_info) == -1) 10118de8d7fSPeter Avalos fatal("Host key verification failed."); 10218de8d7fSPeter Avalos return 0; 10318de8d7fSPeter Avalos } 10418de8d7fSPeter Avalos 105*50a69bb5SSascha Wildner /* Returns the first item from a comma-separated algorithm list */ 1069f304aafSPeter Avalos static char * 107*50a69bb5SSascha Wildner first_alg(const char *algs) 1089f304aafSPeter Avalos { 109*50a69bb5SSascha Wildner char *ret, *cp; 110*50a69bb5SSascha Wildner 111*50a69bb5SSascha Wildner ret = xstrdup(algs); 112*50a69bb5SSascha Wildner if ((cp = strchr(ret, ',')) != NULL) 113*50a69bb5SSascha Wildner *cp = '\0'; 114*50a69bb5SSascha Wildner return ret; 115*50a69bb5SSascha Wildner } 116*50a69bb5SSascha Wildner 117*50a69bb5SSascha Wildner static char * 118*50a69bb5SSascha Wildner order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port, 119*50a69bb5SSascha Wildner const struct ssh_conn_info *cinfo) 120*50a69bb5SSascha Wildner { 121*50a69bb5SSascha Wildner char *oavail = NULL, *avail = NULL, *first = NULL, *last = NULL; 122*50a69bb5SSascha Wildner char *alg = NULL, *hostname = NULL, *ret = NULL, *best = NULL; 1239f304aafSPeter Avalos size_t maxlen; 124*50a69bb5SSascha Wildner struct hostkeys *hostkeys = NULL; 1259f304aafSPeter Avalos int ktype; 1261c188a7fSPeter Avalos u_int i; 1279f304aafSPeter Avalos 1289f304aafSPeter Avalos /* Find all hostkeys for this hostname */ 1299f304aafSPeter Avalos get_hostfile_hostname_ipaddr(host, hostaddr, port, &hostname, NULL); 1309f304aafSPeter Avalos hostkeys = init_hostkeys(); 1311c188a7fSPeter Avalos for (i = 0; i < options.num_user_hostfiles; i++) 132*50a69bb5SSascha Wildner load_hostkeys(hostkeys, hostname, options.user_hostfiles[i], 0); 133*50a69bb5SSascha Wildner for (i = 0; i < options.num_system_hostfiles; i++) { 134*50a69bb5SSascha Wildner load_hostkeys(hostkeys, hostname, 135*50a69bb5SSascha Wildner options.system_hostfiles[i], 0); 136*50a69bb5SSascha Wildner } 137*50a69bb5SSascha Wildner if (options.known_hosts_command != NULL) { 138*50a69bb5SSascha Wildner load_hostkeys_command(hostkeys, options.known_hosts_command, 139*50a69bb5SSascha Wildner "ORDER", cinfo, NULL, host); 140*50a69bb5SSascha Wildner } 141*50a69bb5SSascha Wildner /* 142*50a69bb5SSascha Wildner * If a plain public key exists that matches the type of the best 143*50a69bb5SSascha Wildner * preference HostkeyAlgorithms, then use the whole list as is. 144*50a69bb5SSascha Wildner * Note that we ignore whether the best preference algorithm is a 145*50a69bb5SSascha Wildner * certificate type, as sshconnect.c will downgrade certs to 146*50a69bb5SSascha Wildner * plain keys if necessary. 147*50a69bb5SSascha Wildner */ 148*50a69bb5SSascha Wildner best = first_alg(options.hostkeyalgorithms); 149*50a69bb5SSascha Wildner if (lookup_key_in_hostkeys_by_type(hostkeys, 150*50a69bb5SSascha Wildner sshkey_type_plain(sshkey_type_from_name(best)), 151*50a69bb5SSascha Wildner sshkey_ecdsa_nid_from_name(best), NULL)) { 152*50a69bb5SSascha Wildner debug3_f("have matching best-preference key type %s, " 153*50a69bb5SSascha Wildner "using HostkeyAlgorithms verbatim", best); 154*50a69bb5SSascha Wildner ret = xstrdup(options.hostkeyalgorithms); 155*50a69bb5SSascha Wildner goto out; 156*50a69bb5SSascha Wildner } 1579f304aafSPeter Avalos 158*50a69bb5SSascha Wildner /* 159*50a69bb5SSascha Wildner * Otherwise, prefer the host key algorithms that match known keys 160*50a69bb5SSascha Wildner * while keeping the ordering of HostkeyAlgorithms as much as possible. 161*50a69bb5SSascha Wildner */ 1620cbfa66cSDaniel Fojt oavail = avail = xstrdup(options.hostkeyalgorithms); 1639f304aafSPeter Avalos maxlen = strlen(avail) + 1; 1649f304aafSPeter Avalos first = xmalloc(maxlen); 1659f304aafSPeter Avalos last = xmalloc(maxlen); 1669f304aafSPeter Avalos *first = *last = '\0'; 1679f304aafSPeter Avalos 1689f304aafSPeter Avalos #define ALG_APPEND(to, from) \ 1699f304aafSPeter Avalos do { \ 1709f304aafSPeter Avalos if (*to != '\0') \ 1719f304aafSPeter Avalos strlcat(to, ",", maxlen); \ 1729f304aafSPeter Avalos strlcat(to, from, maxlen); \ 1739f304aafSPeter Avalos } while (0) 1749f304aafSPeter Avalos 1759f304aafSPeter Avalos while ((alg = strsep(&avail, ",")) && *alg != '\0') { 176e9778795SPeter Avalos if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) 177*50a69bb5SSascha Wildner fatal_f("unknown alg %s", alg); 178*50a69bb5SSascha Wildner /* 179*50a69bb5SSascha Wildner * If we have a @cert-authority marker in known_hosts then 180*50a69bb5SSascha Wildner * prefer all certificate algorithms. 181*50a69bb5SSascha Wildner */ 182*50a69bb5SSascha Wildner if (sshkey_type_is_cert(ktype) && 183*50a69bb5SSascha Wildner lookup_marker_in_hostkeys(hostkeys, MRK_CA)) { 1849f304aafSPeter Avalos ALG_APPEND(first, alg); 185*50a69bb5SSascha Wildner continue; 186*50a69bb5SSascha Wildner } 187*50a69bb5SSascha Wildner /* If the key appears in known_hosts then prefer it */ 188*50a69bb5SSascha Wildner if (lookup_key_in_hostkeys_by_type(hostkeys, 189*50a69bb5SSascha Wildner sshkey_type_plain(ktype), 190*50a69bb5SSascha Wildner sshkey_ecdsa_nid_from_name(alg), NULL)) { 191*50a69bb5SSascha Wildner ALG_APPEND(first, alg); 192*50a69bb5SSascha Wildner continue; 193*50a69bb5SSascha Wildner } 194*50a69bb5SSascha Wildner /* Otherwise, put it last */ 1959f304aafSPeter Avalos ALG_APPEND(last, alg); 1969f304aafSPeter Avalos } 1979f304aafSPeter Avalos #undef ALG_APPEND 198e9778795SPeter Avalos xasprintf(&ret, "%s%s%s", first, 199e9778795SPeter Avalos (*first == '\0' || *last == '\0') ? "" : ",", last); 2009f304aafSPeter Avalos if (*first != '\0') 201*50a69bb5SSascha Wildner debug3_f("prefer hostkeyalgs: %s", first); 202*50a69bb5SSascha Wildner else 203*50a69bb5SSascha Wildner debug3_f("no algorithms matched; accept original"); 204*50a69bb5SSascha Wildner out: 205*50a69bb5SSascha Wildner free(best); 20636e94dc5SPeter Avalos free(first); 20736e94dc5SPeter Avalos free(last); 20836e94dc5SPeter Avalos free(hostname); 20936e94dc5SPeter Avalos free(oavail); 2109f304aafSPeter Avalos free_hostkeys(hostkeys); 2119f304aafSPeter Avalos 2129f304aafSPeter Avalos return ret; 2139f304aafSPeter Avalos } 2149f304aafSPeter Avalos 21518de8d7fSPeter Avalos void 216*50a69bb5SSascha Wildner ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, 217*50a69bb5SSascha Wildner const struct ssh_conn_info *cinfo) 21818de8d7fSPeter Avalos { 21936e94dc5SPeter Avalos char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 220664f4763Szrj char *s, *all_key; 2210cbfa66cSDaniel Fojt int r, use_known_hosts_order = 0; 22218de8d7fSPeter Avalos 22318de8d7fSPeter Avalos xxx_host = host; 22418de8d7fSPeter Avalos xxx_hostaddr = hostaddr; 225*50a69bb5SSascha Wildner xxx_conn_info = cinfo; 22618de8d7fSPeter Avalos 2270cbfa66cSDaniel Fojt /* 2280cbfa66cSDaniel Fojt * If the user has not specified HostkeyAlgorithms, or has only 2290cbfa66cSDaniel Fojt * appended or removed algorithms from that list then prefer algorithms 2300cbfa66cSDaniel Fojt * that are in the list that are supported by known_hosts keys. 2310cbfa66cSDaniel Fojt */ 2320cbfa66cSDaniel Fojt if (options.hostkeyalgorithms == NULL || 2330cbfa66cSDaniel Fojt options.hostkeyalgorithms[0] == '-' || 2340cbfa66cSDaniel Fojt options.hostkeyalgorithms[0] == '+') 2350cbfa66cSDaniel Fojt use_known_hosts_order = 1; 2360cbfa66cSDaniel Fojt 2370cbfa66cSDaniel Fojt /* Expand or fill in HostkeyAlgorithms */ 2380cbfa66cSDaniel Fojt all_key = sshkey_alg_list(0, 0, 1, ','); 239*50a69bb5SSascha Wildner if ((r = kex_assemble_names(&options.hostkeyalgorithms, 240*50a69bb5SSascha Wildner kex_default_pk_alg(), all_key)) != 0) 241*50a69bb5SSascha Wildner fatal_fr(r, "kex_assemble_namelist"); 2420cbfa66cSDaniel Fojt free(all_key); 2430cbfa66cSDaniel Fojt 244e9778795SPeter Avalos if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) 245*50a69bb5SSascha Wildner fatal_f("kex_names_cat"); 246*50a69bb5SSascha Wildner myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, s); 24718de8d7fSPeter Avalos myproposal[PROPOSAL_ENC_ALGS_CTOS] = 248*50a69bb5SSascha Wildner compat_cipher_proposal(ssh, options.ciphers); 24918de8d7fSPeter Avalos myproposal[PROPOSAL_ENC_ALGS_STOC] = 250*50a69bb5SSascha Wildner compat_cipher_proposal(ssh, options.ciphers); 25118de8d7fSPeter Avalos myproposal[PROPOSAL_COMP_ALGS_CTOS] = 2520cbfa66cSDaniel Fojt myproposal[PROPOSAL_COMP_ALGS_STOC] = 2530cbfa66cSDaniel Fojt (char *)compression_alg_list(options.compression); 25418de8d7fSPeter Avalos myproposal[PROPOSAL_MAC_ALGS_CTOS] = 25518de8d7fSPeter Avalos myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; 2560cbfa66cSDaniel Fojt if (use_known_hosts_order) { 2570cbfa66cSDaniel Fojt /* Query known_hosts and prefer algorithms that appear there */ 2589f304aafSPeter Avalos myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 259*50a69bb5SSascha Wildner compat_pkalg_proposal(ssh, 260*50a69bb5SSascha Wildner order_hostkeyalgs(host, hostaddr, port, cinfo)); 2610cbfa66cSDaniel Fojt } else { 2620cbfa66cSDaniel Fojt /* Use specified HostkeyAlgorithms exactly */ 2630cbfa66cSDaniel Fojt myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 264*50a69bb5SSascha Wildner compat_pkalg_proposal(ssh, options.hostkeyalgorithms); 2659f304aafSPeter Avalos } 26618de8d7fSPeter Avalos 26736e94dc5SPeter Avalos if (options.rekey_limit || options.rekey_interval) 268664f4763Szrj ssh_packet_set_rekey_limits(ssh, options.rekey_limit, 269ce74bacaSMatthew Dillon options.rekey_interval); 27018de8d7fSPeter Avalos 27118de8d7fSPeter Avalos /* start key exchange */ 272664f4763Szrj if ((r = kex_setup(ssh, myproposal)) != 0) 273*50a69bb5SSascha Wildner fatal_r(r, "kex_setup"); 27436e94dc5SPeter Avalos #ifdef WITH_OPENSSL 275664f4763Szrj ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client; 276664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client; 277664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client; 278664f4763Szrj ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client; 279664f4763Szrj ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client; 280664f4763Szrj ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 281664f4763Szrj ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 282e9778795SPeter Avalos # ifdef OPENSSL_HAS_ECC 283664f4763Szrj ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; 28436e94dc5SPeter Avalos # endif 285e9778795SPeter Avalos #endif 286664f4763Szrj ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 287*50a69bb5SSascha Wildner ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; 288664f4763Szrj ssh->kex->verify_host_key=&verify_host_key_callback; 28918de8d7fSPeter Avalos 290664f4763Szrj ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); 29118de8d7fSPeter Avalos 292e9778795SPeter Avalos /* remove ext-info from the KEX proposals for rekeying */ 293e9778795SPeter Avalos myproposal[PROPOSAL_KEX_ALGS] = 294*50a69bb5SSascha Wildner compat_kex_proposal(ssh, options.kex_algorithms); 295664f4763Szrj if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) 296*50a69bb5SSascha Wildner fatal_r(r, "kex_prop2buf"); 29718de8d7fSPeter Avalos 29818de8d7fSPeter Avalos #ifdef DEBUG_KEXDH 29918de8d7fSPeter Avalos /* send 1st encrypted/maced/compressed message */ 300664f4763Szrj if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || 301664f4763Szrj (r = sshpkt_put_cstring(ssh, "markus")) != 0 || 302664f4763Szrj (r = sshpkt_send(ssh)) != 0 || 303664f4763Szrj (r = ssh_packet_write_wait(ssh)) != 0) 304*50a69bb5SSascha Wildner fatal_fr(r, "send packet"); 30518de8d7fSPeter Avalos #endif 30618de8d7fSPeter Avalos } 30718de8d7fSPeter Avalos 30818de8d7fSPeter Avalos /* 30918de8d7fSPeter Avalos * Authenticate user 31018de8d7fSPeter Avalos */ 31118de8d7fSPeter Avalos 312e9778795SPeter Avalos typedef struct cauthctxt Authctxt; 313e9778795SPeter Avalos typedef struct cauthmethod Authmethod; 31418de8d7fSPeter Avalos typedef struct identity Identity; 31518de8d7fSPeter Avalos typedef struct idlist Idlist; 31618de8d7fSPeter Avalos 31718de8d7fSPeter Avalos struct identity { 31818de8d7fSPeter Avalos TAILQ_ENTRY(identity) next; 319e9778795SPeter Avalos int agent_fd; /* >=0 if agent supports key */ 320e9778795SPeter Avalos struct sshkey *key; /* public/private key */ 32118de8d7fSPeter Avalos char *filename; /* comment for agent-only keys */ 32218de8d7fSPeter Avalos int tried; 32318de8d7fSPeter Avalos int isprivate; /* key points to the private key */ 32436e94dc5SPeter Avalos int userprovided; 32518de8d7fSPeter Avalos }; 32618de8d7fSPeter Avalos TAILQ_HEAD(idlist, identity); 32718de8d7fSPeter Avalos 328e9778795SPeter Avalos struct cauthctxt { 32918de8d7fSPeter Avalos const char *server_user; 33018de8d7fSPeter Avalos const char *local_user; 33118de8d7fSPeter Avalos const char *host; 33218de8d7fSPeter Avalos const char *service; 333e9778795SPeter Avalos struct cauthmethod *method; 334856ea928SPeter Avalos sig_atomic_t success; 33518de8d7fSPeter Avalos char *authlist; 336664f4763Szrj #ifdef GSSAPI 337664f4763Szrj /* gssapi */ 338664f4763Szrj gss_OID_set gss_supported_mechs; 339664f4763Szrj u_int mech_tried; 340664f4763Szrj #endif 34118de8d7fSPeter Avalos /* pubkey */ 342e9778795SPeter Avalos struct idlist keys; 343e9778795SPeter Avalos int agent_fd; 34418de8d7fSPeter Avalos /* hostbased */ 34518de8d7fSPeter Avalos Sensitive *sensitive; 346e9778795SPeter Avalos char *oktypes, *ktypes; 347e9778795SPeter Avalos const char *active_ktype; 34818de8d7fSPeter Avalos /* kbd-interactive */ 34918de8d7fSPeter Avalos int info_req_seen; 350664f4763Szrj int attempt_kbdint; 351664f4763Szrj /* password */ 352664f4763Szrj int attempt_passwd; 35318de8d7fSPeter Avalos /* generic */ 35418de8d7fSPeter Avalos void *methoddata; 35518de8d7fSPeter Avalos }; 356e9778795SPeter Avalos 357e9778795SPeter Avalos struct cauthmethod { 35818de8d7fSPeter Avalos char *name; /* string to compare against server's list */ 359664f4763Szrj int (*userauth)(struct ssh *ssh); 360664f4763Szrj void (*cleanup)(struct ssh *ssh); 36118de8d7fSPeter Avalos int *enabled; /* flag in option struct that enables method */ 36218de8d7fSPeter Avalos int *batch_flag; /* flag in option struct that disables method */ 36318de8d7fSPeter Avalos }; 36418de8d7fSPeter Avalos 365664f4763Szrj static int input_userauth_service_accept(int, u_int32_t, struct ssh *); 366664f4763Szrj static int input_userauth_ext_info(int, u_int32_t, struct ssh *); 367664f4763Szrj static int input_userauth_success(int, u_int32_t, struct ssh *); 368664f4763Szrj static int input_userauth_failure(int, u_int32_t, struct ssh *); 369664f4763Szrj static int input_userauth_banner(int, u_int32_t, struct ssh *); 370664f4763Szrj static int input_userauth_error(int, u_int32_t, struct ssh *); 371664f4763Szrj static int input_userauth_info_req(int, u_int32_t, struct ssh *); 372664f4763Szrj static int input_userauth_pk_ok(int, u_int32_t, struct ssh *); 373664f4763Szrj static int input_userauth_passwd_changereq(int, u_int32_t, struct ssh *); 37418de8d7fSPeter Avalos 375664f4763Szrj static int userauth_none(struct ssh *); 376664f4763Szrj static int userauth_pubkey(struct ssh *); 377664f4763Szrj static int userauth_passwd(struct ssh *); 378664f4763Szrj static int userauth_kbdint(struct ssh *); 379664f4763Szrj static int userauth_hostbased(struct ssh *); 38018de8d7fSPeter Avalos 38118de8d7fSPeter Avalos #ifdef GSSAPI 382664f4763Szrj static int userauth_gssapi(struct ssh *); 383664f4763Szrj static void userauth_gssapi_cleanup(struct ssh *); 384664f4763Szrj static int input_gssapi_response(int type, u_int32_t, struct ssh *); 385664f4763Szrj static int input_gssapi_token(int type, u_int32_t, struct ssh *); 386664f4763Szrj static int input_gssapi_error(int, u_int32_t, struct ssh *); 387664f4763Szrj static int input_gssapi_errtok(int, u_int32_t, struct ssh *); 38818de8d7fSPeter Avalos #endif 38918de8d7fSPeter Avalos 390664f4763Szrj void userauth(struct ssh *, char *); 39118de8d7fSPeter Avalos 392664f4763Szrj static void pubkey_cleanup(struct ssh *); 393664f4763Szrj static int sign_and_send_pubkey(struct ssh *ssh, Identity *); 39418de8d7fSPeter Avalos static void pubkey_prepare(Authctxt *); 395ce74bacaSMatthew Dillon static void pubkey_reset(Authctxt *); 396ce74bacaSMatthew Dillon static struct sshkey *load_identity_file(Identity *); 39718de8d7fSPeter Avalos 39818de8d7fSPeter Avalos static Authmethod *authmethod_get(char *authlist); 39918de8d7fSPeter Avalos static Authmethod *authmethod_lookup(const char *name); 40018de8d7fSPeter Avalos static char *authmethods_get(void); 40118de8d7fSPeter Avalos 40218de8d7fSPeter Avalos Authmethod authmethods[] = { 40318de8d7fSPeter Avalos #ifdef GSSAPI 40418de8d7fSPeter Avalos {"gssapi-with-mic", 40518de8d7fSPeter Avalos userauth_gssapi, 406664f4763Szrj userauth_gssapi_cleanup, 40718de8d7fSPeter Avalos &options.gss_authentication, 40818de8d7fSPeter Avalos NULL}, 40918de8d7fSPeter Avalos #endif 41018de8d7fSPeter Avalos {"hostbased", 41118de8d7fSPeter Avalos userauth_hostbased, 412cb5eb4f1SPeter Avalos NULL, 41318de8d7fSPeter Avalos &options.hostbased_authentication, 41418de8d7fSPeter Avalos NULL}, 41518de8d7fSPeter Avalos {"publickey", 41618de8d7fSPeter Avalos userauth_pubkey, 417cb5eb4f1SPeter Avalos NULL, 41818de8d7fSPeter Avalos &options.pubkey_authentication, 41918de8d7fSPeter Avalos NULL}, 42018de8d7fSPeter Avalos {"keyboard-interactive", 42118de8d7fSPeter Avalos userauth_kbdint, 422cb5eb4f1SPeter Avalos NULL, 42318de8d7fSPeter Avalos &options.kbd_interactive_authentication, 42418de8d7fSPeter Avalos &options.batch_mode}, 42518de8d7fSPeter Avalos {"password", 42618de8d7fSPeter Avalos userauth_passwd, 427cb5eb4f1SPeter Avalos NULL, 42818de8d7fSPeter Avalos &options.password_authentication, 42918de8d7fSPeter Avalos &options.batch_mode}, 43018de8d7fSPeter Avalos {"none", 43118de8d7fSPeter Avalos userauth_none, 43218de8d7fSPeter Avalos NULL, 433cb5eb4f1SPeter Avalos NULL, 43418de8d7fSPeter Avalos NULL}, 435cb5eb4f1SPeter Avalos {NULL, NULL, NULL, NULL, NULL} 43618de8d7fSPeter Avalos }; 43718de8d7fSPeter Avalos 43818de8d7fSPeter Avalos void 439664f4763Szrj ssh_userauth2(struct ssh *ssh, const char *local_user, 440664f4763Szrj const char *server_user, char *host, Sensitive *sensitive) 44118de8d7fSPeter Avalos { 44218de8d7fSPeter Avalos Authctxt authctxt; 443e9778795SPeter Avalos int r; 44418de8d7fSPeter Avalos 44518de8d7fSPeter Avalos if (options.preferred_authentications == NULL) 44618de8d7fSPeter Avalos options.preferred_authentications = authmethods_get(); 44718de8d7fSPeter Avalos 44818de8d7fSPeter Avalos /* setup authentication context */ 44918de8d7fSPeter Avalos memset(&authctxt, 0, sizeof(authctxt)); 45018de8d7fSPeter Avalos authctxt.server_user = server_user; 45118de8d7fSPeter Avalos authctxt.local_user = local_user; 45218de8d7fSPeter Avalos authctxt.host = host; 45318de8d7fSPeter Avalos authctxt.service = "ssh-connection"; /* service name */ 45418de8d7fSPeter Avalos authctxt.success = 0; 45518de8d7fSPeter Avalos authctxt.method = authmethod_lookup("none"); 45618de8d7fSPeter Avalos authctxt.authlist = NULL; 45718de8d7fSPeter Avalos authctxt.methoddata = NULL; 45818de8d7fSPeter Avalos authctxt.sensitive = sensitive; 459e9778795SPeter Avalos authctxt.active_ktype = authctxt.oktypes = authctxt.ktypes = NULL; 46018de8d7fSPeter Avalos authctxt.info_req_seen = 0; 461664f4763Szrj authctxt.attempt_kbdint = 0; 462664f4763Szrj authctxt.attempt_passwd = 0; 463664f4763Szrj #if GSSAPI 464664f4763Szrj authctxt.gss_supported_mechs = NULL; 465664f4763Szrj authctxt.mech_tried = 0; 466664f4763Szrj #endif 467e9778795SPeter Avalos authctxt.agent_fd = -1; 468664f4763Szrj pubkey_prepare(&authctxt); 469664f4763Szrj if (authctxt.method == NULL) { 470*50a69bb5SSascha Wildner fatal_f("internal error: cannot send userauth none request"); 471664f4763Szrj } 47218de8d7fSPeter Avalos 473e9778795SPeter Avalos if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 || 474e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 || 475e9778795SPeter Avalos (r = sshpkt_send(ssh)) != 0) 476*50a69bb5SSascha Wildner fatal_fr(r, "send packet"); 47718de8d7fSPeter Avalos 478ce74bacaSMatthew Dillon ssh->authctxt = &authctxt; 479e9778795SPeter Avalos ssh_dispatch_init(ssh, &input_userauth_error); 480e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info); 481e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept); 482ce74bacaSMatthew Dillon ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */ 483664f4763Szrj pubkey_cleanup(ssh); 484ce74bacaSMatthew Dillon ssh->authctxt = NULL; 48518de8d7fSPeter Avalos 486e9778795SPeter Avalos ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); 48718de8d7fSPeter Avalos 488ce74bacaSMatthew Dillon if (!authctxt.success) 489ce74bacaSMatthew Dillon fatal("Authentication failed."); 490*50a69bb5SSascha Wildner if (ssh_packet_connection_is_on_socket(ssh)) { 491*50a69bb5SSascha Wildner verbose("Authenticated to %s ([%s]:%d) using \"%s\".", host, 492*50a69bb5SSascha Wildner ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), 493*50a69bb5SSascha Wildner authctxt.method->name); 494*50a69bb5SSascha Wildner } else { 495*50a69bb5SSascha Wildner verbose("Authenticated to %s (via proxy) using \"%s\".", host, 496*50a69bb5SSascha Wildner authctxt.method->name); 497*50a69bb5SSascha Wildner } 49818de8d7fSPeter Avalos } 49918de8d7fSPeter Avalos 500e9778795SPeter Avalos /* ARGSUSED */ 501664f4763Szrj static int 502ce74bacaSMatthew Dillon input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh) 503e9778795SPeter Avalos { 504e9778795SPeter Avalos int r; 505e9778795SPeter Avalos 506e9778795SPeter Avalos if (ssh_packet_remaining(ssh) > 0) { 507e9778795SPeter Avalos char *reply; 508e9778795SPeter Avalos 509e9778795SPeter Avalos if ((r = sshpkt_get_cstring(ssh, &reply, NULL)) != 0) 510e9778795SPeter Avalos goto out; 511e9778795SPeter Avalos debug2("service_accept: %s", reply); 512e9778795SPeter Avalos free(reply); 513e9778795SPeter Avalos } else { 514e9778795SPeter Avalos debug2("buggy server: service_accept w/o service"); 515e9778795SPeter Avalos } 516e9778795SPeter Avalos if ((r = sshpkt_get_end(ssh)) != 0) 517e9778795SPeter Avalos goto out; 518e9778795SPeter Avalos debug("SSH2_MSG_SERVICE_ACCEPT received"); 519e9778795SPeter Avalos 520e9778795SPeter Avalos /* initial userauth request */ 521664f4763Szrj userauth_none(ssh); 522e9778795SPeter Avalos 523e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error); 524e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); 525e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); 526e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); 527e9778795SPeter Avalos r = 0; 528e9778795SPeter Avalos out: 529e9778795SPeter Avalos return r; 530e9778795SPeter Avalos } 531e9778795SPeter Avalos 532e9778795SPeter Avalos /* ARGSUSED */ 533664f4763Szrj static int 534ce74bacaSMatthew Dillon input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh) 535e9778795SPeter Avalos { 536ce74bacaSMatthew Dillon return kex_input_ext_info(type, seqnr, ssh); 537e9778795SPeter Avalos } 538e9778795SPeter Avalos 53918de8d7fSPeter Avalos void 540664f4763Szrj userauth(struct ssh *ssh, char *authlist) 54118de8d7fSPeter Avalos { 542664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 543664f4763Szrj 544cb5eb4f1SPeter Avalos if (authctxt->method != NULL && authctxt->method->cleanup != NULL) 545664f4763Szrj authctxt->method->cleanup(ssh); 546cb5eb4f1SPeter Avalos 54736e94dc5SPeter Avalos free(authctxt->methoddata); 54818de8d7fSPeter Avalos authctxt->methoddata = NULL; 54918de8d7fSPeter Avalos if (authlist == NULL) { 55018de8d7fSPeter Avalos authlist = authctxt->authlist; 55118de8d7fSPeter Avalos } else { 55236e94dc5SPeter Avalos free(authctxt->authlist); 55318de8d7fSPeter Avalos authctxt->authlist = authlist; 55418de8d7fSPeter Avalos } 55518de8d7fSPeter Avalos for (;;) { 55618de8d7fSPeter Avalos Authmethod *method = authmethod_get(authlist); 55718de8d7fSPeter Avalos if (method == NULL) 558ce74bacaSMatthew Dillon fatal("%s@%s: Permission denied (%s).", 559ce74bacaSMatthew Dillon authctxt->server_user, authctxt->host, authlist); 56018de8d7fSPeter Avalos authctxt->method = method; 56118de8d7fSPeter Avalos 56218de8d7fSPeter Avalos /* reset the per method handler */ 563664f4763Szrj ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_PER_METHOD_MIN, 56418de8d7fSPeter Avalos SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL); 56518de8d7fSPeter Avalos 56618de8d7fSPeter Avalos /* and try new method */ 567664f4763Szrj if (method->userauth(ssh) != 0) { 56818de8d7fSPeter Avalos debug2("we sent a %s packet, wait for reply", method->name); 56918de8d7fSPeter Avalos break; 57018de8d7fSPeter Avalos } else { 57118de8d7fSPeter Avalos debug2("we did not send a packet, disable method"); 57218de8d7fSPeter Avalos method->enabled = NULL; 57318de8d7fSPeter Avalos } 57418de8d7fSPeter Avalos } 57518de8d7fSPeter Avalos } 57618de8d7fSPeter Avalos 577cb5eb4f1SPeter Avalos /* ARGSUSED */ 578664f4763Szrj static int 579ce74bacaSMatthew Dillon input_userauth_error(int type, u_int32_t seq, struct ssh *ssh) 58018de8d7fSPeter Avalos { 581*50a69bb5SSascha Wildner fatal_f("bad message during authentication: type %d", type); 582e9778795SPeter Avalos return 0; 58318de8d7fSPeter Avalos } 58418de8d7fSPeter Avalos 585cb5eb4f1SPeter Avalos /* ARGSUSED */ 586664f4763Szrj static int 587ce74bacaSMatthew Dillon input_userauth_banner(int type, u_int32_t seq, struct ssh *ssh) 58818de8d7fSPeter Avalos { 589664f4763Szrj char *msg = NULL; 590664f4763Szrj size_t len; 591664f4763Szrj int r; 59218de8d7fSPeter Avalos 593*50a69bb5SSascha Wildner debug3_f("entering"); 594664f4763Szrj if ((r = sshpkt_get_cstring(ssh, &msg, &len)) != 0 || 595664f4763Szrj (r = sshpkt_get_cstring(ssh, NULL, NULL)) != 0) 596664f4763Szrj goto out; 597e9778795SPeter Avalos if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) 598e9778795SPeter Avalos fmprintf(stderr, "%s", msg); 599664f4763Szrj r = 0; 600664f4763Szrj out: 60136e94dc5SPeter Avalos free(msg); 602664f4763Szrj return r; 60318de8d7fSPeter Avalos } 60418de8d7fSPeter Avalos 605cb5eb4f1SPeter Avalos /* ARGSUSED */ 606664f4763Szrj static int 607ce74bacaSMatthew Dillon input_userauth_success(int type, u_int32_t seq, struct ssh *ssh) 60818de8d7fSPeter Avalos { 609ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 610856ea928SPeter Avalos 61118de8d7fSPeter Avalos if (authctxt == NULL) 612*50a69bb5SSascha Wildner fatal_f("no authentication context"); 61336e94dc5SPeter Avalos free(authctxt->authlist); 61418de8d7fSPeter Avalos authctxt->authlist = NULL; 615856ea928SPeter Avalos if (authctxt->method != NULL && authctxt->method->cleanup != NULL) 616664f4763Szrj authctxt->method->cleanup(ssh); 61736e94dc5SPeter Avalos free(authctxt->methoddata); 61818de8d7fSPeter Avalos authctxt->methoddata = NULL; 61918de8d7fSPeter Avalos authctxt->success = 1; /* break out */ 620e9778795SPeter Avalos return 0; 62118de8d7fSPeter Avalos } 62218de8d7fSPeter Avalos 623664f4763Szrj #if 0 624664f4763Szrj static int 625ce74bacaSMatthew Dillon input_userauth_success_unexpected(int type, u_int32_t seq, struct ssh *ssh) 626856ea928SPeter Avalos { 627ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 628856ea928SPeter Avalos 629856ea928SPeter Avalos if (authctxt == NULL) 630*50a69bb5SSascha Wildner fatal_f("no authentication context"); 631856ea928SPeter Avalos 632856ea928SPeter Avalos fatal("Unexpected authentication success during %s.", 633856ea928SPeter Avalos authctxt->method->name); 634e9778795SPeter Avalos return 0; 635856ea928SPeter Avalos } 636664f4763Szrj #endif 637856ea928SPeter Avalos 638cb5eb4f1SPeter Avalos /* ARGSUSED */ 639664f4763Szrj static int 640ce74bacaSMatthew Dillon input_userauth_failure(int type, u_int32_t seq, struct ssh *ssh) 64118de8d7fSPeter Avalos { 642ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 64318de8d7fSPeter Avalos char *authlist = NULL; 644664f4763Szrj u_char partial; 64518de8d7fSPeter Avalos 64618de8d7fSPeter Avalos if (authctxt == NULL) 64718de8d7fSPeter Avalos fatal("input_userauth_failure: no authentication context"); 64818de8d7fSPeter Avalos 6490cbfa66cSDaniel Fojt if (sshpkt_get_cstring(ssh, &authlist, NULL) != 0 || 6500cbfa66cSDaniel Fojt sshpkt_get_u8(ssh, &partial) != 0 || 6510cbfa66cSDaniel Fojt sshpkt_get_end(ssh) != 0) 652664f4763Szrj goto out; 65318de8d7fSPeter Avalos 65436e94dc5SPeter Avalos if (partial != 0) { 655*50a69bb5SSascha Wildner verbose("Authenticated using \"%s\" with partial success.", 656*50a69bb5SSascha Wildner authctxt->method->name); 65736e94dc5SPeter Avalos /* reset state */ 658ce74bacaSMatthew Dillon pubkey_reset(authctxt); 65936e94dc5SPeter Avalos } 66018de8d7fSPeter Avalos debug("Authentications that can continue: %s", authlist); 66118de8d7fSPeter Avalos 662664f4763Szrj userauth(ssh, authlist); 663664f4763Szrj authlist = NULL; 664664f4763Szrj out: 665664f4763Szrj free(authlist); 666e9778795SPeter Avalos return 0; 66718de8d7fSPeter Avalos } 668cb5eb4f1SPeter Avalos 669664f4763Szrj /* 670664f4763Szrj * Format an identity for logging including filename, key type, fingerprint 671664f4763Szrj * and location (agent, etc.). Caller must free. 672664f4763Szrj */ 673664f4763Szrj static char * 674664f4763Szrj format_identity(Identity *id) 675664f4763Szrj { 676664f4763Szrj char *fp = NULL, *ret = NULL; 6770cbfa66cSDaniel Fojt const char *note = ""; 678664f4763Szrj 679664f4763Szrj if (id->key != NULL) { 680664f4763Szrj fp = sshkey_fingerprint(id->key, options.fingerprint_hash, 681664f4763Szrj SSH_FP_DEFAULT); 682664f4763Szrj } 6830cbfa66cSDaniel Fojt if (id->key) { 6840cbfa66cSDaniel Fojt if ((id->key->flags & SSHKEY_FLAG_EXT) != 0) 6850cbfa66cSDaniel Fojt note = " token"; 6860cbfa66cSDaniel Fojt else if (sshkey_is_sk(id->key)) 6870cbfa66cSDaniel Fojt note = " authenticator"; 6880cbfa66cSDaniel Fojt } 689664f4763Szrj xasprintf(&ret, "%s %s%s%s%s%s%s", 690664f4763Szrj id->filename, 691664f4763Szrj id->key ? sshkey_type(id->key) : "", id->key ? " " : "", 692664f4763Szrj fp ? fp : "", 6930cbfa66cSDaniel Fojt id->userprovided ? " explicit" : "", note, 694664f4763Szrj id->agent_fd != -1 ? " agent" : ""); 695664f4763Szrj free(fp); 696664f4763Szrj return ret; 697664f4763Szrj } 698664f4763Szrj 699cb5eb4f1SPeter Avalos /* ARGSUSED */ 700664f4763Szrj static int 701ce74bacaSMatthew Dillon input_userauth_pk_ok(int type, u_int32_t seq, struct ssh *ssh) 70218de8d7fSPeter Avalos { 703ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 704ce74bacaSMatthew Dillon struct sshkey *key = NULL; 70518de8d7fSPeter Avalos Identity *id = NULL; 706664f4763Szrj int pktype, found = 0, sent = 0; 707664f4763Szrj size_t blen; 708664f4763Szrj char *pkalg = NULL, *fp = NULL, *ident = NULL; 709664f4763Szrj u_char *pkblob = NULL; 710664f4763Szrj int r; 71118de8d7fSPeter Avalos 71218de8d7fSPeter Avalos if (authctxt == NULL) 71318de8d7fSPeter Avalos fatal("input_userauth_pk_ok: no authentication context"); 71418de8d7fSPeter Avalos 715664f4763Szrj if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 || 716664f4763Szrj (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 || 717664f4763Szrj (r = sshpkt_get_end(ssh)) != 0) 718664f4763Szrj goto done; 71918de8d7fSPeter Avalos 720664f4763Szrj if ((pktype = sshkey_type_from_name(pkalg)) == KEY_UNSPEC) { 721*50a69bb5SSascha Wildner debug_f("server sent unknown pkalg %s", pkalg); 72218de8d7fSPeter Avalos goto done; 72318de8d7fSPeter Avalos } 724664f4763Szrj if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { 725*50a69bb5SSascha Wildner debug_r(r, "no key from blob. pkalg %s", pkalg); 72618de8d7fSPeter Avalos goto done; 72718de8d7fSPeter Avalos } 72818de8d7fSPeter Avalos if (key->type != pktype) { 72918de8d7fSPeter Avalos error("input_userauth_pk_ok: type mismatch " 73018de8d7fSPeter Avalos "for decoded key (received %d, expected %d)", 73118de8d7fSPeter Avalos key->type, pktype); 73218de8d7fSPeter Avalos goto done; 73318de8d7fSPeter Avalos } 73418de8d7fSPeter Avalos 73518de8d7fSPeter Avalos /* 73618de8d7fSPeter Avalos * search keys in the reverse order, because last candidate has been 73718de8d7fSPeter Avalos * moved to the end of the queue. this also avoids confusion by 73818de8d7fSPeter Avalos * duplicate keys 73918de8d7fSPeter Avalos */ 74018de8d7fSPeter Avalos TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { 741664f4763Szrj if (sshkey_equal(key, id->key)) { 742664f4763Szrj found = 1; 74318de8d7fSPeter Avalos break; 74418de8d7fSPeter Avalos } 74518de8d7fSPeter Avalos } 746664f4763Szrj if (!found || id == NULL) { 747664f4763Szrj fp = sshkey_fingerprint(key, options.fingerprint_hash, 748664f4763Szrj SSH_FP_DEFAULT); 749*50a69bb5SSascha Wildner error_f("server replied with unknown key: %s %s", 750664f4763Szrj sshkey_type(key), fp == NULL ? "<ERROR>" : fp); 751664f4763Szrj goto done; 752664f4763Szrj } 753664f4763Szrj ident = format_identity(id); 754664f4763Szrj debug("Server accepts key: %s", ident); 755664f4763Szrj sent = sign_and_send_pubkey(ssh, id); 756664f4763Szrj r = 0; 75718de8d7fSPeter Avalos done: 758664f4763Szrj sshkey_free(key); 759664f4763Szrj free(ident); 760664f4763Szrj free(fp); 76136e94dc5SPeter Avalos free(pkalg); 76236e94dc5SPeter Avalos free(pkblob); 76318de8d7fSPeter Avalos 76418de8d7fSPeter Avalos /* try another method if we did not send a packet */ 765664f4763Szrj if (r == 0 && sent == 0) 766664f4763Szrj userauth(ssh, NULL); 767664f4763Szrj return r; 76818de8d7fSPeter Avalos } 76918de8d7fSPeter Avalos 77018de8d7fSPeter Avalos #ifdef GSSAPI 771664f4763Szrj static int 772664f4763Szrj userauth_gssapi(struct ssh *ssh) 77318de8d7fSPeter Avalos { 774664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 77518de8d7fSPeter Avalos Gssctxt *gssctxt = NULL; 77618de8d7fSPeter Avalos OM_uint32 min; 777664f4763Szrj int r, ok = 0; 778664f4763Szrj gss_OID mech = NULL; 77918de8d7fSPeter Avalos 78018de8d7fSPeter Avalos /* Try one GSSAPI method at a time, rather than sending them all at 78118de8d7fSPeter Avalos * once. */ 78218de8d7fSPeter Avalos 783664f4763Szrj if (authctxt->gss_supported_mechs == NULL) 784664f4763Szrj gss_indicate_mechs(&min, &authctxt->gss_supported_mechs); 78518de8d7fSPeter Avalos 786664f4763Szrj /* Check to see whether the mechanism is usable before we offer it */ 787664f4763Szrj while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && 788664f4763Szrj !ok) { 789664f4763Szrj mech = &authctxt->gss_supported_mechs-> 790664f4763Szrj elements[authctxt->mech_tried]; 79118de8d7fSPeter Avalos /* My DER encoding requires length<128 */ 792664f4763Szrj if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, 793664f4763Szrj mech, authctxt->host)) { 79418de8d7fSPeter Avalos ok = 1; /* Mechanism works */ 79518de8d7fSPeter Avalos } else { 796664f4763Szrj authctxt->mech_tried++; 79718de8d7fSPeter Avalos } 79818de8d7fSPeter Avalos } 79918de8d7fSPeter Avalos 800664f4763Szrj if (!ok || mech == NULL) 80118de8d7fSPeter Avalos return 0; 80218de8d7fSPeter Avalos 80318de8d7fSPeter Avalos authctxt->methoddata=(void *)gssctxt; 80418de8d7fSPeter Avalos 805664f4763Szrj if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 806664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || 807664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || 808664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || 809664f4763Szrj (r = sshpkt_put_u32(ssh, 1)) != 0 || 810664f4763Szrj (r = sshpkt_put_u32(ssh, (mech->length) + 2)) != 0 || 811664f4763Szrj (r = sshpkt_put_u8(ssh, SSH_GSS_OIDTYPE)) != 0 || 812664f4763Szrj (r = sshpkt_put_u8(ssh, mech->length)) != 0 || 813664f4763Szrj (r = sshpkt_put(ssh, mech->elements, mech->length)) != 0 || 814664f4763Szrj (r = sshpkt_send(ssh)) != 0) 815*50a69bb5SSascha Wildner fatal_fr(r, "send packet"); 81618de8d7fSPeter Avalos 817664f4763Szrj ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response); 818664f4763Szrj ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); 819664f4763Szrj ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error); 820664f4763Szrj ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); 82118de8d7fSPeter Avalos 822664f4763Szrj authctxt->mech_tried++; /* Move along to next candidate */ 82318de8d7fSPeter Avalos 82418de8d7fSPeter Avalos return 1; 82518de8d7fSPeter Avalos } 82618de8d7fSPeter Avalos 827664f4763Szrj static void 828664f4763Szrj userauth_gssapi_cleanup(struct ssh *ssh) 829664f4763Szrj { 830664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 831664f4763Szrj Gssctxt *gssctxt = (Gssctxt *)authctxt->methoddata; 832664f4763Szrj 833664f4763Szrj ssh_gssapi_delete_ctx(&gssctxt); 834664f4763Szrj authctxt->methoddata = NULL; 835664f4763Szrj 836664f4763Szrj free(authctxt->gss_supported_mechs); 837664f4763Szrj authctxt->gss_supported_mechs = NULL; 838664f4763Szrj } 839664f4763Szrj 84018de8d7fSPeter Avalos static OM_uint32 841ce74bacaSMatthew Dillon process_gssapi_token(struct ssh *ssh, gss_buffer_t recv_tok) 84218de8d7fSPeter Avalos { 843ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 84418de8d7fSPeter Avalos Gssctxt *gssctxt = authctxt->methoddata; 84518de8d7fSPeter Avalos gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 84618de8d7fSPeter Avalos gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; 84718de8d7fSPeter Avalos gss_buffer_desc gssbuf; 84818de8d7fSPeter Avalos OM_uint32 status, ms, flags; 849664f4763Szrj int r; 85018de8d7fSPeter Avalos 85118de8d7fSPeter Avalos status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, 85218de8d7fSPeter Avalos recv_tok, &send_tok, &flags); 85318de8d7fSPeter Avalos 85418de8d7fSPeter Avalos if (send_tok.length > 0) { 855664f4763Szrj u_char type = GSS_ERROR(status) ? 856664f4763Szrj SSH2_MSG_USERAUTH_GSSAPI_ERRTOK : 857664f4763Szrj SSH2_MSG_USERAUTH_GSSAPI_TOKEN; 85818de8d7fSPeter Avalos 859664f4763Szrj if ((r = sshpkt_start(ssh, type)) != 0 || 860664f4763Szrj (r = sshpkt_put_string(ssh, send_tok.value, 861664f4763Szrj send_tok.length)) != 0 || 862664f4763Szrj (r = sshpkt_send(ssh)) != 0) 863*50a69bb5SSascha Wildner fatal_fr(r, "send %u packet", type); 864664f4763Szrj 86518de8d7fSPeter Avalos gss_release_buffer(&ms, &send_tok); 86618de8d7fSPeter Avalos } 86718de8d7fSPeter Avalos 86818de8d7fSPeter Avalos if (status == GSS_S_COMPLETE) { 86918de8d7fSPeter Avalos /* send either complete or MIC, depending on mechanism */ 87018de8d7fSPeter Avalos if (!(flags & GSS_C_INTEG_FLAG)) { 871664f4763Szrj if ((r = sshpkt_start(ssh, 872664f4763Szrj SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE)) != 0 || 873664f4763Szrj (r = sshpkt_send(ssh)) != 0) 874*50a69bb5SSascha Wildner fatal_fr(r, "send completion"); 87518de8d7fSPeter Avalos } else { 876664f4763Szrj struct sshbuf *b; 877664f4763Szrj 878664f4763Szrj if ((b = sshbuf_new()) == NULL) 879*50a69bb5SSascha Wildner fatal_f("sshbuf_new failed"); 880664f4763Szrj ssh_gssapi_buildmic(b, authctxt->server_user, 881*50a69bb5SSascha Wildner authctxt->service, "gssapi-with-mic", 882*50a69bb5SSascha Wildner ssh->kex->session_id); 88318de8d7fSPeter Avalos 884664f4763Szrj if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) 885*50a69bb5SSascha Wildner fatal_f("sshbuf_mutable_ptr failed"); 886664f4763Szrj gssbuf.length = sshbuf_len(b); 88718de8d7fSPeter Avalos 88818de8d7fSPeter Avalos status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic); 88918de8d7fSPeter Avalos 89018de8d7fSPeter Avalos if (!GSS_ERROR(status)) { 891664f4763Szrj if ((r = sshpkt_start(ssh, 892664f4763Szrj SSH2_MSG_USERAUTH_GSSAPI_MIC)) != 0 || 893664f4763Szrj (r = sshpkt_put_string(ssh, mic.value, 894664f4763Szrj mic.length)) != 0 || 895664f4763Szrj (r = sshpkt_send(ssh)) != 0) 896*50a69bb5SSascha Wildner fatal_fr(r, "send MIC"); 89718de8d7fSPeter Avalos } 89818de8d7fSPeter Avalos 899664f4763Szrj sshbuf_free(b); 90018de8d7fSPeter Avalos gss_release_buffer(&ms, &mic); 90118de8d7fSPeter Avalos } 90218de8d7fSPeter Avalos } 90318de8d7fSPeter Avalos 90418de8d7fSPeter Avalos return status; 90518de8d7fSPeter Avalos } 90618de8d7fSPeter Avalos 907cb5eb4f1SPeter Avalos /* ARGSUSED */ 908664f4763Szrj static int 909ce74bacaSMatthew Dillon input_gssapi_response(int type, u_int32_t plen, struct ssh *ssh) 91018de8d7fSPeter Avalos { 911ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 91218de8d7fSPeter Avalos Gssctxt *gssctxt; 913664f4763Szrj size_t oidlen; 914664f4763Szrj u_char *oidv = NULL; 915664f4763Szrj int r; 91618de8d7fSPeter Avalos 91718de8d7fSPeter Avalos if (authctxt == NULL) 91818de8d7fSPeter Avalos fatal("input_gssapi_response: no authentication context"); 91918de8d7fSPeter Avalos gssctxt = authctxt->methoddata; 92018de8d7fSPeter Avalos 92118de8d7fSPeter Avalos /* Setup our OID */ 922664f4763Szrj if ((r = sshpkt_get_string(ssh, &oidv, &oidlen)) != 0) 923664f4763Szrj goto done; 92418de8d7fSPeter Avalos 92518de8d7fSPeter Avalos if (oidlen <= 2 || 92618de8d7fSPeter Avalos oidv[0] != SSH_GSS_OIDTYPE || 92718de8d7fSPeter Avalos oidv[1] != oidlen - 2) { 92818de8d7fSPeter Avalos debug("Badly encoded mechanism OID received"); 929664f4763Szrj userauth(ssh, NULL); 930664f4763Szrj goto ok; 93118de8d7fSPeter Avalos } 93218de8d7fSPeter Avalos 93318de8d7fSPeter Avalos if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) 93418de8d7fSPeter Avalos fatal("Server returned different OID than expected"); 93518de8d7fSPeter Avalos 936664f4763Szrj if ((r = sshpkt_get_end(ssh)) != 0) 937664f4763Szrj goto done; 93818de8d7fSPeter Avalos 939ce74bacaSMatthew Dillon if (GSS_ERROR(process_gssapi_token(ssh, GSS_C_NO_BUFFER))) { 94018de8d7fSPeter Avalos /* Start again with next method on list */ 94118de8d7fSPeter Avalos debug("Trying to start again"); 942664f4763Szrj userauth(ssh, NULL); 943664f4763Szrj goto ok; 94418de8d7fSPeter Avalos } 945664f4763Szrj ok: 946664f4763Szrj r = 0; 947664f4763Szrj done: 948664f4763Szrj free(oidv); 949664f4763Szrj return r; 95018de8d7fSPeter Avalos } 95118de8d7fSPeter Avalos 952cb5eb4f1SPeter Avalos /* ARGSUSED */ 953664f4763Szrj static int 954ce74bacaSMatthew Dillon input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh) 95518de8d7fSPeter Avalos { 956ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 95718de8d7fSPeter Avalos gss_buffer_desc recv_tok; 958664f4763Szrj u_char *p = NULL; 959664f4763Szrj size_t len; 96018de8d7fSPeter Avalos OM_uint32 status; 961664f4763Szrj int r; 96218de8d7fSPeter Avalos 96318de8d7fSPeter Avalos if (authctxt == NULL) 96418de8d7fSPeter Avalos fatal("input_gssapi_response: no authentication context"); 96518de8d7fSPeter Avalos 966664f4763Szrj if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 || 967664f4763Szrj (r = sshpkt_get_end(ssh)) != 0) 968664f4763Szrj goto out; 96918de8d7fSPeter Avalos 970664f4763Szrj recv_tok.value = p; 971664f4763Szrj recv_tok.length = len; 972ce74bacaSMatthew Dillon status = process_gssapi_token(ssh, &recv_tok); 97318de8d7fSPeter Avalos 97418de8d7fSPeter Avalos /* Start again with the next method in the list */ 975664f4763Szrj if (GSS_ERROR(status)) { 976664f4763Szrj userauth(ssh, NULL); 977664f4763Szrj /* ok */ 97818de8d7fSPeter Avalos } 979664f4763Szrj r = 0; 980664f4763Szrj out: 981664f4763Szrj free(p); 982664f4763Szrj return r; 98318de8d7fSPeter Avalos } 98418de8d7fSPeter Avalos 985cb5eb4f1SPeter Avalos /* ARGSUSED */ 986664f4763Szrj static int 987ce74bacaSMatthew Dillon input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh) 98818de8d7fSPeter Avalos { 989ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 99018de8d7fSPeter Avalos Gssctxt *gssctxt; 99118de8d7fSPeter Avalos gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 99218de8d7fSPeter Avalos gss_buffer_desc recv_tok; 99336e94dc5SPeter Avalos OM_uint32 ms; 994664f4763Szrj u_char *p = NULL; 995664f4763Szrj size_t len; 996664f4763Szrj int r; 99718de8d7fSPeter Avalos 99818de8d7fSPeter Avalos if (authctxt == NULL) 99918de8d7fSPeter Avalos fatal("input_gssapi_response: no authentication context"); 100018de8d7fSPeter Avalos gssctxt = authctxt->methoddata; 100118de8d7fSPeter Avalos 1002664f4763Szrj if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 || 1003664f4763Szrj (r = sshpkt_get_end(ssh)) != 0) { 1004664f4763Szrj free(p); 1005664f4763Szrj return r; 1006664f4763Szrj } 100718de8d7fSPeter Avalos 100818de8d7fSPeter Avalos /* Stick it into GSSAPI and see what it says */ 1009664f4763Szrj recv_tok.value = p; 1010664f4763Szrj recv_tok.length = len; 101136e94dc5SPeter Avalos (void)ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, 101218de8d7fSPeter Avalos &recv_tok, &send_tok, NULL); 1013664f4763Szrj free(p); 101418de8d7fSPeter Avalos gss_release_buffer(&ms, &send_tok); 101518de8d7fSPeter Avalos 101618de8d7fSPeter Avalos /* Server will be returning a failed packet after this one */ 1017e9778795SPeter Avalos return 0; 101818de8d7fSPeter Avalos } 101918de8d7fSPeter Avalos 1020cb5eb4f1SPeter Avalos /* ARGSUSED */ 1021664f4763Szrj static int 1022ce74bacaSMatthew Dillon input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) 102318de8d7fSPeter Avalos { 1024664f4763Szrj char *msg = NULL; 1025664f4763Szrj char *lang = NULL; 1026664f4763Szrj int r; 102718de8d7fSPeter Avalos 1028664f4763Szrj if ((r = sshpkt_get_u32(ssh, NULL)) != 0 || /* maj */ 1029664f4763Szrj (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* min */ 1030664f4763Szrj (r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 || 1031664f4763Szrj (r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0) 1032664f4763Szrj goto out; 1033664f4763Szrj r = sshpkt_get_end(ssh); 103418de8d7fSPeter Avalos debug("Server GSSAPI Error:\n%s", msg); 1035664f4763Szrj out: 103636e94dc5SPeter Avalos free(msg); 103736e94dc5SPeter Avalos free(lang); 1038664f4763Szrj return r; 103918de8d7fSPeter Avalos } 104018de8d7fSPeter Avalos #endif /* GSSAPI */ 104118de8d7fSPeter Avalos 1042664f4763Szrj static int 1043664f4763Szrj userauth_none(struct ssh *ssh) 104418de8d7fSPeter Avalos { 1045664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 1046664f4763Szrj int r; 1047664f4763Szrj 104818de8d7fSPeter Avalos /* initial userauth request */ 1049664f4763Szrj if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1050664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || 1051664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || 1052664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || 1053664f4763Szrj (r = sshpkt_send(ssh)) != 0) 1054*50a69bb5SSascha Wildner fatal_fr(r, "send packet"); 105518de8d7fSPeter Avalos return 1; 105618de8d7fSPeter Avalos } 105718de8d7fSPeter Avalos 1058664f4763Szrj static int 1059664f4763Szrj userauth_passwd(struct ssh *ssh) 106018de8d7fSPeter Avalos { 1061664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 1062664f4763Szrj char *password, *prompt = NULL; 1063856ea928SPeter Avalos const char *host = options.host_key_alias ? options.host_key_alias : 1064856ea928SPeter Avalos authctxt->host; 1065664f4763Szrj int r; 106618de8d7fSPeter Avalos 1067664f4763Szrj if (authctxt->attempt_passwd++ >= options.number_of_password_prompts) 106818de8d7fSPeter Avalos return 0; 106918de8d7fSPeter Avalos 1070664f4763Szrj if (authctxt->attempt_passwd != 1) 107118de8d7fSPeter Avalos error("Permission denied, please try again."); 107218de8d7fSPeter Avalos 1073664f4763Szrj xasprintf(&prompt, "%s@%s's password: ", authctxt->server_user, host); 107418de8d7fSPeter Avalos password = read_passphrase(prompt, 0); 1075664f4763Szrj if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1076664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || 1077664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || 1078664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || 1079664f4763Szrj (r = sshpkt_put_u8(ssh, 0)) != 0 || 1080664f4763Szrj (r = sshpkt_put_cstring(ssh, password)) != 0 || 1081664f4763Szrj (r = sshpkt_add_padding(ssh, 64)) != 0 || 1082664f4763Szrj (r = sshpkt_send(ssh)) != 0) 1083*50a69bb5SSascha Wildner fatal_fr(r, "send packet"); 108418de8d7fSPeter Avalos 1085664f4763Szrj free(prompt); 1086664f4763Szrj if (password != NULL) 1087664f4763Szrj freezero(password, strlen(password)); 1088664f4763Szrj 1089664f4763Szrj ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 109018de8d7fSPeter Avalos &input_userauth_passwd_changereq); 109118de8d7fSPeter Avalos 109218de8d7fSPeter Avalos return 1; 109318de8d7fSPeter Avalos } 1094cb5eb4f1SPeter Avalos 109518de8d7fSPeter Avalos /* 109618de8d7fSPeter Avalos * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST 109718de8d7fSPeter Avalos */ 1098cb5eb4f1SPeter Avalos /* ARGSUSED */ 1099664f4763Szrj static int 1100ce74bacaSMatthew Dillon input_userauth_passwd_changereq(int type, u_int32_t seqnr, struct ssh *ssh) 110118de8d7fSPeter Avalos { 1102ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 1103664f4763Szrj char *info = NULL, *lang = NULL, *password = NULL, *retype = NULL; 1104ce74bacaSMatthew Dillon char prompt[256]; 1105ce74bacaSMatthew Dillon const char *host; 1106664f4763Szrj int r; 110718de8d7fSPeter Avalos 110818de8d7fSPeter Avalos debug2("input_userauth_passwd_changereq"); 110918de8d7fSPeter Avalos 111018de8d7fSPeter Avalos if (authctxt == NULL) 111118de8d7fSPeter Avalos fatal("input_userauth_passwd_changereq: " 111218de8d7fSPeter Avalos "no authentication context"); 1113ce74bacaSMatthew Dillon host = options.host_key_alias ? options.host_key_alias : authctxt->host; 111418de8d7fSPeter Avalos 1115664f4763Szrj if ((r = sshpkt_get_cstring(ssh, &info, NULL)) != 0 || 1116664f4763Szrj (r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0) 1117664f4763Szrj goto out; 111818de8d7fSPeter Avalos if (strlen(info) > 0) 111918de8d7fSPeter Avalos logit("%s", info); 1120664f4763Szrj if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1121664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || 1122664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || 1123664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || 1124664f4763Szrj (r = sshpkt_put_u8(ssh, 1)) != 0) /* additional info */ 1125664f4763Szrj goto out; 1126664f4763Szrj 112718de8d7fSPeter Avalos snprintf(prompt, sizeof(prompt), 112818de8d7fSPeter Avalos "Enter %.30s@%.128s's old password: ", 1129856ea928SPeter Avalos authctxt->server_user, host); 113018de8d7fSPeter Avalos password = read_passphrase(prompt, 0); 1131664f4763Szrj if ((r = sshpkt_put_cstring(ssh, password)) != 0) 1132664f4763Szrj goto out; 1133664f4763Szrj 1134664f4763Szrj freezero(password, strlen(password)); 113518de8d7fSPeter Avalos password = NULL; 113618de8d7fSPeter Avalos while (password == NULL) { 113718de8d7fSPeter Avalos snprintf(prompt, sizeof(prompt), 113818de8d7fSPeter Avalos "Enter %.30s@%.128s's new password: ", 1139856ea928SPeter Avalos authctxt->server_user, host); 114018de8d7fSPeter Avalos password = read_passphrase(prompt, RP_ALLOW_EOF); 114118de8d7fSPeter Avalos if (password == NULL) { 114218de8d7fSPeter Avalos /* bail out */ 1143664f4763Szrj r = 0; 1144664f4763Szrj goto out; 114518de8d7fSPeter Avalos } 114618de8d7fSPeter Avalos snprintf(prompt, sizeof(prompt), 114718de8d7fSPeter Avalos "Retype %.30s@%.128s's new password: ", 1148856ea928SPeter Avalos authctxt->server_user, host); 114918de8d7fSPeter Avalos retype = read_passphrase(prompt, 0); 115018de8d7fSPeter Avalos if (strcmp(password, retype) != 0) { 1151664f4763Szrj freezero(password, strlen(password)); 115218de8d7fSPeter Avalos logit("Mismatch; try again, EOF to quit."); 115318de8d7fSPeter Avalos password = NULL; 115418de8d7fSPeter Avalos } 1155664f4763Szrj freezero(retype, strlen(retype)); 115618de8d7fSPeter Avalos } 1157664f4763Szrj if ((r = sshpkt_put_cstring(ssh, password)) != 0 || 1158664f4763Szrj (r = sshpkt_add_padding(ssh, 64)) != 0 || 1159664f4763Szrj (r = sshpkt_send(ssh)) != 0) 1160664f4763Szrj goto out; 116118de8d7fSPeter Avalos 1162664f4763Szrj ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 116318de8d7fSPeter Avalos &input_userauth_passwd_changereq); 1164664f4763Szrj r = 0; 1165664f4763Szrj out: 1166664f4763Szrj if (password) 1167664f4763Szrj freezero(password, strlen(password)); 1168664f4763Szrj free(info); 1169664f4763Szrj free(lang); 1170664f4763Szrj return r; 1171e9778795SPeter Avalos } 1172e9778795SPeter Avalos 1173664f4763Szrj /* 1174664f4763Szrj * Select an algorithm for publickey signatures. 1175664f4763Szrj * Returns algorithm (caller must free) or NULL if no mutual algorithm found. 1176664f4763Szrj * 1177664f4763Szrj * Call with ssh==NULL to ignore server-sig-algs extension list and 1178664f4763Szrj * only attempt with the key's base signature type. 1179664f4763Szrj */ 1180664f4763Szrj static char * 1181664f4763Szrj key_sig_algorithm(struct ssh *ssh, const struct sshkey *key) 1182e9778795SPeter Avalos { 1183664f4763Szrj char *allowed, *oallowed, *cp, *tmp, *alg = NULL; 1184*50a69bb5SSascha Wildner const char *server_sig_algs; 1185e9778795SPeter Avalos 1186664f4763Szrj /* 1187664f4763Szrj * The signature algorithm will only differ from the key algorithm 1188664f4763Szrj * for RSA keys/certs and when the server advertises support for 1189664f4763Szrj * newer (SHA2) algorithms. 1190664f4763Szrj */ 1191664f4763Szrj if (ssh == NULL || ssh->kex->server_sig_algs == NULL || 1192664f4763Szrj (key->type != KEY_RSA && key->type != KEY_RSA_CERT) || 1193*50a69bb5SSascha Wildner (key->type == KEY_RSA_CERT && (ssh->compat & SSH_BUG_SIGTYPE))) { 1194664f4763Szrj /* Filter base key signature alg against our configuration */ 1195664f4763Szrj return match_list(sshkey_ssh_name(key), 1196*50a69bb5SSascha Wildner options.pubkey_accepted_algos, NULL); 1197e9778795SPeter Avalos } 1198664f4763Szrj 1199664f4763Szrj /* 1200*50a69bb5SSascha Wildner * Workaround OpenSSH 7.4 bug: this version supports RSA/SHA-2 but 1201*50a69bb5SSascha Wildner * fails to advertise it via SSH2_MSG_EXT_INFO. 1202*50a69bb5SSascha Wildner */ 1203*50a69bb5SSascha Wildner server_sig_algs = ssh->kex->server_sig_algs; 1204*50a69bb5SSascha Wildner if (key->type == KEY_RSA && (ssh->compat & SSH_BUG_SIGTYPE74)) 1205*50a69bb5SSascha Wildner server_sig_algs = "rsa-sha2-256,rsa-sha2-512"; 1206*50a69bb5SSascha Wildner 1207*50a69bb5SSascha Wildner /* 1208664f4763Szrj * For RSA keys/certs, since these might have a different sig type: 1209*50a69bb5SSascha Wildner * find the first entry in PubkeyAcceptedAlgorithms of the right type 1210664f4763Szrj * that also appears in the supported signature algorithms list from 1211664f4763Szrj * the server. 1212664f4763Szrj */ 1213*50a69bb5SSascha Wildner oallowed = allowed = xstrdup(options.pubkey_accepted_algos); 1214664f4763Szrj while ((cp = strsep(&allowed, ",")) != NULL) { 1215664f4763Szrj if (sshkey_type_from_name(cp) != key->type) 1216664f4763Szrj continue; 1217*50a69bb5SSascha Wildner tmp = match_list(sshkey_sigalg_by_name(cp), 1218*50a69bb5SSascha Wildner server_sig_algs, NULL); 1219664f4763Szrj if (tmp != NULL) 1220664f4763Szrj alg = xstrdup(cp); 1221664f4763Szrj free(tmp); 1222664f4763Szrj if (alg != NULL) 1223664f4763Szrj break; 1224e9778795SPeter Avalos } 1225664f4763Szrj free(oallowed); 1226664f4763Szrj return alg; 122718de8d7fSPeter Avalos } 122818de8d7fSPeter Avalos 122918de8d7fSPeter Avalos static int 1230e9778795SPeter Avalos identity_sign(struct identity *id, u_char **sigp, size_t *lenp, 1231664f4763Szrj const u_char *data, size_t datalen, u_int compat, const char *alg) 123218de8d7fSPeter Avalos { 12330cbfa66cSDaniel Fojt struct sshkey *sign_key = NULL, *prv = NULL; 1234*50a69bb5SSascha Wildner int retried = 0, r = SSH_ERR_INTERNAL_ERROR; 12350cbfa66cSDaniel Fojt struct notifier_ctx *notifier = NULL; 1236*50a69bb5SSascha Wildner char *fp = NULL, *pin = NULL, *prompt = NULL; 12370cbfa66cSDaniel Fojt 12380cbfa66cSDaniel Fojt *sigp = NULL; 12390cbfa66cSDaniel Fojt *lenp = 0; 124018de8d7fSPeter Avalos 1241664f4763Szrj /* The agent supports this key. */ 1242664f4763Szrj if (id->key != NULL && id->agent_fd != -1) { 1243e9778795SPeter Avalos return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, 1244664f4763Szrj data, datalen, alg, compat); 1245664f4763Szrj } 1246e9778795SPeter Avalos 124718de8d7fSPeter Avalos /* 1248664f4763Szrj * We have already loaded the private key or the private key is 1249664f4763Szrj * stored in external hardware. 125018de8d7fSPeter Avalos */ 1251ce74bacaSMatthew Dillon if (id->key != NULL && 1252664f4763Szrj (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) { 12530cbfa66cSDaniel Fojt sign_key = id->key; 12540cbfa66cSDaniel Fojt } else { 1255664f4763Szrj /* Load the private key from the file. */ 1256e9778795SPeter Avalos if ((prv = load_identity_file(id)) == NULL) 1257e9778795SPeter Avalos return SSH_ERR_KEY_NOT_FOUND; 1258ce74bacaSMatthew Dillon if (id->key != NULL && !sshkey_equal_public(prv, id->key)) { 1259*50a69bb5SSascha Wildner error_f("private key %s contents do not match public", 1260*50a69bb5SSascha Wildner id->filename); 12610cbfa66cSDaniel Fojt r = SSH_ERR_KEY_NOT_FOUND; 12620cbfa66cSDaniel Fojt goto out; 1263ce74bacaSMatthew Dillon } 12640cbfa66cSDaniel Fojt sign_key = prv; 1265*50a69bb5SSascha Wildner if (sshkey_is_sk(sign_key)) { 1266*50a69bb5SSascha Wildner if ((sign_key->sk_flags & 1267*50a69bb5SSascha Wildner SSH_SK_USER_VERIFICATION_REQD)) { 1268*50a69bb5SSascha Wildner retry_pin: 1269*50a69bb5SSascha Wildner xasprintf(&prompt, "Enter PIN for %s key %s: ", 1270*50a69bb5SSascha Wildner sshkey_type(sign_key), id->filename); 1271*50a69bb5SSascha Wildner pin = read_passphrase(prompt, 0); 1272*50a69bb5SSascha Wildner } 1273*50a69bb5SSascha Wildner if ((sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { 1274*50a69bb5SSascha Wildner /* XXX should batch mode just skip these? */ 12750cbfa66cSDaniel Fojt if ((fp = sshkey_fingerprint(sign_key, 1276*50a69bb5SSascha Wildner options.fingerprint_hash, 1277*50a69bb5SSascha Wildner SSH_FP_DEFAULT)) == NULL) 1278*50a69bb5SSascha Wildner fatal_f("fingerprint failed"); 12790cbfa66cSDaniel Fojt notifier = notify_start(options.batch_mode, 12800cbfa66cSDaniel Fojt "Confirm user presence for key %s %s", 12810cbfa66cSDaniel Fojt sshkey_type(sign_key), fp); 12820cbfa66cSDaniel Fojt free(fp); 12830cbfa66cSDaniel Fojt } 12840cbfa66cSDaniel Fojt } 1285*50a69bb5SSascha Wildner } 12860cbfa66cSDaniel Fojt if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, 1287*50a69bb5SSascha Wildner alg, options.sk_provider, pin, compat)) != 0) { 1288*50a69bb5SSascha Wildner debug_fr(r, "sshkey_sign"); 1289*50a69bb5SSascha Wildner if (pin == NULL && !retried && sshkey_is_sk(sign_key) && 1290*50a69bb5SSascha Wildner r == SSH_ERR_KEY_WRONG_PASSPHRASE) { 1291*50a69bb5SSascha Wildner notify_complete(notifier, NULL); 1292*50a69bb5SSascha Wildner notifier = NULL; 1293*50a69bb5SSascha Wildner retried = 1; 1294*50a69bb5SSascha Wildner goto retry_pin; 1295*50a69bb5SSascha Wildner } 12960cbfa66cSDaniel Fojt goto out; 12970cbfa66cSDaniel Fojt } 1298*50a69bb5SSascha Wildner 12990cbfa66cSDaniel Fojt /* 13000cbfa66cSDaniel Fojt * PKCS#11 tokens may not support all signature algorithms, 13010cbfa66cSDaniel Fojt * so check what we get back. 13020cbfa66cSDaniel Fojt */ 13030cbfa66cSDaniel Fojt if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) { 1304*50a69bb5SSascha Wildner debug_fr(r, "sshkey_check_sigtype"); 13050cbfa66cSDaniel Fojt goto out; 13060cbfa66cSDaniel Fojt } 13070cbfa66cSDaniel Fojt /* success */ 13080cbfa66cSDaniel Fojt r = 0; 13090cbfa66cSDaniel Fojt out: 1310*50a69bb5SSascha Wildner free(prompt); 1311*50a69bb5SSascha Wildner if (pin != NULL) 1312*50a69bb5SSascha Wildner freezero(pin, strlen(pin)); 1313*50a69bb5SSascha Wildner notify_complete(notifier, r == 0 ? "User presence confirmed" : NULL); 1314e9778795SPeter Avalos sshkey_free(prv); 1315664f4763Szrj return r; 131618de8d7fSPeter Avalos } 131718de8d7fSPeter Avalos 131818de8d7fSPeter Avalos static int 1319ce74bacaSMatthew Dillon id_filename_matches(Identity *id, Identity *private_id) 1320ce74bacaSMatthew Dillon { 1321ce74bacaSMatthew Dillon const char *suffixes[] = { ".pub", "-cert.pub", NULL }; 1322ce74bacaSMatthew Dillon size_t len = strlen(id->filename), plen = strlen(private_id->filename); 1323ce74bacaSMatthew Dillon size_t i, slen; 1324ce74bacaSMatthew Dillon 1325ce74bacaSMatthew Dillon if (strcmp(id->filename, private_id->filename) == 0) 1326ce74bacaSMatthew Dillon return 1; 1327ce74bacaSMatthew Dillon for (i = 0; suffixes[i]; i++) { 1328ce74bacaSMatthew Dillon slen = strlen(suffixes[i]); 1329ce74bacaSMatthew Dillon if (len > slen && plen == len - slen && 1330ce74bacaSMatthew Dillon strcmp(id->filename + (len - slen), suffixes[i]) == 0 && 1331ce74bacaSMatthew Dillon memcmp(id->filename, private_id->filename, plen) == 0) 1332ce74bacaSMatthew Dillon return 1; 1333ce74bacaSMatthew Dillon } 1334ce74bacaSMatthew Dillon return 0; 1335ce74bacaSMatthew Dillon } 1336ce74bacaSMatthew Dillon 1337ce74bacaSMatthew Dillon static int 1338664f4763Szrj sign_and_send_pubkey(struct ssh *ssh, Identity *id) 133918de8d7fSPeter Avalos { 1340664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 1341664f4763Szrj struct sshbuf *b = NULL; 1342664f4763Szrj Identity *private_id, *sign_id = NULL; 1343664f4763Szrj u_char *signature = NULL; 1344664f4763Szrj size_t slen = 0, skip = 0; 1345664f4763Szrj int r, fallback_sigtype, sent = 0; 1346664f4763Szrj char *alg = NULL, *fp = NULL; 1347664f4763Szrj const char *loc = ""; 134818de8d7fSPeter Avalos 1349e9778795SPeter Avalos if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, 1350e9778795SPeter Avalos SSH_FP_DEFAULT)) == NULL) 1351e9778795SPeter Avalos return 0; 135218de8d7fSPeter Avalos 1353*50a69bb5SSascha Wildner debug3_f("%s %s", sshkey_type(id->key), fp); 135418de8d7fSPeter Avalos 1355e9778795SPeter Avalos /* 1356e9778795SPeter Avalos * If the key is an certificate, try to find a matching private key 1357e9778795SPeter Avalos * and use it to complete the signature. 1358e9778795SPeter Avalos * If no such private key exists, fall back to trying the certificate 1359e9778795SPeter Avalos * key itself in case it has a private half already loaded. 1360664f4763Szrj * This will try to set sign_id to the private key that will perform 1361664f4763Szrj * the signature. 1362e9778795SPeter Avalos */ 1363664f4763Szrj if (sshkey_is_cert(id->key)) { 1364e9778795SPeter Avalos TAILQ_FOREACH(private_id, &authctxt->keys, next) { 1365e9778795SPeter Avalos if (sshkey_equal_public(id->key, private_id->key) && 1366e9778795SPeter Avalos id->key->type != private_id->key->type) { 1367664f4763Szrj sign_id = private_id; 1368e9778795SPeter Avalos break; 1369e9778795SPeter Avalos } 1370e9778795SPeter Avalos } 1371ce74bacaSMatthew Dillon /* 1372ce74bacaSMatthew Dillon * Exact key matches are preferred, but also allow 1373ce74bacaSMatthew Dillon * filename matches for non-PKCS#11/agent keys that 1374ce74bacaSMatthew Dillon * didn't load public keys. This supports the case 1375ce74bacaSMatthew Dillon * of keeping just a private key file and public 1376ce74bacaSMatthew Dillon * certificate on disk. 1377ce74bacaSMatthew Dillon */ 1378664f4763Szrj if (sign_id == NULL && 1379664f4763Szrj !id->isprivate && id->agent_fd == -1 && 1380ce74bacaSMatthew Dillon (id->key->flags & SSHKEY_FLAG_EXT) == 0) { 1381ce74bacaSMatthew Dillon TAILQ_FOREACH(private_id, &authctxt->keys, next) { 1382ce74bacaSMatthew Dillon if (private_id->key == NULL && 1383ce74bacaSMatthew Dillon id_filename_matches(id, private_id)) { 1384664f4763Szrj sign_id = private_id; 1385ce74bacaSMatthew Dillon break; 1386ce74bacaSMatthew Dillon } 1387ce74bacaSMatthew Dillon } 1388ce74bacaSMatthew Dillon } 1389664f4763Szrj if (sign_id != NULL) { 1390*50a69bb5SSascha Wildner debug2_f("using private key \"%s\"%s for " 1391*50a69bb5SSascha Wildner "certificate", sign_id->filename, 1392*50a69bb5SSascha Wildner sign_id->agent_fd != -1 ? " from agent" : ""); 1393e9778795SPeter Avalos } else { 1394*50a69bb5SSascha Wildner debug_f("no separate private key for certificate " 1395*50a69bb5SSascha Wildner "\"%s\"", id->filename); 1396e9778795SPeter Avalos } 1397e9778795SPeter Avalos } 1398e9778795SPeter Avalos 1399664f4763Szrj /* 1400664f4763Szrj * If the above didn't select another identity to do the signing 1401664f4763Szrj * then default to the one we started with. 1402664f4763Szrj */ 1403664f4763Szrj if (sign_id == NULL) 1404664f4763Szrj sign_id = id; 1405664f4763Szrj 1406664f4763Szrj /* assemble and sign data */ 1407664f4763Szrj for (fallback_sigtype = 0; fallback_sigtype <= 1; fallback_sigtype++) { 1408664f4763Szrj free(alg); 1409664f4763Szrj slen = 0; 1410664f4763Szrj signature = NULL; 1411664f4763Szrj if ((alg = key_sig_algorithm(fallback_sigtype ? NULL : ssh, 1412664f4763Szrj id->key)) == NULL) { 1413*50a69bb5SSascha Wildner error_f("no mutual signature supported"); 1414664f4763Szrj goto out; 1415664f4763Szrj } 1416*50a69bb5SSascha Wildner debug3_f("signing using %s %s", alg, fp); 1417664f4763Szrj 1418664f4763Szrj sshbuf_free(b); 1419664f4763Szrj if ((b = sshbuf_new()) == NULL) 1420*50a69bb5SSascha Wildner fatal_f("sshbuf_new failed"); 1421*50a69bb5SSascha Wildner if (ssh->compat & SSH_OLD_SESSIONID) { 1422*50a69bb5SSascha Wildner if ((r = sshbuf_putb(b, ssh->kex->session_id)) != 0) 1423*50a69bb5SSascha Wildner fatal_fr(r, "sshbuf_putb"); 1424664f4763Szrj } else { 1425*50a69bb5SSascha Wildner if ((r = sshbuf_put_stringb(b, 1426*50a69bb5SSascha Wildner ssh->kex->session_id)) != 0) 1427*50a69bb5SSascha Wildner fatal_fr(r, "sshbuf_put_stringb"); 1428664f4763Szrj } 1429664f4763Szrj skip = sshbuf_len(b); 1430664f4763Szrj if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1431664f4763Szrj (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || 1432664f4763Szrj (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || 1433664f4763Szrj (r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 || 1434664f4763Szrj (r = sshbuf_put_u8(b, 1)) != 0 || 1435664f4763Szrj (r = sshbuf_put_cstring(b, alg)) != 0 || 1436664f4763Szrj (r = sshkey_puts(id->key, b)) != 0) { 1437*50a69bb5SSascha Wildner fatal_fr(r, "assemble signed data"); 1438664f4763Szrj } 1439664f4763Szrj 144018de8d7fSPeter Avalos /* generate signature */ 1441664f4763Szrj r = identity_sign(sign_id, &signature, &slen, 1442*50a69bb5SSascha Wildner sshbuf_ptr(b), sshbuf_len(b), ssh->compat, alg); 1443664f4763Szrj if (r == 0) 1444664f4763Szrj break; 1445664f4763Szrj else if (r == SSH_ERR_KEY_NOT_FOUND) 1446664f4763Szrj goto out; /* soft failure */ 1447664f4763Szrj else if (r == SSH_ERR_SIGN_ALG_UNSUPPORTED && 1448664f4763Szrj !fallback_sigtype) { 1449664f4763Szrj if (sign_id->agent_fd != -1) 1450664f4763Szrj loc = "agent "; 1451664f4763Szrj else if ((sign_id->key->flags & SSHKEY_FLAG_EXT) != 0) 1452664f4763Szrj loc = "token "; 1453664f4763Szrj logit("%skey %s %s returned incorrect signature type", 1454664f4763Szrj loc, sshkey_type(id->key), fp); 1455664f4763Szrj continue; 145618de8d7fSPeter Avalos } 1457*50a69bb5SSascha Wildner error_fr(r, "signing failed for %s \"%s\"%s", 14580cbfa66cSDaniel Fojt sshkey_type(sign_id->key), sign_id->filename, 1459*50a69bb5SSascha Wildner id->agent_fd != -1 ? " from agent" : ""); 1460664f4763Szrj goto out; 146118de8d7fSPeter Avalos } 1462664f4763Szrj if (slen == 0 || signature == NULL) /* shouldn't happen */ 1463*50a69bb5SSascha Wildner fatal_f("no signature"); 146418de8d7fSPeter Avalos 146518de8d7fSPeter Avalos /* append signature */ 1466664f4763Szrj if ((r = sshbuf_put_string(b, signature, slen)) != 0) 1467*50a69bb5SSascha Wildner fatal_fr(r, "append signature"); 146818de8d7fSPeter Avalos 1469664f4763Szrj #ifdef DEBUG_PK 1470664f4763Szrj sshbuf_dump(b, stderr); 1471664f4763Szrj #endif 147218de8d7fSPeter Avalos /* skip session id and packet type */ 1473664f4763Szrj if ((r = sshbuf_consume(b, skip + 1)) != 0) 1474*50a69bb5SSascha Wildner fatal_fr(r, "consume"); 147518de8d7fSPeter Avalos 147618de8d7fSPeter Avalos /* put remaining data from buffer into packet */ 1477664f4763Szrj if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1478664f4763Szrj (r = sshpkt_putb(ssh, b)) != 0 || 1479664f4763Szrj (r = sshpkt_send(ssh)) != 0) 1480*50a69bb5SSascha Wildner fatal_fr(r, "enqueue request"); 148118de8d7fSPeter Avalos 1482664f4763Szrj /* success */ 1483664f4763Szrj sent = 1; 1484664f4763Szrj 1485664f4763Szrj out: 1486664f4763Szrj free(fp); 1487664f4763Szrj free(alg); 1488664f4763Szrj sshbuf_free(b); 1489664f4763Szrj freezero(signature, slen); 1490664f4763Szrj return sent; 149118de8d7fSPeter Avalos } 149218de8d7fSPeter Avalos 149318de8d7fSPeter Avalos static int 1494664f4763Szrj send_pubkey_test(struct ssh *ssh, Identity *id) 149518de8d7fSPeter Avalos { 1496664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 1497664f4763Szrj u_char *blob = NULL; 1498664f4763Szrj char *alg = NULL; 1499664f4763Szrj size_t bloblen; 1500664f4763Szrj u_int have_sig = 0; 1501664f4763Szrj int sent = 0, r; 150218de8d7fSPeter Avalos 1503664f4763Szrj if ((alg = key_sig_algorithm(ssh, id->key)) == NULL) { 1504*50a69bb5SSascha Wildner debug_f("no mutual signature algorithm"); 1505664f4763Szrj goto out; 1506664f4763Szrj } 150718de8d7fSPeter Avalos 1508664f4763Szrj if ((r = sshkey_to_blob(id->key, &blob, &bloblen)) != 0) { 150918de8d7fSPeter Avalos /* we cannot handle this key */ 1510*50a69bb5SSascha Wildner debug3_f("cannot handle key"); 1511664f4763Szrj goto out; 151218de8d7fSPeter Avalos } 151318de8d7fSPeter Avalos /* register callback for USERAUTH_PK_OK message */ 1514664f4763Szrj ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); 151518de8d7fSPeter Avalos 1516664f4763Szrj if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1517664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || 1518664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || 1519664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || 1520664f4763Szrj (r = sshpkt_put_u8(ssh, have_sig)) != 0 || 1521664f4763Szrj (r = sshpkt_put_cstring(ssh, alg)) != 0 || 1522664f4763Szrj (r = sshpkt_put_string(ssh, blob, bloblen)) != 0 || 1523664f4763Szrj (r = sshpkt_send(ssh)) != 0) 1524*50a69bb5SSascha Wildner fatal_fr(r, "send packet"); 1525664f4763Szrj sent = 1; 1526664f4763Szrj 1527664f4763Szrj out: 1528664f4763Szrj free(alg); 152936e94dc5SPeter Avalos free(blob); 1530664f4763Szrj return sent; 153118de8d7fSPeter Avalos } 153218de8d7fSPeter Avalos 1533ce74bacaSMatthew Dillon static struct sshkey * 1534e9778795SPeter Avalos load_identity_file(Identity *id) 153518de8d7fSPeter Avalos { 1536ce74bacaSMatthew Dillon struct sshkey *private = NULL; 1537e9778795SPeter Avalos char prompt[300], *passphrase, *comment; 15380cbfa66cSDaniel Fojt int r, quit = 0, i; 153918de8d7fSPeter Avalos struct stat st; 154018de8d7fSPeter Avalos 15410cbfa66cSDaniel Fojt if (stat(id->filename, &st) == -1) { 1542*50a69bb5SSascha Wildner do_log2(id->userprovided ? 1543*50a69bb5SSascha Wildner SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_DEBUG3, 1544*50a69bb5SSascha Wildner "no such identity: %s: %s", id->filename, strerror(errno)); 154518de8d7fSPeter Avalos return NULL; 154618de8d7fSPeter Avalos } 154718de8d7fSPeter Avalos snprintf(prompt, sizeof prompt, 1548e9778795SPeter Avalos "Enter passphrase for key '%.100s': ", id->filename); 1549e9778795SPeter Avalos for (i = 0; i <= options.number_of_password_prompts; i++) { 1550e9778795SPeter Avalos if (i == 0) 1551e9778795SPeter Avalos passphrase = ""; 1552e9778795SPeter Avalos else { 155318de8d7fSPeter Avalos passphrase = read_passphrase(prompt, 0); 1554e9778795SPeter Avalos if (*passphrase == '\0') { 155518de8d7fSPeter Avalos debug2("no passphrase given, try next key"); 1556e9778795SPeter Avalos free(passphrase); 1557e9778795SPeter Avalos break; 155818de8d7fSPeter Avalos } 1559e9778795SPeter Avalos } 1560e9778795SPeter Avalos switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename, 15610cbfa66cSDaniel Fojt passphrase, &private, &comment))) { 1562e9778795SPeter Avalos case 0: 1563e9778795SPeter Avalos break; 1564e9778795SPeter Avalos case SSH_ERR_KEY_WRONG_PASSPHRASE: 1565e9778795SPeter Avalos if (options.batch_mode) { 1566e9778795SPeter Avalos quit = 1; 1567e9778795SPeter Avalos break; 1568e9778795SPeter Avalos } 1569e9778795SPeter Avalos if (i != 0) 1570e9778795SPeter Avalos debug2("bad passphrase given, try again..."); 1571e9778795SPeter Avalos break; 1572e9778795SPeter Avalos case SSH_ERR_SYSTEM_ERROR: 1573e9778795SPeter Avalos if (errno == ENOENT) { 1574*50a69bb5SSascha Wildner debug2_r(r, "Load key \"%s\"", id->filename); 1575e9778795SPeter Avalos quit = 1; 1576e9778795SPeter Avalos break; 1577e9778795SPeter Avalos } 1578e9778795SPeter Avalos /* FALLTHROUGH */ 1579e9778795SPeter Avalos default: 1580*50a69bb5SSascha Wildner error_r(r, "Load key \"%s\"", id->filename); 1581e9778795SPeter Avalos quit = 1; 1582e9778795SPeter Avalos break; 1583e9778795SPeter Avalos } 15840cbfa66cSDaniel Fojt if (private != NULL && sshkey_is_sk(private) && 15850cbfa66cSDaniel Fojt options.sk_provider == NULL) { 15860cbfa66cSDaniel Fojt debug("key \"%s\" is an authenticator-hosted key, " 15870cbfa66cSDaniel Fojt "but no provider specified", id->filename); 15880cbfa66cSDaniel Fojt sshkey_free(private); 15890cbfa66cSDaniel Fojt private = NULL; 15900cbfa66cSDaniel Fojt quit = 1; 15910cbfa66cSDaniel Fojt } 1592e9778795SPeter Avalos if (!quit && private != NULL && id->agent_fd == -1 && 1593e9778795SPeter Avalos !(id->key && id->isprivate)) 1594e9778795SPeter Avalos maybe_add_key_to_agent(id->filename, private, comment, 1595e9778795SPeter Avalos passphrase); 1596664f4763Szrj if (i > 0) 1597664f4763Szrj freezero(passphrase, strlen(passphrase)); 1598e9778795SPeter Avalos free(comment); 159918de8d7fSPeter Avalos if (private != NULL || quit) 160018de8d7fSPeter Avalos break; 160118de8d7fSPeter Avalos } 160218de8d7fSPeter Avalos return private; 160318de8d7fSPeter Avalos } 160418de8d7fSPeter Avalos 1605664f4763Szrj static int 1606664f4763Szrj key_type_allowed_by_config(struct sshkey *key) 1607664f4763Szrj { 1608664f4763Szrj if (match_pattern_list(sshkey_ssh_name(key), 1609*50a69bb5SSascha Wildner options.pubkey_accepted_algos, 0) == 1) 1610664f4763Szrj return 1; 1611664f4763Szrj 1612664f4763Szrj /* RSA keys/certs might be allowed by alternate signature types */ 1613664f4763Szrj switch (key->type) { 1614664f4763Szrj case KEY_RSA: 1615664f4763Szrj if (match_pattern_list("rsa-sha2-512", 1616*50a69bb5SSascha Wildner options.pubkey_accepted_algos, 0) == 1) 1617664f4763Szrj return 1; 1618664f4763Szrj if (match_pattern_list("rsa-sha2-256", 1619*50a69bb5SSascha Wildner options.pubkey_accepted_algos, 0) == 1) 1620664f4763Szrj return 1; 1621664f4763Szrj break; 1622664f4763Szrj case KEY_RSA_CERT: 1623664f4763Szrj if (match_pattern_list("rsa-sha2-512-cert-v01@openssh.com", 1624*50a69bb5SSascha Wildner options.pubkey_accepted_algos, 0) == 1) 1625664f4763Szrj return 1; 1626664f4763Szrj if (match_pattern_list("rsa-sha2-256-cert-v01@openssh.com", 1627*50a69bb5SSascha Wildner options.pubkey_accepted_algos, 0) == 1) 1628664f4763Szrj return 1; 1629664f4763Szrj break; 1630664f4763Szrj } 1631664f4763Szrj return 0; 1632664f4763Szrj } 1633664f4763Szrj 1634664f4763Szrj 163518de8d7fSPeter Avalos /* 163618de8d7fSPeter Avalos * try keys in the following order: 1637e9778795SPeter Avalos * 1. certificates listed in the config file 1638e9778795SPeter Avalos * 2. other input certificates 1639e9778795SPeter Avalos * 3. agent keys that are found in the config file 1640e9778795SPeter Avalos * 4. other agent keys 1641e9778795SPeter Avalos * 5. keys that are only listed in the config file 164218de8d7fSPeter Avalos */ 164318de8d7fSPeter Avalos static void 164418de8d7fSPeter Avalos pubkey_prepare(Authctxt *authctxt) 164518de8d7fSPeter Avalos { 1646e9778795SPeter Avalos struct identity *id, *id2, *tmp; 1647e9778795SPeter Avalos struct idlist agent, files, *preferred; 1648e9778795SPeter Avalos struct sshkey *key; 1649e9778795SPeter Avalos int agent_fd = -1, i, r, found; 1650e9778795SPeter Avalos size_t j; 1651e9778795SPeter Avalos struct ssh_identitylist *idlist; 1652664f4763Szrj char *ident; 165318de8d7fSPeter Avalos 165418de8d7fSPeter Avalos TAILQ_INIT(&agent); /* keys from the agent */ 165518de8d7fSPeter Avalos TAILQ_INIT(&files); /* keys from the config file */ 165618de8d7fSPeter Avalos preferred = &authctxt->keys; 165718de8d7fSPeter Avalos TAILQ_INIT(preferred); /* preferred order of keys */ 165818de8d7fSPeter Avalos 165936e94dc5SPeter Avalos /* list of keys stored in the filesystem and PKCS#11 */ 166018de8d7fSPeter Avalos for (i = 0; i < options.num_identity_files; i++) { 166118de8d7fSPeter Avalos key = options.identity_keys[i]; 16620cbfa66cSDaniel Fojt if (key && key->cert && 16630cbfa66cSDaniel Fojt key->cert->type != SSH2_CERT_TYPE_USER) { 1664*50a69bb5SSascha Wildner debug_f("ignoring certificate %s: not a user " 1665*50a69bb5SSascha Wildner "certificate", options.identity_files[i]); 1666856ea928SPeter Avalos continue; 16670cbfa66cSDaniel Fojt } 16680cbfa66cSDaniel Fojt if (key && sshkey_is_sk(key) && options.sk_provider == NULL) { 1669*50a69bb5SSascha Wildner debug_f("ignoring authenticator-hosted key %s as no " 16700cbfa66cSDaniel Fojt "SecurityKeyProvider has been specified", 1671*50a69bb5SSascha Wildner options.identity_files[i]); 16720cbfa66cSDaniel Fojt continue; 16730cbfa66cSDaniel Fojt } 167418de8d7fSPeter Avalos options.identity_keys[i] = NULL; 167518de8d7fSPeter Avalos id = xcalloc(1, sizeof(*id)); 1676e9778795SPeter Avalos id->agent_fd = -1; 167718de8d7fSPeter Avalos id->key = key; 167818de8d7fSPeter Avalos id->filename = xstrdup(options.identity_files[i]); 167936e94dc5SPeter Avalos id->userprovided = options.identity_file_userprovided[i]; 168018de8d7fSPeter Avalos TAILQ_INSERT_TAIL(&files, id, next); 168118de8d7fSPeter Avalos } 1682e9778795SPeter Avalos /* list of certificates specified by user */ 1683e9778795SPeter Avalos for (i = 0; i < options.num_certificate_files; i++) { 1684e9778795SPeter Avalos key = options.certificates[i]; 1685664f4763Szrj if (!sshkey_is_cert(key) || key->cert == NULL || 16860cbfa66cSDaniel Fojt key->cert->type != SSH2_CERT_TYPE_USER) { 1687*50a69bb5SSascha Wildner debug_f("ignoring certificate %s: not a user " 1688*50a69bb5SSascha Wildner "certificate", options.identity_files[i]); 1689e9778795SPeter Avalos continue; 16900cbfa66cSDaniel Fojt } 16910cbfa66cSDaniel Fojt if (key && sshkey_is_sk(key) && options.sk_provider == NULL) { 1692*50a69bb5SSascha Wildner debug_f("ignoring authenticator-hosted key " 16930cbfa66cSDaniel Fojt "certificate %s as no " 16940cbfa66cSDaniel Fojt "SecurityKeyProvider has been specified", 1695*50a69bb5SSascha Wildner options.identity_files[i]); 16960cbfa66cSDaniel Fojt continue; 16970cbfa66cSDaniel Fojt } 1698e9778795SPeter Avalos id = xcalloc(1, sizeof(*id)); 1699e9778795SPeter Avalos id->agent_fd = -1; 1700e9778795SPeter Avalos id->key = key; 1701e9778795SPeter Avalos id->filename = xstrdup(options.certificate_files[i]); 1702e9778795SPeter Avalos id->userprovided = options.certificate_file_userprovided[i]; 1703e9778795SPeter Avalos TAILQ_INSERT_TAIL(preferred, id, next); 1704e9778795SPeter Avalos } 1705e9778795SPeter Avalos /* list of keys supported by the agent */ 1706e9778795SPeter Avalos if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { 1707e9778795SPeter Avalos if (r != SSH_ERR_AGENT_NOT_PRESENT) 1708*50a69bb5SSascha Wildner debug_fr(r, "ssh_get_authentication_socket"); 1709ce74bacaSMatthew Dillon } else if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { 1710e9778795SPeter Avalos if (r != SSH_ERR_AGENT_NO_IDENTITIES) 1711*50a69bb5SSascha Wildner debug_fr(r, "ssh_fetch_identitylist"); 1712e9778795SPeter Avalos close(agent_fd); 1713e9778795SPeter Avalos } else { 1714e9778795SPeter Avalos for (j = 0; j < idlist->nkeys; j++) { 1715e9778795SPeter Avalos found = 0; 1716e9778795SPeter Avalos TAILQ_FOREACH(id, &files, next) { 1717e9778795SPeter Avalos /* 1718e9778795SPeter Avalos * agent keys from the config file are 1719e9778795SPeter Avalos * preferred 1720e9778795SPeter Avalos */ 1721e9778795SPeter Avalos if (sshkey_equal(idlist->keys[j], id->key)) { 1722e9778795SPeter Avalos TAILQ_REMOVE(&files, id, next); 1723e9778795SPeter Avalos TAILQ_INSERT_TAIL(preferred, id, next); 1724e9778795SPeter Avalos id->agent_fd = agent_fd; 1725e9778795SPeter Avalos found = 1; 1726e9778795SPeter Avalos break; 1727e9778795SPeter Avalos } 1728e9778795SPeter Avalos } 1729e9778795SPeter Avalos if (!found && !options.identities_only) { 1730e9778795SPeter Avalos id = xcalloc(1, sizeof(*id)); 1731e9778795SPeter Avalos /* XXX "steals" key/comment from idlist */ 1732e9778795SPeter Avalos id->key = idlist->keys[j]; 1733e9778795SPeter Avalos id->filename = idlist->comments[j]; 1734e9778795SPeter Avalos idlist->keys[j] = NULL; 1735e9778795SPeter Avalos idlist->comments[j] = NULL; 1736e9778795SPeter Avalos id->agent_fd = agent_fd; 1737e9778795SPeter Avalos TAILQ_INSERT_TAIL(&agent, id, next); 1738e9778795SPeter Avalos } 1739e9778795SPeter Avalos } 1740e9778795SPeter Avalos ssh_free_identitylist(idlist); 1741e9778795SPeter Avalos /* append remaining agent keys */ 1742*50a69bb5SSascha Wildner TAILQ_CONCAT(preferred, &agent, next); 1743e9778795SPeter Avalos authctxt->agent_fd = agent_fd; 1744e9778795SPeter Avalos } 174536e94dc5SPeter Avalos /* Prefer PKCS11 keys that are explicitly listed */ 174636e94dc5SPeter Avalos TAILQ_FOREACH_SAFE(id, &files, next, tmp) { 174736e94dc5SPeter Avalos if (id->key == NULL || (id->key->flags & SSHKEY_FLAG_EXT) == 0) 174836e94dc5SPeter Avalos continue; 174936e94dc5SPeter Avalos found = 0; 175036e94dc5SPeter Avalos TAILQ_FOREACH(id2, &files, next) { 175136e94dc5SPeter Avalos if (id2->key == NULL || 17520cbfa66cSDaniel Fojt (id2->key->flags & SSHKEY_FLAG_EXT) != 0) 175336e94dc5SPeter Avalos continue; 1754e9778795SPeter Avalos if (sshkey_equal(id->key, id2->key)) { 175536e94dc5SPeter Avalos TAILQ_REMOVE(&files, id, next); 175636e94dc5SPeter Avalos TAILQ_INSERT_TAIL(preferred, id, next); 175736e94dc5SPeter Avalos found = 1; 175836e94dc5SPeter Avalos break; 175936e94dc5SPeter Avalos } 176036e94dc5SPeter Avalos } 176136e94dc5SPeter Avalos /* If IdentitiesOnly set and key not found then don't use it */ 176236e94dc5SPeter Avalos if (!found && options.identities_only) { 176336e94dc5SPeter Avalos TAILQ_REMOVE(&files, id, next); 1764664f4763Szrj freezero(id, sizeof(*id)); 176536e94dc5SPeter Avalos } 176636e94dc5SPeter Avalos } 176718de8d7fSPeter Avalos /* append remaining keys from the config file */ 1768*50a69bb5SSascha Wildner TAILQ_CONCAT(preferred, &files, next); 1769*50a69bb5SSascha Wildner /* finally, filter by PubkeyAcceptedAlgorithms */ 1770e9778795SPeter Avalos TAILQ_FOREACH_SAFE(id, preferred, next, id2) { 1771664f4763Szrj if (id->key != NULL && !key_type_allowed_by_config(id->key)) { 1772e9778795SPeter Avalos debug("Skipping %s key %s - " 1773*50a69bb5SSascha Wildner "corresponding algo not in PubkeyAcceptedAlgorithms", 1774e9778795SPeter Avalos sshkey_ssh_name(id->key), id->filename); 1775e9778795SPeter Avalos TAILQ_REMOVE(preferred, id, next); 1776e9778795SPeter Avalos sshkey_free(id->key); 1777e9778795SPeter Avalos free(id->filename); 1778e9778795SPeter Avalos memset(id, 0, sizeof(*id)); 1779e9778795SPeter Avalos continue; 1780e9778795SPeter Avalos } 178118de8d7fSPeter Avalos } 1782664f4763Szrj /* List the keys we plan on using */ 1783664f4763Szrj TAILQ_FOREACH_SAFE(id, preferred, next, id2) { 1784664f4763Szrj ident = format_identity(id); 1785664f4763Szrj debug("Will attempt key: %s", ident); 1786664f4763Szrj free(ident); 1787664f4763Szrj } 1788*50a69bb5SSascha Wildner debug2_f("done"); 178918de8d7fSPeter Avalos } 179018de8d7fSPeter Avalos 179118de8d7fSPeter Avalos static void 1792664f4763Szrj pubkey_cleanup(struct ssh *ssh) 179318de8d7fSPeter Avalos { 1794664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 179518de8d7fSPeter Avalos Identity *id; 179618de8d7fSPeter Avalos 1797664f4763Szrj if (authctxt->agent_fd != -1) { 1798e9778795SPeter Avalos ssh_close_authentication_socket(authctxt->agent_fd); 1799664f4763Szrj authctxt->agent_fd = -1; 1800664f4763Szrj } 180118de8d7fSPeter Avalos for (id = TAILQ_FIRST(&authctxt->keys); id; 180218de8d7fSPeter Avalos id = TAILQ_FIRST(&authctxt->keys)) { 180318de8d7fSPeter Avalos TAILQ_REMOVE(&authctxt->keys, id, next); 1804e9778795SPeter Avalos sshkey_free(id->key); 180536e94dc5SPeter Avalos free(id->filename); 180636e94dc5SPeter Avalos free(id); 180718de8d7fSPeter Avalos } 180818de8d7fSPeter Avalos } 180918de8d7fSPeter Avalos 1810ce74bacaSMatthew Dillon static void 1811ce74bacaSMatthew Dillon pubkey_reset(Authctxt *authctxt) 1812ce74bacaSMatthew Dillon { 1813ce74bacaSMatthew Dillon Identity *id; 1814ce74bacaSMatthew Dillon 1815ce74bacaSMatthew Dillon TAILQ_FOREACH(id, &authctxt->keys, next) 1816ce74bacaSMatthew Dillon id->tried = 0; 1817ce74bacaSMatthew Dillon } 1818ce74bacaSMatthew Dillon 1819e9778795SPeter Avalos static int 1820*50a69bb5SSascha Wildner try_identity(struct ssh *ssh, Identity *id) 1821e9778795SPeter Avalos { 1822e9778795SPeter Avalos if (!id->key) 1823e9778795SPeter Avalos return (0); 1824664f4763Szrj if (sshkey_type_plain(id->key->type) == KEY_RSA && 1825*50a69bb5SSascha Wildner (ssh->compat & SSH_BUG_RSASIGMD5) != 0) { 1826e9778795SPeter Avalos debug("Skipped %s key %s for RSA/MD5 server", 1827664f4763Szrj sshkey_type(id->key), id->filename); 1828e9778795SPeter Avalos return (0); 1829e9778795SPeter Avalos } 1830ce74bacaSMatthew Dillon return 1; 1831e9778795SPeter Avalos } 1832e9778795SPeter Avalos 1833664f4763Szrj static int 1834664f4763Szrj userauth_pubkey(struct ssh *ssh) 183518de8d7fSPeter Avalos { 1836664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 183718de8d7fSPeter Avalos Identity *id; 183818de8d7fSPeter Avalos int sent = 0; 1839664f4763Szrj char *ident; 184018de8d7fSPeter Avalos 184118de8d7fSPeter Avalos while ((id = TAILQ_FIRST(&authctxt->keys))) { 184218de8d7fSPeter Avalos if (id->tried++) 184318de8d7fSPeter Avalos return (0); 184418de8d7fSPeter Avalos /* move key to the end of the queue */ 184518de8d7fSPeter Avalos TAILQ_REMOVE(&authctxt->keys, id, next); 184618de8d7fSPeter Avalos TAILQ_INSERT_TAIL(&authctxt->keys, id, next); 184718de8d7fSPeter Avalos /* 184818de8d7fSPeter Avalos * send a test message if we have the public key. for 184918de8d7fSPeter Avalos * encrypted keys we cannot do this and have to load the 185018de8d7fSPeter Avalos * private key instead 185118de8d7fSPeter Avalos */ 185236e94dc5SPeter Avalos if (id->key != NULL) { 1853*50a69bb5SSascha Wildner if (try_identity(ssh, id)) { 1854664f4763Szrj ident = format_identity(id); 1855664f4763Szrj debug("Offering public key: %s", ident); 1856664f4763Szrj free(ident); 1857664f4763Szrj sent = send_pubkey_test(ssh, id); 185836e94dc5SPeter Avalos } 185936e94dc5SPeter Avalos } else { 186018de8d7fSPeter Avalos debug("Trying private key: %s", id->filename); 1861e9778795SPeter Avalos id->key = load_identity_file(id); 186218de8d7fSPeter Avalos if (id->key != NULL) { 1863*50a69bb5SSascha Wildner if (try_identity(ssh, id)) { 186418de8d7fSPeter Avalos id->isprivate = 1; 1865664f4763Szrj sent = sign_and_send_pubkey(ssh, id); 186636e94dc5SPeter Avalos } 1867664f4763Szrj sshkey_free(id->key); 186818de8d7fSPeter Avalos id->key = NULL; 1869ce74bacaSMatthew Dillon id->isprivate = 0; 187018de8d7fSPeter Avalos } 187118de8d7fSPeter Avalos } 187218de8d7fSPeter Avalos if (sent) 187318de8d7fSPeter Avalos return (sent); 187418de8d7fSPeter Avalos } 187518de8d7fSPeter Avalos return (0); 187618de8d7fSPeter Avalos } 187718de8d7fSPeter Avalos 187818de8d7fSPeter Avalos /* 187918de8d7fSPeter Avalos * Send userauth request message specifying keyboard-interactive method. 188018de8d7fSPeter Avalos */ 1881664f4763Szrj static int 1882664f4763Szrj userauth_kbdint(struct ssh *ssh) 188318de8d7fSPeter Avalos { 1884664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 1885664f4763Szrj int r; 188618de8d7fSPeter Avalos 1887664f4763Szrj if (authctxt->attempt_kbdint++ >= options.number_of_password_prompts) 188818de8d7fSPeter Avalos return 0; 188918de8d7fSPeter Avalos /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */ 1890664f4763Szrj if (authctxt->attempt_kbdint > 1 && !authctxt->info_req_seen) { 189118de8d7fSPeter Avalos debug3("userauth_kbdint: disable: no info_req_seen"); 1892664f4763Szrj ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_REQUEST, NULL); 189318de8d7fSPeter Avalos return 0; 189418de8d7fSPeter Avalos } 189518de8d7fSPeter Avalos 189618de8d7fSPeter Avalos debug2("userauth_kbdint"); 1897664f4763Szrj if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1898664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || 1899664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || 1900664f4763Szrj (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || 1901664f4763Szrj (r = sshpkt_put_cstring(ssh, "")) != 0 || /* lang */ 1902664f4763Szrj (r = sshpkt_put_cstring(ssh, options.kbd_interactive_devices ? 1903664f4763Szrj options.kbd_interactive_devices : "")) != 0 || 1904664f4763Szrj (r = sshpkt_send(ssh)) != 0) 1905*50a69bb5SSascha Wildner fatal_fr(r, "send packet"); 190618de8d7fSPeter Avalos 1907664f4763Szrj ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); 190818de8d7fSPeter Avalos return 1; 190918de8d7fSPeter Avalos } 191018de8d7fSPeter Avalos 191118de8d7fSPeter Avalos /* 191218de8d7fSPeter Avalos * parse INFO_REQUEST, prompt user and send INFO_RESPONSE 191318de8d7fSPeter Avalos */ 1914664f4763Szrj static int 1915ce74bacaSMatthew Dillon input_userauth_info_req(int type, u_int32_t seq, struct ssh *ssh) 191618de8d7fSPeter Avalos { 1917ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 1918664f4763Szrj char *name = NULL, *inst = NULL, *lang = NULL, *prompt = NULL; 1919*50a69bb5SSascha Wildner char *display_prompt = NULL, *response = NULL; 1920664f4763Szrj u_char echo = 0; 192118de8d7fSPeter Avalos u_int num_prompts, i; 1922664f4763Szrj int r; 192318de8d7fSPeter Avalos 1924*50a69bb5SSascha Wildner debug2_f("entering"); 192518de8d7fSPeter Avalos 192618de8d7fSPeter Avalos if (authctxt == NULL) 1927*50a69bb5SSascha Wildner fatal_f("no authentication context"); 192818de8d7fSPeter Avalos 192918de8d7fSPeter Avalos authctxt->info_req_seen = 1; 193018de8d7fSPeter Avalos 1931664f4763Szrj if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0 || 1932664f4763Szrj (r = sshpkt_get_cstring(ssh, &inst, NULL)) != 0 || 1933664f4763Szrj (r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0) 1934664f4763Szrj goto out; 193518de8d7fSPeter Avalos if (strlen(name) > 0) 193618de8d7fSPeter Avalos logit("%s", name); 193718de8d7fSPeter Avalos if (strlen(inst) > 0) 193818de8d7fSPeter Avalos logit("%s", inst); 193918de8d7fSPeter Avalos 1940664f4763Szrj if ((r = sshpkt_get_u32(ssh, &num_prompts)) != 0) 1941664f4763Szrj goto out; 194218de8d7fSPeter Avalos /* 194318de8d7fSPeter Avalos * Begin to build info response packet based on prompts requested. 194418de8d7fSPeter Avalos * We commit to providing the correct number of responses, so if 194518de8d7fSPeter Avalos * further on we run into a problem that prevents this, we have to 194618de8d7fSPeter Avalos * be sure and clean this up and send a correct error response. 194718de8d7fSPeter Avalos */ 1948664f4763Szrj if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE)) != 0 || 1949664f4763Szrj (r = sshpkt_put_u32(ssh, num_prompts)) != 0) 1950664f4763Szrj goto out; 195118de8d7fSPeter Avalos 1952*50a69bb5SSascha Wildner debug2_f("num_prompts %d", num_prompts); 195318de8d7fSPeter Avalos for (i = 0; i < num_prompts; i++) { 1954664f4763Szrj if ((r = sshpkt_get_cstring(ssh, &prompt, NULL)) != 0 || 1955664f4763Szrj (r = sshpkt_get_u8(ssh, &echo)) != 0) 1956664f4763Szrj goto out; 1957*50a69bb5SSascha Wildner if (asmprintf(&display_prompt, INT_MAX, NULL, "(%s@%s) %s", 1958*50a69bb5SSascha Wildner authctxt->server_user, options.host_key_alias ? 1959*50a69bb5SSascha Wildner options.host_key_alias : authctxt->host, prompt) == -1) 1960*50a69bb5SSascha Wildner fatal_f("asmprintf failed"); 1961*50a69bb5SSascha Wildner response = read_passphrase(display_prompt, echo ? RP_ECHO : 0); 1962664f4763Szrj if ((r = sshpkt_put_cstring(ssh, response)) != 0) 1963664f4763Szrj goto out; 1964664f4763Szrj freezero(response, strlen(response)); 196536e94dc5SPeter Avalos free(prompt); 1966*50a69bb5SSascha Wildner free(display_prompt); 1967*50a69bb5SSascha Wildner display_prompt = response = prompt = NULL; 196818de8d7fSPeter Avalos } 1969664f4763Szrj /* done with parsing incoming message. */ 1970664f4763Szrj if ((r = sshpkt_get_end(ssh)) != 0 || 1971664f4763Szrj (r = sshpkt_add_padding(ssh, 64)) != 0) 1972664f4763Szrj goto out; 1973664f4763Szrj r = sshpkt_send(ssh); 1974664f4763Szrj out: 1975664f4763Szrj if (response) 1976664f4763Szrj freezero(response, strlen(response)); 1977664f4763Szrj free(prompt); 1978*50a69bb5SSascha Wildner free(display_prompt); 1979664f4763Szrj free(name); 1980664f4763Szrj free(inst); 1981664f4763Szrj free(lang); 1982664f4763Szrj return r; 198318de8d7fSPeter Avalos } 198418de8d7fSPeter Avalos 198518de8d7fSPeter Avalos static int 1986664f4763Szrj ssh_keysign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp, 1987e9778795SPeter Avalos const u_char *data, size_t datalen) 198818de8d7fSPeter Avalos { 1989e9778795SPeter Avalos struct sshbuf *b; 199018de8d7fSPeter Avalos struct stat st; 199118de8d7fSPeter Avalos pid_t pid; 19920cbfa66cSDaniel Fojt int r, to[2], from[2], status; 1993664f4763Szrj int sock = ssh_packet_get_connection_in(ssh); 1994e9778795SPeter Avalos u_char rversion = 0, version = 2; 1995e9778795SPeter Avalos void (*osigchld)(int); 199618de8d7fSPeter Avalos 1997e9778795SPeter Avalos *sigp = NULL; 1998e9778795SPeter Avalos *lenp = 0; 199918de8d7fSPeter Avalos 20000cbfa66cSDaniel Fojt if (stat(_PATH_SSH_KEY_SIGN, &st) == -1) { 2001*50a69bb5SSascha Wildner error_f("not installed: %s", strerror(errno)); 200218de8d7fSPeter Avalos return -1; 200318de8d7fSPeter Avalos } 2004e9778795SPeter Avalos if (fflush(stdout) != 0) { 2005*50a69bb5SSascha Wildner error_f("fflush: %s", strerror(errno)); 2006e9778795SPeter Avalos return -1; 2007e9778795SPeter Avalos } 20080cbfa66cSDaniel Fojt if (pipe(to) == -1) { 2009*50a69bb5SSascha Wildner error_f("pipe: %s", strerror(errno)); 201018de8d7fSPeter Avalos return -1; 201118de8d7fSPeter Avalos } 20120cbfa66cSDaniel Fojt if (pipe(from) == -1) { 2013*50a69bb5SSascha Wildner error_f("pipe: %s", strerror(errno)); 201418de8d7fSPeter Avalos return -1; 201518de8d7fSPeter Avalos } 20160cbfa66cSDaniel Fojt if ((pid = fork()) == -1) { 2017*50a69bb5SSascha Wildner error_f("fork: %s", strerror(errno)); 201818de8d7fSPeter Avalos return -1; 201918de8d7fSPeter Avalos } 20200cbfa66cSDaniel Fojt osigchld = ssh_signal(SIGCHLD, SIG_DFL); 202118de8d7fSPeter Avalos if (pid == 0) { 202218de8d7fSPeter Avalos close(from[0]); 20230cbfa66cSDaniel Fojt if (dup2(from[1], STDOUT_FILENO) == -1) 2024*50a69bb5SSascha Wildner fatal_f("dup2: %s", strerror(errno)); 202518de8d7fSPeter Avalos close(to[1]); 20260cbfa66cSDaniel Fojt if (dup2(to[0], STDIN_FILENO) == -1) 2027*50a69bb5SSascha Wildner fatal_f("dup2: %s", strerror(errno)); 202818de8d7fSPeter Avalos close(from[1]); 202918de8d7fSPeter Avalos close(to[0]); 20300cbfa66cSDaniel Fojt 20310cbfa66cSDaniel Fojt if (dup2(sock, STDERR_FILENO + 1) == -1) 2032*50a69bb5SSascha Wildner fatal_f("dup2: %s", strerror(errno)); 20330cbfa66cSDaniel Fojt sock = STDERR_FILENO + 1; 20340cbfa66cSDaniel Fojt fcntl(sock, F_SETFD, 0); /* keep the socket on exec */ 2035e9778795SPeter Avalos closefrom(sock + 1); 20360cbfa66cSDaniel Fojt 2037*50a69bb5SSascha Wildner debug3_f("[child] pid=%ld, exec %s", 2038*50a69bb5SSascha Wildner (long)getpid(), _PATH_SSH_KEY_SIGN); 2039e9778795SPeter Avalos execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *)NULL); 2040*50a69bb5SSascha Wildner fatal_f("exec(%s): %s", _PATH_SSH_KEY_SIGN, 204118de8d7fSPeter Avalos strerror(errno)); 204218de8d7fSPeter Avalos } 204318de8d7fSPeter Avalos close(from[1]); 204418de8d7fSPeter Avalos close(to[0]); 20450cbfa66cSDaniel Fojt sock = STDERR_FILENO + 1; 204618de8d7fSPeter Avalos 2047e9778795SPeter Avalos if ((b = sshbuf_new()) == NULL) 2048*50a69bb5SSascha Wildner fatal_f("sshbuf_new failed"); 2049e9778795SPeter Avalos /* send # of sock, data to be signed */ 2050ce74bacaSMatthew Dillon if ((r = sshbuf_put_u32(b, sock)) != 0 || 2051e9778795SPeter Avalos (r = sshbuf_put_string(b, data, datalen)) != 0) 2052*50a69bb5SSascha Wildner fatal_fr(r, "buffer error"); 2053e9778795SPeter Avalos if (ssh_msg_send(to[1], version, b) == -1) 2054*50a69bb5SSascha Wildner fatal_f("couldn't send request"); 2055e9778795SPeter Avalos sshbuf_reset(b); 2056e9778795SPeter Avalos r = ssh_msg_recv(from[0], b); 205718de8d7fSPeter Avalos close(from[0]); 205818de8d7fSPeter Avalos close(to[1]); 2059e9778795SPeter Avalos if (r < 0) { 2060*50a69bb5SSascha Wildner error_f("no reply"); 2061e9778795SPeter Avalos goto fail; 2062e9778795SPeter Avalos } 206318de8d7fSPeter Avalos 2064e9778795SPeter Avalos errno = 0; 20650cbfa66cSDaniel Fojt while (waitpid(pid, &status, 0) == -1) { 2066e9778795SPeter Avalos if (errno != EINTR) { 2067*50a69bb5SSascha Wildner error_f("waitpid %ld: %s", (long)pid, strerror(errno)); 2068e9778795SPeter Avalos goto fail; 2069e9778795SPeter Avalos } 2070e9778795SPeter Avalos } 2071e9778795SPeter Avalos if (!WIFEXITED(status)) { 2072*50a69bb5SSascha Wildner error_f("exited abnormally"); 2073e9778795SPeter Avalos goto fail; 2074e9778795SPeter Avalos } 2075e9778795SPeter Avalos if (WEXITSTATUS(status) != 0) { 2076*50a69bb5SSascha Wildner error_f("exited with status %d", WEXITSTATUS(status)); 2077e9778795SPeter Avalos goto fail; 2078e9778795SPeter Avalos } 2079e9778795SPeter Avalos if ((r = sshbuf_get_u8(b, &rversion)) != 0) { 2080*50a69bb5SSascha Wildner error_fr(r, "buffer error"); 2081e9778795SPeter Avalos goto fail; 2082e9778795SPeter Avalos } 2083e9778795SPeter Avalos if (rversion != version) { 2084*50a69bb5SSascha Wildner error_f("bad version"); 2085e9778795SPeter Avalos goto fail; 2086e9778795SPeter Avalos } 2087e9778795SPeter Avalos if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) { 2088*50a69bb5SSascha Wildner error_fr(r, "buffer error"); 2089e9778795SPeter Avalos fail: 20900cbfa66cSDaniel Fojt ssh_signal(SIGCHLD, osigchld); 2091e9778795SPeter Avalos sshbuf_free(b); 209218de8d7fSPeter Avalos return -1; 209318de8d7fSPeter Avalos } 20940cbfa66cSDaniel Fojt ssh_signal(SIGCHLD, osigchld); 2095e9778795SPeter Avalos sshbuf_free(b); 209618de8d7fSPeter Avalos 209718de8d7fSPeter Avalos return 0; 209818de8d7fSPeter Avalos } 209918de8d7fSPeter Avalos 2100664f4763Szrj static int 2101664f4763Szrj userauth_hostbased(struct ssh *ssh) 210218de8d7fSPeter Avalos { 2103664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 2104e9778795SPeter Avalos struct sshkey *private = NULL; 2105e9778795SPeter Avalos struct sshbuf *b = NULL; 2106e9778795SPeter Avalos u_char *sig = NULL, *keyblob = NULL; 2107e9778795SPeter Avalos char *fp = NULL, *chost = NULL, *lname = NULL; 2108e9778795SPeter Avalos size_t siglen = 0, keylen = 0; 2109e9778795SPeter Avalos int i, r, success = 0; 2110e9778795SPeter Avalos 2111e9778795SPeter Avalos if (authctxt->ktypes == NULL) { 2112*50a69bb5SSascha Wildner authctxt->oktypes = xstrdup(options.hostbased_accepted_algos); 2113e9778795SPeter Avalos authctxt->ktypes = authctxt->oktypes; 2114e9778795SPeter Avalos } 2115e9778795SPeter Avalos 2116e9778795SPeter Avalos /* 2117*50a69bb5SSascha Wildner * Work through each listed type pattern in HostbasedAcceptedAlgorithms, 2118e9778795SPeter Avalos * trying each hostkey that matches the type in turn. 2119e9778795SPeter Avalos */ 2120e9778795SPeter Avalos for (;;) { 2121e9778795SPeter Avalos if (authctxt->active_ktype == NULL) 2122e9778795SPeter Avalos authctxt->active_ktype = strsep(&authctxt->ktypes, ","); 2123e9778795SPeter Avalos if (authctxt->active_ktype == NULL || 2124e9778795SPeter Avalos *authctxt->active_ktype == '\0') 2125e9778795SPeter Avalos break; 2126*50a69bb5SSascha Wildner debug3_f("trying key type %s", authctxt->active_ktype); 212718de8d7fSPeter Avalos 212818de8d7fSPeter Avalos /* check for a useful key */ 2129e9778795SPeter Avalos private = NULL; 2130e9778795SPeter Avalos for (i = 0; i < authctxt->sensitive->nkeys; i++) { 2131e9778795SPeter Avalos if (authctxt->sensitive->keys[i] == NULL || 2132e9778795SPeter Avalos authctxt->sensitive->keys[i]->type == KEY_UNSPEC) 2133e9778795SPeter Avalos continue; 2134e9778795SPeter Avalos if (match_pattern_list( 2135e9778795SPeter Avalos sshkey_ssh_name(authctxt->sensitive->keys[i]), 2136e9778795SPeter Avalos authctxt->active_ktype, 0) != 1) 2137e9778795SPeter Avalos continue; 213818de8d7fSPeter Avalos /* we take and free the key */ 2139e9778795SPeter Avalos private = authctxt->sensitive->keys[i]; 2140e9778795SPeter Avalos authctxt->sensitive->keys[i] = NULL; 214118de8d7fSPeter Avalos break; 214218de8d7fSPeter Avalos } 2143e9778795SPeter Avalos /* Found one */ 2144e9778795SPeter Avalos if (private != NULL) 2145e9778795SPeter Avalos break; 2146e9778795SPeter Avalos /* No more keys of this type; advance */ 2147e9778795SPeter Avalos authctxt->active_ktype = NULL; 214818de8d7fSPeter Avalos } 2149e9778795SPeter Avalos if (private == NULL) { 2150e9778795SPeter Avalos free(authctxt->oktypes); 2151e9778795SPeter Avalos authctxt->oktypes = authctxt->ktypes = NULL; 2152e9778795SPeter Avalos authctxt->active_ktype = NULL; 215318de8d7fSPeter Avalos debug("No more client hostkeys for hostbased authentication."); 2154e9778795SPeter Avalos goto out; 215518de8d7fSPeter Avalos } 2156e9778795SPeter Avalos 2157e9778795SPeter Avalos if ((fp = sshkey_fingerprint(private, options.fingerprint_hash, 2158e9778795SPeter Avalos SSH_FP_DEFAULT)) == NULL) { 2159*50a69bb5SSascha Wildner error_f("sshkey_fingerprint failed"); 2160e9778795SPeter Avalos goto out; 216118de8d7fSPeter Avalos } 2162*50a69bb5SSascha Wildner debug_f("trying hostkey %s %s", sshkey_ssh_name(private), fp); 2163e9778795SPeter Avalos 216418de8d7fSPeter Avalos /* figure out a name for the client host */ 2165664f4763Szrj lname = get_local_name(ssh_packet_get_connection_in(ssh)); 2166664f4763Szrj if (lname == NULL) { 2167*50a69bb5SSascha Wildner error_f("cannot get local ipaddr/name"); 2168e9778795SPeter Avalos goto out; 216918de8d7fSPeter Avalos } 2170e9778795SPeter Avalos 2171e9778795SPeter Avalos /* XXX sshbuf_put_stringf? */ 2172e9778795SPeter Avalos xasprintf(&chost, "%s.", lname); 2173*50a69bb5SSascha Wildner debug2_f("chost %s", chost); 217418de8d7fSPeter Avalos 2175e9778795SPeter Avalos /* construct data */ 2176e9778795SPeter Avalos if ((b = sshbuf_new()) == NULL) { 2177*50a69bb5SSascha Wildner error_f("sshbuf_new failed"); 2178e9778795SPeter Avalos goto out; 2179e9778795SPeter Avalos } 2180e9778795SPeter Avalos if ((r = sshkey_to_blob(private, &keyblob, &keylen)) != 0) { 2181*50a69bb5SSascha Wildner error_fr(r, "sshkey_to_blob"); 2182e9778795SPeter Avalos goto out; 2183e9778795SPeter Avalos } 2184*50a69bb5SSascha Wildner if ((r = sshbuf_put_stringb(b, ssh->kex->session_id)) != 0 || 2185e9778795SPeter Avalos (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 2186e9778795SPeter Avalos (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || 2187664f4763Szrj (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || 2188e9778795SPeter Avalos (r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 || 2189*50a69bb5SSascha Wildner (r = sshbuf_put_cstring(b, authctxt->active_ktype)) != 0 || 2190e9778795SPeter Avalos (r = sshbuf_put_string(b, keyblob, keylen)) != 0 || 2191e9778795SPeter Avalos (r = sshbuf_put_cstring(b, chost)) != 0 || 2192e9778795SPeter Avalos (r = sshbuf_put_cstring(b, authctxt->local_user)) != 0) { 2193*50a69bb5SSascha Wildner error_fr(r, "buffer error"); 2194e9778795SPeter Avalos goto out; 2195e9778795SPeter Avalos } 2196e9778795SPeter Avalos 2197e9778795SPeter Avalos #ifdef DEBUG_PK 2198e9778795SPeter Avalos sshbuf_dump(b, stderr); 2199e9778795SPeter Avalos #endif 2200664f4763Szrj if ((r = ssh_keysign(ssh, private, &sig, &siglen, 2201664f4763Szrj sshbuf_ptr(b), sshbuf_len(b))) != 0) { 2202e9778795SPeter Avalos error("sign using hostkey %s %s failed", 2203e9778795SPeter Avalos sshkey_ssh_name(private), fp); 2204e9778795SPeter Avalos goto out; 2205e9778795SPeter Avalos } 2206e9778795SPeter Avalos if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 2207e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || 2208e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || 2209e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || 2210*50a69bb5SSascha Wildner (r = sshpkt_put_cstring(ssh, authctxt->active_ktype)) != 0 || 2211e9778795SPeter Avalos (r = sshpkt_put_string(ssh, keyblob, keylen)) != 0 || 2212e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, chost)) != 0 || 2213e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, authctxt->local_user)) != 0 || 2214e9778795SPeter Avalos (r = sshpkt_put_string(ssh, sig, siglen)) != 0 || 2215e9778795SPeter Avalos (r = sshpkt_send(ssh)) != 0) { 2216*50a69bb5SSascha Wildner error_fr(r, "packet error"); 2217e9778795SPeter Avalos goto out; 2218e9778795SPeter Avalos } 2219e9778795SPeter Avalos success = 1; 2220e9778795SPeter Avalos 2221e9778795SPeter Avalos out: 2222664f4763Szrj if (sig != NULL) 2223664f4763Szrj freezero(sig, siglen); 2224e9778795SPeter Avalos free(keyblob); 2225e9778795SPeter Avalos free(lname); 2226e9778795SPeter Avalos free(fp); 2227e9778795SPeter Avalos free(chost); 2228e9778795SPeter Avalos sshkey_free(private); 2229e9778795SPeter Avalos sshbuf_free(b); 2230e9778795SPeter Avalos 2231e9778795SPeter Avalos return success; 223218de8d7fSPeter Avalos } 223318de8d7fSPeter Avalos 223418de8d7fSPeter Avalos /* find auth method */ 223518de8d7fSPeter Avalos 223618de8d7fSPeter Avalos /* 223718de8d7fSPeter Avalos * given auth method name, if configurable options permit this method fill 223818de8d7fSPeter Avalos * in auth_ident field and return true, otherwise return false. 223918de8d7fSPeter Avalos */ 224018de8d7fSPeter Avalos static int 224118de8d7fSPeter Avalos authmethod_is_enabled(Authmethod *method) 224218de8d7fSPeter Avalos { 224318de8d7fSPeter Avalos if (method == NULL) 224418de8d7fSPeter Avalos return 0; 224518de8d7fSPeter Avalos /* return false if options indicate this method is disabled */ 224618de8d7fSPeter Avalos if (method->enabled == NULL || *method->enabled == 0) 224718de8d7fSPeter Avalos return 0; 224818de8d7fSPeter Avalos /* return false if batch mode is enabled but method needs interactive mode */ 224918de8d7fSPeter Avalos if (method->batch_flag != NULL && *method->batch_flag != 0) 225018de8d7fSPeter Avalos return 0; 225118de8d7fSPeter Avalos return 1; 225218de8d7fSPeter Avalos } 225318de8d7fSPeter Avalos 225418de8d7fSPeter Avalos static Authmethod * 225518de8d7fSPeter Avalos authmethod_lookup(const char *name) 225618de8d7fSPeter Avalos { 225718de8d7fSPeter Avalos Authmethod *method = NULL; 225818de8d7fSPeter Avalos if (name != NULL) 225918de8d7fSPeter Avalos for (method = authmethods; method->name != NULL; method++) 226018de8d7fSPeter Avalos if (strcmp(name, method->name) == 0) 226118de8d7fSPeter Avalos return method; 226218de8d7fSPeter Avalos debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); 226318de8d7fSPeter Avalos return NULL; 226418de8d7fSPeter Avalos } 226518de8d7fSPeter Avalos 226618de8d7fSPeter Avalos /* XXX internal state */ 226718de8d7fSPeter Avalos static Authmethod *current = NULL; 226818de8d7fSPeter Avalos static char *supported = NULL; 226918de8d7fSPeter Avalos static char *preferred = NULL; 227018de8d7fSPeter Avalos 227118de8d7fSPeter Avalos /* 227218de8d7fSPeter Avalos * Given the authentication method list sent by the server, return the 227318de8d7fSPeter Avalos * next method we should try. If the server initially sends a nil list, 227418de8d7fSPeter Avalos * use a built-in default list. 227518de8d7fSPeter Avalos */ 227618de8d7fSPeter Avalos static Authmethod * 227718de8d7fSPeter Avalos authmethod_get(char *authlist) 227818de8d7fSPeter Avalos { 227918de8d7fSPeter Avalos char *name = NULL; 228018de8d7fSPeter Avalos u_int next; 228118de8d7fSPeter Avalos 228218de8d7fSPeter Avalos /* Use a suitable default if we're passed a nil list. */ 228318de8d7fSPeter Avalos if (authlist == NULL || strlen(authlist) == 0) 228418de8d7fSPeter Avalos authlist = options.preferred_authentications; 228518de8d7fSPeter Avalos 228618de8d7fSPeter Avalos if (supported == NULL || strcmp(authlist, supported) != 0) { 228718de8d7fSPeter Avalos debug3("start over, passed a different list %s", authlist); 228836e94dc5SPeter Avalos free(supported); 228918de8d7fSPeter Avalos supported = xstrdup(authlist); 229018de8d7fSPeter Avalos preferred = options.preferred_authentications; 229118de8d7fSPeter Avalos debug3("preferred %s", preferred); 229218de8d7fSPeter Avalos current = NULL; 229318de8d7fSPeter Avalos } else if (current != NULL && authmethod_is_enabled(current)) 229418de8d7fSPeter Avalos return current; 229518de8d7fSPeter Avalos 229618de8d7fSPeter Avalos for (;;) { 229718de8d7fSPeter Avalos if ((name = match_list(preferred, supported, &next)) == NULL) { 229818de8d7fSPeter Avalos debug("No more authentication methods to try."); 229918de8d7fSPeter Avalos current = NULL; 230018de8d7fSPeter Avalos return NULL; 230118de8d7fSPeter Avalos } 230218de8d7fSPeter Avalos preferred += next; 230318de8d7fSPeter Avalos debug3("authmethod_lookup %s", name); 230418de8d7fSPeter Avalos debug3("remaining preferred: %s", preferred); 230518de8d7fSPeter Avalos if ((current = authmethod_lookup(name)) != NULL && 230618de8d7fSPeter Avalos authmethod_is_enabled(current)) { 230718de8d7fSPeter Avalos debug3("authmethod_is_enabled %s", name); 230818de8d7fSPeter Avalos debug("Next authentication method: %s", name); 230936e94dc5SPeter Avalos free(name); 231018de8d7fSPeter Avalos return current; 231118de8d7fSPeter Avalos } 231236e94dc5SPeter Avalos free(name); 231318de8d7fSPeter Avalos } 231418de8d7fSPeter Avalos } 231518de8d7fSPeter Avalos 231618de8d7fSPeter Avalos static char * 231718de8d7fSPeter Avalos authmethods_get(void) 231818de8d7fSPeter Avalos { 231918de8d7fSPeter Avalos Authmethod *method = NULL; 2320664f4763Szrj struct sshbuf *b; 232118de8d7fSPeter Avalos char *list; 2322664f4763Szrj int r; 232318de8d7fSPeter Avalos 2324664f4763Szrj if ((b = sshbuf_new()) == NULL) 2325*50a69bb5SSascha Wildner fatal_f("sshbuf_new failed"); 232618de8d7fSPeter Avalos for (method = authmethods; method->name != NULL; method++) { 232718de8d7fSPeter Avalos if (authmethod_is_enabled(method)) { 2328664f4763Szrj if ((r = sshbuf_putf(b, "%s%s", 2329664f4763Szrj sshbuf_len(b) ? "," : "", method->name)) != 0) 2330*50a69bb5SSascha Wildner fatal_fr(r, "buffer error"); 233118de8d7fSPeter Avalos } 233218de8d7fSPeter Avalos } 2333664f4763Szrj if ((list = sshbuf_dup_string(b)) == NULL) 2334*50a69bb5SSascha Wildner fatal_f("sshbuf_dup_string failed"); 2335664f4763Szrj sshbuf_free(b); 233618de8d7fSPeter Avalos return list; 233718de8d7fSPeter Avalos } 2338