1*ce74bacaSMatthew Dillon /* $OpenBSD: sshconnect2.c,v 1.266 2017/08/27 00:38:41 dtucker 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> 3618de8d7fSPeter Avalos #include <netdb.h> 3718de8d7fSPeter Avalos #include <pwd.h> 3818de8d7fSPeter Avalos #include <signal.h> 3918de8d7fSPeter Avalos #include <stdarg.h> 4018de8d7fSPeter Avalos #include <stdio.h> 4118de8d7fSPeter Avalos #include <string.h> 4218de8d7fSPeter Avalos #include <unistd.h> 4336e94dc5SPeter Avalos #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) 4418de8d7fSPeter Avalos #include <vis.h> 4518de8d7fSPeter Avalos #endif 4618de8d7fSPeter Avalos 4718de8d7fSPeter Avalos #include "openbsd-compat/sys-queue.h" 4818de8d7fSPeter Avalos 4918de8d7fSPeter Avalos #include "xmalloc.h" 5018de8d7fSPeter Avalos #include "ssh.h" 5118de8d7fSPeter Avalos #include "ssh2.h" 5218de8d7fSPeter Avalos #include "buffer.h" 5318de8d7fSPeter Avalos #include "packet.h" 5418de8d7fSPeter Avalos #include "compat.h" 5518de8d7fSPeter Avalos #include "cipher.h" 5618de8d7fSPeter Avalos #include "key.h" 5718de8d7fSPeter Avalos #include "kex.h" 5818de8d7fSPeter Avalos #include "myproposal.h" 5918de8d7fSPeter Avalos #include "sshconnect.h" 6018de8d7fSPeter Avalos #include "authfile.h" 6118de8d7fSPeter Avalos #include "dh.h" 6218de8d7fSPeter Avalos #include "authfd.h" 6318de8d7fSPeter Avalos #include "log.h" 6418de8d7fSPeter Avalos #include "misc.h" 6536e94dc5SPeter Avalos #include "readconf.h" 6618de8d7fSPeter Avalos #include "match.h" 6718de8d7fSPeter Avalos #include "dispatch.h" 6818de8d7fSPeter Avalos #include "canohost.h" 6918de8d7fSPeter Avalos #include "msg.h" 7018de8d7fSPeter Avalos #include "pathnames.h" 7118de8d7fSPeter Avalos #include "uidswap.h" 729f304aafSPeter Avalos #include "hostfile.h" 73e9778795SPeter Avalos #include "ssherr.h" 74e9778795SPeter Avalos #include "utf8.h" 7518de8d7fSPeter Avalos 7618de8d7fSPeter Avalos #ifdef GSSAPI 7718de8d7fSPeter Avalos #include "ssh-gss.h" 7818de8d7fSPeter Avalos #endif 7918de8d7fSPeter Avalos 8018de8d7fSPeter Avalos /* import */ 8118de8d7fSPeter Avalos extern char *client_version_string; 8218de8d7fSPeter Avalos extern char *server_version_string; 8318de8d7fSPeter Avalos extern Options options; 8418de8d7fSPeter Avalos 8518de8d7fSPeter Avalos /* 8618de8d7fSPeter Avalos * SSH2 key exchange 8718de8d7fSPeter Avalos */ 8818de8d7fSPeter Avalos 8918de8d7fSPeter Avalos u_char *session_id2 = NULL; 9018de8d7fSPeter Avalos u_int session_id2_len = 0; 9118de8d7fSPeter Avalos 9218de8d7fSPeter Avalos char *xxx_host; 9318de8d7fSPeter Avalos struct sockaddr *xxx_hostaddr; 9418de8d7fSPeter Avalos 9518de8d7fSPeter Avalos static int 96*ce74bacaSMatthew Dillon verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh) 9718de8d7fSPeter Avalos { 9818de8d7fSPeter Avalos if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) 9918de8d7fSPeter Avalos fatal("Host key verification failed."); 10018de8d7fSPeter Avalos return 0; 10118de8d7fSPeter Avalos } 10218de8d7fSPeter Avalos 1039f304aafSPeter Avalos static char * 1049f304aafSPeter Avalos order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port) 1059f304aafSPeter Avalos { 1069f304aafSPeter Avalos char *oavail, *avail, *first, *last, *alg, *hostname, *ret; 1079f304aafSPeter Avalos size_t maxlen; 1089f304aafSPeter Avalos struct hostkeys *hostkeys; 1099f304aafSPeter Avalos int ktype; 1101c188a7fSPeter Avalos u_int i; 1119f304aafSPeter Avalos 1129f304aafSPeter Avalos /* Find all hostkeys for this hostname */ 1139f304aafSPeter Avalos get_hostfile_hostname_ipaddr(host, hostaddr, port, &hostname, NULL); 1149f304aafSPeter Avalos hostkeys = init_hostkeys(); 1151c188a7fSPeter Avalos for (i = 0; i < options.num_user_hostfiles; i++) 1161c188a7fSPeter Avalos load_hostkeys(hostkeys, hostname, options.user_hostfiles[i]); 1171c188a7fSPeter Avalos for (i = 0; i < options.num_system_hostfiles; i++) 1181c188a7fSPeter Avalos load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]); 1199f304aafSPeter Avalos 1209f304aafSPeter Avalos oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG); 1219f304aafSPeter Avalos maxlen = strlen(avail) + 1; 1229f304aafSPeter Avalos first = xmalloc(maxlen); 1239f304aafSPeter Avalos last = xmalloc(maxlen); 1249f304aafSPeter Avalos *first = *last = '\0'; 1259f304aafSPeter Avalos 1269f304aafSPeter Avalos #define ALG_APPEND(to, from) \ 1279f304aafSPeter Avalos do { \ 1289f304aafSPeter Avalos if (*to != '\0') \ 1299f304aafSPeter Avalos strlcat(to, ",", maxlen); \ 1309f304aafSPeter Avalos strlcat(to, from, maxlen); \ 1319f304aafSPeter Avalos } while (0) 1329f304aafSPeter Avalos 1339f304aafSPeter Avalos while ((alg = strsep(&avail, ",")) && *alg != '\0') { 134e9778795SPeter Avalos if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) 1359f304aafSPeter Avalos fatal("%s: unknown alg %s", __func__, alg); 1369f304aafSPeter Avalos if (lookup_key_in_hostkeys_by_type(hostkeys, 137e9778795SPeter Avalos sshkey_type_plain(ktype), NULL)) 1389f304aafSPeter Avalos ALG_APPEND(first, alg); 1399f304aafSPeter Avalos else 1409f304aafSPeter Avalos ALG_APPEND(last, alg); 1419f304aafSPeter Avalos } 1429f304aafSPeter Avalos #undef ALG_APPEND 143e9778795SPeter Avalos xasprintf(&ret, "%s%s%s", first, 144e9778795SPeter Avalos (*first == '\0' || *last == '\0') ? "" : ",", last); 1459f304aafSPeter Avalos if (*first != '\0') 1469f304aafSPeter Avalos debug3("%s: prefer hostkeyalgs: %s", __func__, first); 1479f304aafSPeter Avalos 14836e94dc5SPeter Avalos free(first); 14936e94dc5SPeter Avalos free(last); 15036e94dc5SPeter Avalos free(hostname); 15136e94dc5SPeter Avalos free(oavail); 1529f304aafSPeter Avalos free_hostkeys(hostkeys); 1539f304aafSPeter Avalos 1549f304aafSPeter Avalos return ret; 1559f304aafSPeter Avalos } 1569f304aafSPeter Avalos 15718de8d7fSPeter Avalos void 1589f304aafSPeter Avalos ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) 15918de8d7fSPeter Avalos { 16036e94dc5SPeter Avalos char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 161e9778795SPeter Avalos char *s; 162e9778795SPeter Avalos struct kex *kex; 163e9778795SPeter Avalos int r; 16418de8d7fSPeter Avalos 16518de8d7fSPeter Avalos xxx_host = host; 16618de8d7fSPeter Avalos xxx_hostaddr = hostaddr; 16718de8d7fSPeter Avalos 168e9778795SPeter Avalos if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) 169e9778795SPeter Avalos fatal("%s: kex_names_cat", __func__); 170e9778795SPeter Avalos myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s); 17118de8d7fSPeter Avalos myproposal[PROPOSAL_ENC_ALGS_CTOS] = 172e9778795SPeter Avalos compat_cipher_proposal(options.ciphers); 17318de8d7fSPeter Avalos myproposal[PROPOSAL_ENC_ALGS_STOC] = 174e9778795SPeter Avalos compat_cipher_proposal(options.ciphers); 17518de8d7fSPeter Avalos myproposal[PROPOSAL_COMP_ALGS_CTOS] = 176e9778795SPeter Avalos myproposal[PROPOSAL_COMP_ALGS_STOC] = options.compression ? 177e9778795SPeter Avalos "zlib@openssh.com,zlib,none" : "none,zlib@openssh.com,zlib"; 17818de8d7fSPeter Avalos myproposal[PROPOSAL_MAC_ALGS_CTOS] = 17918de8d7fSPeter Avalos myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; 180e9778795SPeter Avalos if (options.hostkeyalgorithms != NULL) { 181e9778795SPeter Avalos if (kex_assemble_names(KEX_DEFAULT_PK_ALG, 182e9778795SPeter Avalos &options.hostkeyalgorithms) != 0) 183e9778795SPeter Avalos fatal("%s: kex_assemble_namelist", __func__); 18418de8d7fSPeter Avalos myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 18536e94dc5SPeter Avalos compat_pkalg_proposal(options.hostkeyalgorithms); 186e9778795SPeter Avalos } else { 187e9778795SPeter Avalos /* Enforce default */ 188e9778795SPeter Avalos options.hostkeyalgorithms = xstrdup(KEX_DEFAULT_PK_ALG); 1899f304aafSPeter Avalos /* Prefer algorithms that we already have keys for */ 1909f304aafSPeter Avalos myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 19136e94dc5SPeter Avalos compat_pkalg_proposal( 19236e94dc5SPeter Avalos order_hostkeyalgs(host, hostaddr, port)); 1939f304aafSPeter Avalos } 19418de8d7fSPeter Avalos 19536e94dc5SPeter Avalos if (options.rekey_limit || options.rekey_interval) 196*ce74bacaSMatthew Dillon packet_set_rekey_limits(options.rekey_limit, 197*ce74bacaSMatthew Dillon options.rekey_interval); 19818de8d7fSPeter Avalos 19918de8d7fSPeter Avalos /* start key exchange */ 200e9778795SPeter Avalos if ((r = kex_setup(active_state, myproposal)) != 0) 201e9778795SPeter Avalos fatal("kex_setup: %s", ssh_err(r)); 202e9778795SPeter Avalos kex = active_state->kex; 20336e94dc5SPeter Avalos #ifdef WITH_OPENSSL 20418de8d7fSPeter Avalos kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 20518de8d7fSPeter Avalos kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 206e9778795SPeter Avalos kex->kex[KEX_DH_GRP14_SHA256] = kexdh_client; 207e9778795SPeter Avalos kex->kex[KEX_DH_GRP16_SHA512] = kexdh_client; 208e9778795SPeter Avalos kex->kex[KEX_DH_GRP18_SHA512] = kexdh_client; 20918de8d7fSPeter Avalos kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 21018de8d7fSPeter Avalos kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 211e9778795SPeter Avalos # ifdef OPENSSL_HAS_ECC 2129f304aafSPeter Avalos kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 21336e94dc5SPeter Avalos # endif 214e9778795SPeter Avalos #endif 21536e94dc5SPeter Avalos kex->kex[KEX_C25519_SHA256] = kexc25519_client; 21618de8d7fSPeter Avalos kex->client_version_string=client_version_string; 21718de8d7fSPeter Avalos kex->server_version_string=server_version_string; 21818de8d7fSPeter Avalos kex->verify_host_key=&verify_host_key_callback; 21918de8d7fSPeter Avalos 220*ce74bacaSMatthew Dillon ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done); 22118de8d7fSPeter Avalos 222e9778795SPeter Avalos /* remove ext-info from the KEX proposals for rekeying */ 223e9778795SPeter Avalos myproposal[PROPOSAL_KEX_ALGS] = 224e9778795SPeter Avalos compat_kex_proposal(options.kex_algorithms); 225e9778795SPeter Avalos if ((r = kex_prop2buf(kex->my, myproposal)) != 0) 226e9778795SPeter Avalos fatal("kex_prop2buf: %s", ssh_err(r)); 227856ea928SPeter Avalos 22818de8d7fSPeter Avalos session_id2 = kex->session_id; 22918de8d7fSPeter Avalos session_id2_len = kex->session_id_len; 23018de8d7fSPeter Avalos 23118de8d7fSPeter Avalos #ifdef DEBUG_KEXDH 23218de8d7fSPeter Avalos /* send 1st encrypted/maced/compressed message */ 23318de8d7fSPeter Avalos packet_start(SSH2_MSG_IGNORE); 23418de8d7fSPeter Avalos packet_put_cstring("markus"); 23518de8d7fSPeter Avalos packet_send(); 23618de8d7fSPeter Avalos packet_write_wait(); 23718de8d7fSPeter Avalos #endif 23818de8d7fSPeter Avalos } 23918de8d7fSPeter Avalos 24018de8d7fSPeter Avalos /* 24118de8d7fSPeter Avalos * Authenticate user 24218de8d7fSPeter Avalos */ 24318de8d7fSPeter Avalos 244e9778795SPeter Avalos typedef struct cauthctxt Authctxt; 245e9778795SPeter Avalos typedef struct cauthmethod Authmethod; 24618de8d7fSPeter Avalos typedef struct identity Identity; 24718de8d7fSPeter Avalos typedef struct idlist Idlist; 24818de8d7fSPeter Avalos 24918de8d7fSPeter Avalos struct identity { 25018de8d7fSPeter Avalos TAILQ_ENTRY(identity) next; 251e9778795SPeter Avalos int agent_fd; /* >=0 if agent supports key */ 252e9778795SPeter Avalos struct sshkey *key; /* public/private key */ 25318de8d7fSPeter Avalos char *filename; /* comment for agent-only keys */ 25418de8d7fSPeter Avalos int tried; 25518de8d7fSPeter Avalos int isprivate; /* key points to the private key */ 25636e94dc5SPeter Avalos int userprovided; 25718de8d7fSPeter Avalos }; 25818de8d7fSPeter Avalos TAILQ_HEAD(idlist, identity); 25918de8d7fSPeter Avalos 260e9778795SPeter Avalos struct cauthctxt { 26118de8d7fSPeter Avalos const char *server_user; 26218de8d7fSPeter Avalos const char *local_user; 26318de8d7fSPeter Avalos const char *host; 26418de8d7fSPeter Avalos const char *service; 265e9778795SPeter Avalos struct cauthmethod *method; 266856ea928SPeter Avalos sig_atomic_t success; 26718de8d7fSPeter Avalos char *authlist; 268e9778795SPeter Avalos int attempt; 26918de8d7fSPeter Avalos /* pubkey */ 270e9778795SPeter Avalos struct idlist keys; 271e9778795SPeter Avalos int agent_fd; 27218de8d7fSPeter Avalos /* hostbased */ 27318de8d7fSPeter Avalos Sensitive *sensitive; 274e9778795SPeter Avalos char *oktypes, *ktypes; 275e9778795SPeter Avalos const char *active_ktype; 27618de8d7fSPeter Avalos /* kbd-interactive */ 27718de8d7fSPeter Avalos int info_req_seen; 27818de8d7fSPeter Avalos /* generic */ 27918de8d7fSPeter Avalos void *methoddata; 28018de8d7fSPeter Avalos }; 281e9778795SPeter Avalos 282e9778795SPeter Avalos struct cauthmethod { 28318de8d7fSPeter Avalos char *name; /* string to compare against server's list */ 28418de8d7fSPeter Avalos int (*userauth)(Authctxt *authctxt); 285cb5eb4f1SPeter Avalos void (*cleanup)(Authctxt *authctxt); 28618de8d7fSPeter Avalos int *enabled; /* flag in option struct that enables method */ 28718de8d7fSPeter Avalos int *batch_flag; /* flag in option struct that disables method */ 28818de8d7fSPeter Avalos }; 28918de8d7fSPeter Avalos 290*ce74bacaSMatthew Dillon int input_userauth_service_accept(int, u_int32_t, struct ssh *); 291*ce74bacaSMatthew Dillon int input_userauth_ext_info(int, u_int32_t, struct ssh *); 292*ce74bacaSMatthew Dillon int input_userauth_success(int, u_int32_t, struct ssh *); 293*ce74bacaSMatthew Dillon int input_userauth_success_unexpected(int, u_int32_t, struct ssh *); 294*ce74bacaSMatthew Dillon int input_userauth_failure(int, u_int32_t, struct ssh *); 295*ce74bacaSMatthew Dillon int input_userauth_banner(int, u_int32_t, struct ssh *); 296*ce74bacaSMatthew Dillon int input_userauth_error(int, u_int32_t, struct ssh *); 297*ce74bacaSMatthew Dillon int input_userauth_info_req(int, u_int32_t, struct ssh *); 298*ce74bacaSMatthew Dillon int input_userauth_pk_ok(int, u_int32_t, struct ssh *); 299*ce74bacaSMatthew Dillon int input_userauth_passwd_changereq(int, u_int32_t, struct ssh *); 30018de8d7fSPeter Avalos 30118de8d7fSPeter Avalos int userauth_none(Authctxt *); 30218de8d7fSPeter Avalos int userauth_pubkey(Authctxt *); 30318de8d7fSPeter Avalos int userauth_passwd(Authctxt *); 30418de8d7fSPeter Avalos int userauth_kbdint(Authctxt *); 30518de8d7fSPeter Avalos int userauth_hostbased(Authctxt *); 30618de8d7fSPeter Avalos 30718de8d7fSPeter Avalos #ifdef GSSAPI 30818de8d7fSPeter Avalos int userauth_gssapi(Authctxt *authctxt); 309*ce74bacaSMatthew Dillon int input_gssapi_response(int type, u_int32_t, struct ssh *); 310*ce74bacaSMatthew Dillon int input_gssapi_token(int type, u_int32_t, struct ssh *); 311*ce74bacaSMatthew Dillon int input_gssapi_hash(int type, u_int32_t, struct ssh *); 312*ce74bacaSMatthew Dillon int input_gssapi_error(int, u_int32_t, struct ssh *); 313*ce74bacaSMatthew Dillon int input_gssapi_errtok(int, u_int32_t, struct ssh *); 31418de8d7fSPeter Avalos #endif 31518de8d7fSPeter Avalos 31618de8d7fSPeter Avalos void userauth(Authctxt *, char *); 31718de8d7fSPeter Avalos 31818de8d7fSPeter Avalos static int sign_and_send_pubkey(Authctxt *, Identity *); 31918de8d7fSPeter Avalos static void pubkey_prepare(Authctxt *); 32018de8d7fSPeter Avalos static void pubkey_cleanup(Authctxt *); 321*ce74bacaSMatthew Dillon static void pubkey_reset(Authctxt *); 322*ce74bacaSMatthew Dillon static struct sshkey *load_identity_file(Identity *); 32318de8d7fSPeter Avalos 32418de8d7fSPeter Avalos static Authmethod *authmethod_get(char *authlist); 32518de8d7fSPeter Avalos static Authmethod *authmethod_lookup(const char *name); 32618de8d7fSPeter Avalos static char *authmethods_get(void); 32718de8d7fSPeter Avalos 32818de8d7fSPeter Avalos Authmethod authmethods[] = { 32918de8d7fSPeter Avalos #ifdef GSSAPI 33018de8d7fSPeter Avalos {"gssapi-with-mic", 33118de8d7fSPeter Avalos userauth_gssapi, 332cb5eb4f1SPeter Avalos NULL, 33318de8d7fSPeter Avalos &options.gss_authentication, 33418de8d7fSPeter Avalos NULL}, 33518de8d7fSPeter Avalos #endif 33618de8d7fSPeter Avalos {"hostbased", 33718de8d7fSPeter Avalos userauth_hostbased, 338cb5eb4f1SPeter Avalos NULL, 33918de8d7fSPeter Avalos &options.hostbased_authentication, 34018de8d7fSPeter Avalos NULL}, 34118de8d7fSPeter Avalos {"publickey", 34218de8d7fSPeter Avalos userauth_pubkey, 343cb5eb4f1SPeter Avalos NULL, 34418de8d7fSPeter Avalos &options.pubkey_authentication, 34518de8d7fSPeter Avalos NULL}, 34618de8d7fSPeter Avalos {"keyboard-interactive", 34718de8d7fSPeter Avalos userauth_kbdint, 348cb5eb4f1SPeter Avalos NULL, 34918de8d7fSPeter Avalos &options.kbd_interactive_authentication, 35018de8d7fSPeter Avalos &options.batch_mode}, 35118de8d7fSPeter Avalos {"password", 35218de8d7fSPeter Avalos userauth_passwd, 353cb5eb4f1SPeter Avalos NULL, 35418de8d7fSPeter Avalos &options.password_authentication, 35518de8d7fSPeter Avalos &options.batch_mode}, 35618de8d7fSPeter Avalos {"none", 35718de8d7fSPeter Avalos userauth_none, 35818de8d7fSPeter Avalos NULL, 359cb5eb4f1SPeter Avalos NULL, 36018de8d7fSPeter Avalos NULL}, 361cb5eb4f1SPeter Avalos {NULL, NULL, NULL, NULL, NULL} 36218de8d7fSPeter Avalos }; 36318de8d7fSPeter Avalos 36418de8d7fSPeter Avalos void 36518de8d7fSPeter Avalos ssh_userauth2(const char *local_user, const char *server_user, char *host, 36618de8d7fSPeter Avalos Sensitive *sensitive) 36718de8d7fSPeter Avalos { 368e9778795SPeter Avalos struct ssh *ssh = active_state; 36918de8d7fSPeter Avalos Authctxt authctxt; 370e9778795SPeter Avalos int r; 37118de8d7fSPeter Avalos 37218de8d7fSPeter Avalos if (options.challenge_response_authentication) 37318de8d7fSPeter Avalos options.kbd_interactive_authentication = 1; 37418de8d7fSPeter Avalos if (options.preferred_authentications == NULL) 37518de8d7fSPeter Avalos options.preferred_authentications = authmethods_get(); 37618de8d7fSPeter Avalos 37718de8d7fSPeter Avalos /* setup authentication context */ 37818de8d7fSPeter Avalos memset(&authctxt, 0, sizeof(authctxt)); 37918de8d7fSPeter Avalos pubkey_prepare(&authctxt); 38018de8d7fSPeter Avalos authctxt.server_user = server_user; 38118de8d7fSPeter Avalos authctxt.local_user = local_user; 38218de8d7fSPeter Avalos authctxt.host = host; 38318de8d7fSPeter Avalos authctxt.service = "ssh-connection"; /* service name */ 38418de8d7fSPeter Avalos authctxt.success = 0; 38518de8d7fSPeter Avalos authctxt.method = authmethod_lookup("none"); 38618de8d7fSPeter Avalos authctxt.authlist = NULL; 38718de8d7fSPeter Avalos authctxt.methoddata = NULL; 38818de8d7fSPeter Avalos authctxt.sensitive = sensitive; 389e9778795SPeter Avalos authctxt.active_ktype = authctxt.oktypes = authctxt.ktypes = NULL; 39018de8d7fSPeter Avalos authctxt.info_req_seen = 0; 391e9778795SPeter Avalos authctxt.agent_fd = -1; 39218de8d7fSPeter Avalos if (authctxt.method == NULL) 39318de8d7fSPeter Avalos fatal("ssh_userauth2: internal error: cannot send userauth none request"); 39418de8d7fSPeter Avalos 395e9778795SPeter Avalos if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 || 396e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 || 397e9778795SPeter Avalos (r = sshpkt_send(ssh)) != 0) 398e9778795SPeter Avalos fatal("%s: %s", __func__, ssh_err(r)); 39918de8d7fSPeter Avalos 400*ce74bacaSMatthew Dillon ssh->authctxt = &authctxt; 401e9778795SPeter Avalos ssh_dispatch_init(ssh, &input_userauth_error); 402e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info); 403e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept); 404*ce74bacaSMatthew Dillon ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */ 405*ce74bacaSMatthew Dillon ssh->authctxt = NULL; 40618de8d7fSPeter Avalos 40718de8d7fSPeter Avalos pubkey_cleanup(&authctxt); 408e9778795SPeter Avalos ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); 40918de8d7fSPeter Avalos 410*ce74bacaSMatthew Dillon if (!authctxt.success) 411*ce74bacaSMatthew Dillon fatal("Authentication failed."); 41218de8d7fSPeter Avalos debug("Authentication succeeded (%s).", authctxt.method->name); 41318de8d7fSPeter Avalos } 41418de8d7fSPeter Avalos 415e9778795SPeter Avalos /* ARGSUSED */ 416e9778795SPeter Avalos int 417*ce74bacaSMatthew Dillon input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh) 418e9778795SPeter Avalos { 419*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 420e9778795SPeter Avalos int r; 421e9778795SPeter Avalos 422e9778795SPeter Avalos if (ssh_packet_remaining(ssh) > 0) { 423e9778795SPeter Avalos char *reply; 424e9778795SPeter Avalos 425e9778795SPeter Avalos if ((r = sshpkt_get_cstring(ssh, &reply, NULL)) != 0) 426e9778795SPeter Avalos goto out; 427e9778795SPeter Avalos debug2("service_accept: %s", reply); 428e9778795SPeter Avalos free(reply); 429e9778795SPeter Avalos } else { 430e9778795SPeter Avalos debug2("buggy server: service_accept w/o service"); 431e9778795SPeter Avalos } 432e9778795SPeter Avalos if ((r = sshpkt_get_end(ssh)) != 0) 433e9778795SPeter Avalos goto out; 434e9778795SPeter Avalos debug("SSH2_MSG_SERVICE_ACCEPT received"); 435e9778795SPeter Avalos 436e9778795SPeter Avalos /* initial userauth request */ 437e9778795SPeter Avalos userauth_none(authctxt); 438e9778795SPeter Avalos 439e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error); 440e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); 441e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); 442e9778795SPeter Avalos ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); 443e9778795SPeter Avalos r = 0; 444e9778795SPeter Avalos out: 445e9778795SPeter Avalos return r; 446e9778795SPeter Avalos } 447e9778795SPeter Avalos 448e9778795SPeter Avalos /* ARGSUSED */ 449e9778795SPeter Avalos int 450*ce74bacaSMatthew Dillon input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh) 451e9778795SPeter Avalos { 452*ce74bacaSMatthew Dillon return kex_input_ext_info(type, seqnr, ssh); 453e9778795SPeter Avalos } 454e9778795SPeter Avalos 45518de8d7fSPeter Avalos void 45618de8d7fSPeter Avalos userauth(Authctxt *authctxt, char *authlist) 45718de8d7fSPeter Avalos { 458cb5eb4f1SPeter Avalos if (authctxt->method != NULL && authctxt->method->cleanup != NULL) 459cb5eb4f1SPeter Avalos authctxt->method->cleanup(authctxt); 460cb5eb4f1SPeter Avalos 46136e94dc5SPeter Avalos free(authctxt->methoddata); 46218de8d7fSPeter Avalos authctxt->methoddata = NULL; 46318de8d7fSPeter Avalos if (authlist == NULL) { 46418de8d7fSPeter Avalos authlist = authctxt->authlist; 46518de8d7fSPeter Avalos } else { 46636e94dc5SPeter Avalos free(authctxt->authlist); 46718de8d7fSPeter Avalos authctxt->authlist = authlist; 46818de8d7fSPeter Avalos } 46918de8d7fSPeter Avalos for (;;) { 47018de8d7fSPeter Avalos Authmethod *method = authmethod_get(authlist); 47118de8d7fSPeter Avalos if (method == NULL) 472*ce74bacaSMatthew Dillon fatal("%s@%s: Permission denied (%s).", 473*ce74bacaSMatthew Dillon authctxt->server_user, authctxt->host, authlist); 47418de8d7fSPeter Avalos authctxt->method = method; 47518de8d7fSPeter Avalos 47618de8d7fSPeter Avalos /* reset the per method handler */ 47718de8d7fSPeter Avalos dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN, 47818de8d7fSPeter Avalos SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL); 47918de8d7fSPeter Avalos 48018de8d7fSPeter Avalos /* and try new method */ 48118de8d7fSPeter Avalos if (method->userauth(authctxt) != 0) { 48218de8d7fSPeter Avalos debug2("we sent a %s packet, wait for reply", method->name); 48318de8d7fSPeter Avalos break; 48418de8d7fSPeter Avalos } else { 48518de8d7fSPeter Avalos debug2("we did not send a packet, disable method"); 48618de8d7fSPeter Avalos method->enabled = NULL; 48718de8d7fSPeter Avalos } 48818de8d7fSPeter Avalos } 48918de8d7fSPeter Avalos } 49018de8d7fSPeter Avalos 491cb5eb4f1SPeter Avalos /* ARGSUSED */ 492e9778795SPeter Avalos int 493*ce74bacaSMatthew Dillon input_userauth_error(int type, u_int32_t seq, struct ssh *ssh) 49418de8d7fSPeter Avalos { 49518de8d7fSPeter Avalos fatal("input_userauth_error: bad message during authentication: " 49618de8d7fSPeter Avalos "type %d", type); 497e9778795SPeter Avalos return 0; 49818de8d7fSPeter Avalos } 49918de8d7fSPeter Avalos 500cb5eb4f1SPeter Avalos /* ARGSUSED */ 501e9778795SPeter Avalos int 502*ce74bacaSMatthew Dillon input_userauth_banner(int type, u_int32_t seq, struct ssh *ssh) 50318de8d7fSPeter Avalos { 504e9778795SPeter Avalos char *msg, *lang; 50518de8d7fSPeter Avalos u_int len; 50618de8d7fSPeter Avalos 507e9778795SPeter Avalos debug3("%s", __func__); 508e9778795SPeter Avalos msg = packet_get_string(&len); 50918de8d7fSPeter Avalos lang = packet_get_string(NULL); 510e9778795SPeter Avalos if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) 511e9778795SPeter Avalos fmprintf(stderr, "%s", msg); 51236e94dc5SPeter Avalos free(msg); 51336e94dc5SPeter Avalos free(lang); 514e9778795SPeter Avalos return 0; 51518de8d7fSPeter Avalos } 51618de8d7fSPeter Avalos 517cb5eb4f1SPeter Avalos /* ARGSUSED */ 518e9778795SPeter Avalos int 519*ce74bacaSMatthew Dillon input_userauth_success(int type, u_int32_t seq, struct ssh *ssh) 52018de8d7fSPeter Avalos { 521*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 522856ea928SPeter Avalos 52318de8d7fSPeter Avalos if (authctxt == NULL) 52418de8d7fSPeter Avalos fatal("input_userauth_success: no authentication context"); 52536e94dc5SPeter Avalos free(authctxt->authlist); 52618de8d7fSPeter Avalos authctxt->authlist = NULL; 527856ea928SPeter Avalos if (authctxt->method != NULL && authctxt->method->cleanup != NULL) 528856ea928SPeter Avalos authctxt->method->cleanup(authctxt); 52936e94dc5SPeter Avalos free(authctxt->methoddata); 53018de8d7fSPeter Avalos authctxt->methoddata = NULL; 53118de8d7fSPeter Avalos authctxt->success = 1; /* break out */ 532e9778795SPeter Avalos return 0; 53318de8d7fSPeter Avalos } 53418de8d7fSPeter Avalos 535e9778795SPeter Avalos int 536*ce74bacaSMatthew Dillon input_userauth_success_unexpected(int type, u_int32_t seq, struct ssh *ssh) 537856ea928SPeter Avalos { 538*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 539856ea928SPeter Avalos 540856ea928SPeter Avalos if (authctxt == NULL) 541856ea928SPeter Avalos fatal("%s: no authentication context", __func__); 542856ea928SPeter Avalos 543856ea928SPeter Avalos fatal("Unexpected authentication success during %s.", 544856ea928SPeter Avalos authctxt->method->name); 545e9778795SPeter Avalos return 0; 546856ea928SPeter Avalos } 547856ea928SPeter Avalos 548cb5eb4f1SPeter Avalos /* ARGSUSED */ 549e9778795SPeter Avalos int 550*ce74bacaSMatthew Dillon input_userauth_failure(int type, u_int32_t seq, struct ssh *ssh) 55118de8d7fSPeter Avalos { 552*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 55318de8d7fSPeter Avalos char *authlist = NULL; 55418de8d7fSPeter Avalos int partial; 55518de8d7fSPeter Avalos 55618de8d7fSPeter Avalos if (authctxt == NULL) 55718de8d7fSPeter Avalos fatal("input_userauth_failure: no authentication context"); 55818de8d7fSPeter Avalos 55918de8d7fSPeter Avalos authlist = packet_get_string(NULL); 56018de8d7fSPeter Avalos partial = packet_get_char(); 56118de8d7fSPeter Avalos packet_check_eom(); 56218de8d7fSPeter Avalos 56336e94dc5SPeter Avalos if (partial != 0) { 564e9778795SPeter Avalos verbose("Authenticated with partial success."); 56536e94dc5SPeter Avalos /* reset state */ 566*ce74bacaSMatthew Dillon pubkey_reset(authctxt); 56736e94dc5SPeter Avalos } 56818de8d7fSPeter Avalos debug("Authentications that can continue: %s", authlist); 56918de8d7fSPeter Avalos 57018de8d7fSPeter Avalos userauth(authctxt, authlist); 571e9778795SPeter Avalos return 0; 57218de8d7fSPeter Avalos } 573cb5eb4f1SPeter Avalos 574cb5eb4f1SPeter Avalos /* ARGSUSED */ 575e9778795SPeter Avalos int 576*ce74bacaSMatthew Dillon input_userauth_pk_ok(int type, u_int32_t seq, struct ssh *ssh) 57718de8d7fSPeter Avalos { 578*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 579*ce74bacaSMatthew Dillon struct sshkey *key = NULL; 58018de8d7fSPeter Avalos Identity *id = NULL; 58118de8d7fSPeter Avalos Buffer b; 58218de8d7fSPeter Avalos int pktype, sent = 0; 58318de8d7fSPeter Avalos u_int alen, blen; 58418de8d7fSPeter Avalos char *pkalg, *fp; 58518de8d7fSPeter Avalos u_char *pkblob; 58618de8d7fSPeter Avalos 58718de8d7fSPeter Avalos if (authctxt == NULL) 58818de8d7fSPeter Avalos fatal("input_userauth_pk_ok: no authentication context"); 58918de8d7fSPeter Avalos if (datafellows & SSH_BUG_PKOK) { 59018de8d7fSPeter Avalos /* this is similar to SSH_BUG_PKAUTH */ 59118de8d7fSPeter Avalos debug2("input_userauth_pk_ok: SSH_BUG_PKOK"); 59218de8d7fSPeter Avalos pkblob = packet_get_string(&blen); 59318de8d7fSPeter Avalos buffer_init(&b); 59418de8d7fSPeter Avalos buffer_append(&b, pkblob, blen); 59518de8d7fSPeter Avalos pkalg = buffer_get_string(&b, &alen); 59618de8d7fSPeter Avalos buffer_free(&b); 59718de8d7fSPeter Avalos } else { 59818de8d7fSPeter Avalos pkalg = packet_get_string(&alen); 59918de8d7fSPeter Avalos pkblob = packet_get_string(&blen); 60018de8d7fSPeter Avalos } 60118de8d7fSPeter Avalos packet_check_eom(); 60218de8d7fSPeter Avalos 60318de8d7fSPeter Avalos debug("Server accepts key: pkalg %s blen %u", pkalg, blen); 60418de8d7fSPeter Avalos 60518de8d7fSPeter Avalos if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { 60618de8d7fSPeter Avalos debug("unknown pkalg %s", pkalg); 60718de8d7fSPeter Avalos goto done; 60818de8d7fSPeter Avalos } 60918de8d7fSPeter Avalos if ((key = key_from_blob(pkblob, blen)) == NULL) { 61018de8d7fSPeter Avalos debug("no key from blob. pkalg %s", pkalg); 61118de8d7fSPeter Avalos goto done; 61218de8d7fSPeter Avalos } 61318de8d7fSPeter Avalos if (key->type != pktype) { 61418de8d7fSPeter Avalos error("input_userauth_pk_ok: type mismatch " 61518de8d7fSPeter Avalos "for decoded key (received %d, expected %d)", 61618de8d7fSPeter Avalos key->type, pktype); 61718de8d7fSPeter Avalos goto done; 61818de8d7fSPeter Avalos } 619e9778795SPeter Avalos if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, 620e9778795SPeter Avalos SSH_FP_DEFAULT)) == NULL) 621e9778795SPeter Avalos goto done; 62218de8d7fSPeter Avalos debug2("input_userauth_pk_ok: fp %s", fp); 62336e94dc5SPeter Avalos free(fp); 62418de8d7fSPeter Avalos 62518de8d7fSPeter Avalos /* 62618de8d7fSPeter Avalos * search keys in the reverse order, because last candidate has been 62718de8d7fSPeter Avalos * moved to the end of the queue. this also avoids confusion by 62818de8d7fSPeter Avalos * duplicate keys 62918de8d7fSPeter Avalos */ 63018de8d7fSPeter Avalos TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { 63118de8d7fSPeter Avalos if (key_equal(key, id->key)) { 63218de8d7fSPeter Avalos sent = sign_and_send_pubkey(authctxt, id); 63318de8d7fSPeter Avalos break; 63418de8d7fSPeter Avalos } 63518de8d7fSPeter Avalos } 63618de8d7fSPeter Avalos done: 63718de8d7fSPeter Avalos if (key != NULL) 63818de8d7fSPeter Avalos key_free(key); 63936e94dc5SPeter Avalos free(pkalg); 64036e94dc5SPeter Avalos free(pkblob); 64118de8d7fSPeter Avalos 64218de8d7fSPeter Avalos /* try another method if we did not send a packet */ 64318de8d7fSPeter Avalos if (sent == 0) 64418de8d7fSPeter Avalos userauth(authctxt, NULL); 645e9778795SPeter Avalos return 0; 64618de8d7fSPeter Avalos } 64718de8d7fSPeter Avalos 64818de8d7fSPeter Avalos #ifdef GSSAPI 64918de8d7fSPeter Avalos int 65018de8d7fSPeter Avalos userauth_gssapi(Authctxt *authctxt) 65118de8d7fSPeter Avalos { 65218de8d7fSPeter Avalos Gssctxt *gssctxt = NULL; 65318de8d7fSPeter Avalos static gss_OID_set gss_supported = NULL; 65418de8d7fSPeter Avalos static u_int mech = 0; 65518de8d7fSPeter Avalos OM_uint32 min; 65618de8d7fSPeter Avalos int ok = 0; 65718de8d7fSPeter Avalos 65818de8d7fSPeter Avalos /* Try one GSSAPI method at a time, rather than sending them all at 65918de8d7fSPeter Avalos * once. */ 66018de8d7fSPeter Avalos 66118de8d7fSPeter Avalos if (gss_supported == NULL) 66218de8d7fSPeter Avalos gss_indicate_mechs(&min, &gss_supported); 66318de8d7fSPeter Avalos 66418de8d7fSPeter Avalos /* Check to see if the mechanism is usable before we offer it */ 66518de8d7fSPeter Avalos while (mech < gss_supported->count && !ok) { 66618de8d7fSPeter Avalos /* My DER encoding requires length<128 */ 66718de8d7fSPeter Avalos if (gss_supported->elements[mech].length < 128 && 66818de8d7fSPeter Avalos ssh_gssapi_check_mechanism(&gssctxt, 66918de8d7fSPeter Avalos &gss_supported->elements[mech], authctxt->host)) { 67018de8d7fSPeter Avalos ok = 1; /* Mechanism works */ 67118de8d7fSPeter Avalos } else { 67218de8d7fSPeter Avalos mech++; 67318de8d7fSPeter Avalos } 67418de8d7fSPeter Avalos } 67518de8d7fSPeter Avalos 67618de8d7fSPeter Avalos if (!ok) 67718de8d7fSPeter Avalos return 0; 67818de8d7fSPeter Avalos 67918de8d7fSPeter Avalos authctxt->methoddata=(void *)gssctxt; 68018de8d7fSPeter Avalos 68118de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_REQUEST); 68218de8d7fSPeter Avalos packet_put_cstring(authctxt->server_user); 68318de8d7fSPeter Avalos packet_put_cstring(authctxt->service); 68418de8d7fSPeter Avalos packet_put_cstring(authctxt->method->name); 68518de8d7fSPeter Avalos 68618de8d7fSPeter Avalos packet_put_int(1); 68718de8d7fSPeter Avalos 68818de8d7fSPeter Avalos packet_put_int((gss_supported->elements[mech].length) + 2); 68918de8d7fSPeter Avalos packet_put_char(SSH_GSS_OIDTYPE); 69018de8d7fSPeter Avalos packet_put_char(gss_supported->elements[mech].length); 69118de8d7fSPeter Avalos packet_put_raw(gss_supported->elements[mech].elements, 69218de8d7fSPeter Avalos gss_supported->elements[mech].length); 69318de8d7fSPeter Avalos 69418de8d7fSPeter Avalos packet_send(); 69518de8d7fSPeter Avalos 69618de8d7fSPeter Avalos dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response); 69718de8d7fSPeter Avalos dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); 69818de8d7fSPeter Avalos dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error); 69918de8d7fSPeter Avalos dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); 70018de8d7fSPeter Avalos 70118de8d7fSPeter Avalos mech++; /* Move along to next candidate */ 70218de8d7fSPeter Avalos 70318de8d7fSPeter Avalos return 1; 70418de8d7fSPeter Avalos } 70518de8d7fSPeter Avalos 70618de8d7fSPeter Avalos static OM_uint32 707*ce74bacaSMatthew Dillon process_gssapi_token(struct ssh *ssh, gss_buffer_t recv_tok) 70818de8d7fSPeter Avalos { 709*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 71018de8d7fSPeter Avalos Gssctxt *gssctxt = authctxt->methoddata; 71118de8d7fSPeter Avalos gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 71218de8d7fSPeter Avalos gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; 71318de8d7fSPeter Avalos gss_buffer_desc gssbuf; 71418de8d7fSPeter Avalos OM_uint32 status, ms, flags; 71518de8d7fSPeter Avalos Buffer b; 71618de8d7fSPeter Avalos 71718de8d7fSPeter Avalos status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, 71818de8d7fSPeter Avalos recv_tok, &send_tok, &flags); 71918de8d7fSPeter Avalos 72018de8d7fSPeter Avalos if (send_tok.length > 0) { 72118de8d7fSPeter Avalos if (GSS_ERROR(status)) 72218de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); 72318de8d7fSPeter Avalos else 72418de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); 72518de8d7fSPeter Avalos 72618de8d7fSPeter Avalos packet_put_string(send_tok.value, send_tok.length); 72718de8d7fSPeter Avalos packet_send(); 72818de8d7fSPeter Avalos gss_release_buffer(&ms, &send_tok); 72918de8d7fSPeter Avalos } 73018de8d7fSPeter Avalos 73118de8d7fSPeter Avalos if (status == GSS_S_COMPLETE) { 73218de8d7fSPeter Avalos /* send either complete or MIC, depending on mechanism */ 73318de8d7fSPeter Avalos if (!(flags & GSS_C_INTEG_FLAG)) { 73418de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); 73518de8d7fSPeter Avalos packet_send(); 73618de8d7fSPeter Avalos } else { 73718de8d7fSPeter Avalos ssh_gssapi_buildmic(&b, authctxt->server_user, 73818de8d7fSPeter Avalos authctxt->service, "gssapi-with-mic"); 73918de8d7fSPeter Avalos 74018de8d7fSPeter Avalos gssbuf.value = buffer_ptr(&b); 74118de8d7fSPeter Avalos gssbuf.length = buffer_len(&b); 74218de8d7fSPeter Avalos 74318de8d7fSPeter Avalos status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic); 74418de8d7fSPeter Avalos 74518de8d7fSPeter Avalos if (!GSS_ERROR(status)) { 74618de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC); 74718de8d7fSPeter Avalos packet_put_string(mic.value, mic.length); 74818de8d7fSPeter Avalos 74918de8d7fSPeter Avalos packet_send(); 75018de8d7fSPeter Avalos } 75118de8d7fSPeter Avalos 75218de8d7fSPeter Avalos buffer_free(&b); 75318de8d7fSPeter Avalos gss_release_buffer(&ms, &mic); 75418de8d7fSPeter Avalos } 75518de8d7fSPeter Avalos } 75618de8d7fSPeter Avalos 75718de8d7fSPeter Avalos return status; 75818de8d7fSPeter Avalos } 75918de8d7fSPeter Avalos 760cb5eb4f1SPeter Avalos /* ARGSUSED */ 761e9778795SPeter Avalos int 762*ce74bacaSMatthew Dillon input_gssapi_response(int type, u_int32_t plen, struct ssh *ssh) 76318de8d7fSPeter Avalos { 764*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 76518de8d7fSPeter Avalos Gssctxt *gssctxt; 76618de8d7fSPeter Avalos int oidlen; 76718de8d7fSPeter Avalos char *oidv; 76818de8d7fSPeter Avalos 76918de8d7fSPeter Avalos if (authctxt == NULL) 77018de8d7fSPeter Avalos fatal("input_gssapi_response: no authentication context"); 77118de8d7fSPeter Avalos gssctxt = authctxt->methoddata; 77218de8d7fSPeter Avalos 77318de8d7fSPeter Avalos /* Setup our OID */ 77418de8d7fSPeter Avalos oidv = packet_get_string(&oidlen); 77518de8d7fSPeter Avalos 77618de8d7fSPeter Avalos if (oidlen <= 2 || 77718de8d7fSPeter Avalos oidv[0] != SSH_GSS_OIDTYPE || 77818de8d7fSPeter Avalos oidv[1] != oidlen - 2) { 77936e94dc5SPeter Avalos free(oidv); 78018de8d7fSPeter Avalos debug("Badly encoded mechanism OID received"); 78118de8d7fSPeter Avalos userauth(authctxt, NULL); 782e9778795SPeter Avalos return 0; 78318de8d7fSPeter Avalos } 78418de8d7fSPeter Avalos 78518de8d7fSPeter Avalos if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) 78618de8d7fSPeter Avalos fatal("Server returned different OID than expected"); 78718de8d7fSPeter Avalos 78818de8d7fSPeter Avalos packet_check_eom(); 78918de8d7fSPeter Avalos 79036e94dc5SPeter Avalos free(oidv); 79118de8d7fSPeter Avalos 792*ce74bacaSMatthew Dillon if (GSS_ERROR(process_gssapi_token(ssh, GSS_C_NO_BUFFER))) { 79318de8d7fSPeter Avalos /* Start again with next method on list */ 79418de8d7fSPeter Avalos debug("Trying to start again"); 79518de8d7fSPeter Avalos userauth(authctxt, NULL); 796e9778795SPeter Avalos return 0; 79718de8d7fSPeter Avalos } 798e9778795SPeter Avalos return 0; 79918de8d7fSPeter Avalos } 80018de8d7fSPeter Avalos 801cb5eb4f1SPeter Avalos /* ARGSUSED */ 802e9778795SPeter Avalos int 803*ce74bacaSMatthew Dillon input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh) 80418de8d7fSPeter Avalos { 805*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 80618de8d7fSPeter Avalos gss_buffer_desc recv_tok; 80718de8d7fSPeter Avalos OM_uint32 status; 80818de8d7fSPeter Avalos u_int slen; 80918de8d7fSPeter Avalos 81018de8d7fSPeter Avalos if (authctxt == NULL) 81118de8d7fSPeter Avalos fatal("input_gssapi_response: no authentication context"); 81218de8d7fSPeter Avalos 81318de8d7fSPeter Avalos recv_tok.value = packet_get_string(&slen); 81418de8d7fSPeter Avalos recv_tok.length = slen; /* safe typecast */ 81518de8d7fSPeter Avalos 81618de8d7fSPeter Avalos packet_check_eom(); 81718de8d7fSPeter Avalos 818*ce74bacaSMatthew Dillon status = process_gssapi_token(ssh, &recv_tok); 81918de8d7fSPeter Avalos 82036e94dc5SPeter Avalos free(recv_tok.value); 82118de8d7fSPeter Avalos 82218de8d7fSPeter Avalos if (GSS_ERROR(status)) { 82318de8d7fSPeter Avalos /* Start again with the next method in the list */ 82418de8d7fSPeter Avalos userauth(authctxt, NULL); 825e9778795SPeter Avalos return 0; 82618de8d7fSPeter Avalos } 827e9778795SPeter Avalos return 0; 82818de8d7fSPeter Avalos } 82918de8d7fSPeter Avalos 830cb5eb4f1SPeter Avalos /* ARGSUSED */ 831e9778795SPeter Avalos int 832*ce74bacaSMatthew Dillon input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh) 83318de8d7fSPeter Avalos { 834*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 83518de8d7fSPeter Avalos Gssctxt *gssctxt; 83618de8d7fSPeter Avalos gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 83718de8d7fSPeter Avalos gss_buffer_desc recv_tok; 83836e94dc5SPeter Avalos OM_uint32 ms; 83918de8d7fSPeter Avalos u_int len; 84018de8d7fSPeter Avalos 84118de8d7fSPeter Avalos if (authctxt == NULL) 84218de8d7fSPeter Avalos fatal("input_gssapi_response: no authentication context"); 84318de8d7fSPeter Avalos gssctxt = authctxt->methoddata; 84418de8d7fSPeter Avalos 84518de8d7fSPeter Avalos recv_tok.value = packet_get_string(&len); 84618de8d7fSPeter Avalos recv_tok.length = len; 84718de8d7fSPeter Avalos 84818de8d7fSPeter Avalos packet_check_eom(); 84918de8d7fSPeter Avalos 85018de8d7fSPeter Avalos /* Stick it into GSSAPI and see what it says */ 85136e94dc5SPeter Avalos (void)ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, 85218de8d7fSPeter Avalos &recv_tok, &send_tok, NULL); 85318de8d7fSPeter Avalos 85436e94dc5SPeter Avalos free(recv_tok.value); 85518de8d7fSPeter Avalos gss_release_buffer(&ms, &send_tok); 85618de8d7fSPeter Avalos 85718de8d7fSPeter Avalos /* Server will be returning a failed packet after this one */ 858e9778795SPeter Avalos return 0; 85918de8d7fSPeter Avalos } 86018de8d7fSPeter Avalos 861cb5eb4f1SPeter Avalos /* ARGSUSED */ 862e9778795SPeter Avalos int 863*ce74bacaSMatthew Dillon input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) 86418de8d7fSPeter Avalos { 86518de8d7fSPeter Avalos char *msg; 86618de8d7fSPeter Avalos char *lang; 86718de8d7fSPeter Avalos 86836e94dc5SPeter Avalos /* maj */(void)packet_get_int(); 86936e94dc5SPeter Avalos /* min */(void)packet_get_int(); 87018de8d7fSPeter Avalos msg=packet_get_string(NULL); 87118de8d7fSPeter Avalos lang=packet_get_string(NULL); 87218de8d7fSPeter Avalos 87318de8d7fSPeter Avalos packet_check_eom(); 87418de8d7fSPeter Avalos 87518de8d7fSPeter Avalos debug("Server GSSAPI Error:\n%s", msg); 87636e94dc5SPeter Avalos free(msg); 87736e94dc5SPeter Avalos free(lang); 878e9778795SPeter Avalos return 0; 87918de8d7fSPeter Avalos } 88018de8d7fSPeter Avalos #endif /* GSSAPI */ 88118de8d7fSPeter Avalos 88218de8d7fSPeter Avalos int 88318de8d7fSPeter Avalos userauth_none(Authctxt *authctxt) 88418de8d7fSPeter Avalos { 88518de8d7fSPeter Avalos /* initial userauth request */ 88618de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_REQUEST); 88718de8d7fSPeter Avalos packet_put_cstring(authctxt->server_user); 88818de8d7fSPeter Avalos packet_put_cstring(authctxt->service); 88918de8d7fSPeter Avalos packet_put_cstring(authctxt->method->name); 89018de8d7fSPeter Avalos packet_send(); 89118de8d7fSPeter Avalos return 1; 89218de8d7fSPeter Avalos } 89318de8d7fSPeter Avalos 89418de8d7fSPeter Avalos int 89518de8d7fSPeter Avalos userauth_passwd(Authctxt *authctxt) 89618de8d7fSPeter Avalos { 89718de8d7fSPeter Avalos static int attempt = 0; 898*ce74bacaSMatthew Dillon char prompt[256]; 89918de8d7fSPeter Avalos char *password; 900856ea928SPeter Avalos const char *host = options.host_key_alias ? options.host_key_alias : 901856ea928SPeter Avalos authctxt->host; 90218de8d7fSPeter Avalos 90318de8d7fSPeter Avalos if (attempt++ >= options.number_of_password_prompts) 90418de8d7fSPeter Avalos return 0; 90518de8d7fSPeter Avalos 90618de8d7fSPeter Avalos if (attempt != 1) 90718de8d7fSPeter Avalos error("Permission denied, please try again."); 90818de8d7fSPeter Avalos 90918de8d7fSPeter Avalos snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", 910856ea928SPeter Avalos authctxt->server_user, host); 91118de8d7fSPeter Avalos password = read_passphrase(prompt, 0); 91218de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_REQUEST); 91318de8d7fSPeter Avalos packet_put_cstring(authctxt->server_user); 91418de8d7fSPeter Avalos packet_put_cstring(authctxt->service); 91518de8d7fSPeter Avalos packet_put_cstring(authctxt->method->name); 91618de8d7fSPeter Avalos packet_put_char(0); 91718de8d7fSPeter Avalos packet_put_cstring(password); 91836e94dc5SPeter Avalos explicit_bzero(password, strlen(password)); 91936e94dc5SPeter Avalos free(password); 92018de8d7fSPeter Avalos packet_add_padding(64); 92118de8d7fSPeter Avalos packet_send(); 92218de8d7fSPeter Avalos 92318de8d7fSPeter Avalos dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 92418de8d7fSPeter Avalos &input_userauth_passwd_changereq); 92518de8d7fSPeter Avalos 92618de8d7fSPeter Avalos return 1; 92718de8d7fSPeter Avalos } 928cb5eb4f1SPeter Avalos 92918de8d7fSPeter Avalos /* 93018de8d7fSPeter Avalos * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST 93118de8d7fSPeter Avalos */ 932cb5eb4f1SPeter Avalos /* ARGSUSED */ 933e9778795SPeter Avalos int 934*ce74bacaSMatthew Dillon input_userauth_passwd_changereq(int type, u_int32_t seqnr, struct ssh *ssh) 93518de8d7fSPeter Avalos { 936*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 93718de8d7fSPeter Avalos char *info, *lang, *password = NULL, *retype = NULL; 938*ce74bacaSMatthew Dillon char prompt[256]; 939*ce74bacaSMatthew Dillon const char *host; 94018de8d7fSPeter Avalos 94118de8d7fSPeter Avalos debug2("input_userauth_passwd_changereq"); 94218de8d7fSPeter Avalos 94318de8d7fSPeter Avalos if (authctxt == NULL) 94418de8d7fSPeter Avalos fatal("input_userauth_passwd_changereq: " 94518de8d7fSPeter Avalos "no authentication context"); 946*ce74bacaSMatthew Dillon host = options.host_key_alias ? options.host_key_alias : authctxt->host; 94718de8d7fSPeter Avalos 94818de8d7fSPeter Avalos info = packet_get_string(NULL); 94918de8d7fSPeter Avalos lang = packet_get_string(NULL); 95018de8d7fSPeter Avalos if (strlen(info) > 0) 95118de8d7fSPeter Avalos logit("%s", info); 95236e94dc5SPeter Avalos free(info); 95336e94dc5SPeter Avalos free(lang); 95418de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_REQUEST); 95518de8d7fSPeter Avalos packet_put_cstring(authctxt->server_user); 95618de8d7fSPeter Avalos packet_put_cstring(authctxt->service); 95718de8d7fSPeter Avalos packet_put_cstring(authctxt->method->name); 95818de8d7fSPeter Avalos packet_put_char(1); /* additional info */ 95918de8d7fSPeter Avalos snprintf(prompt, sizeof(prompt), 96018de8d7fSPeter Avalos "Enter %.30s@%.128s's old password: ", 961856ea928SPeter Avalos authctxt->server_user, host); 96218de8d7fSPeter Avalos password = read_passphrase(prompt, 0); 96318de8d7fSPeter Avalos packet_put_cstring(password); 96436e94dc5SPeter Avalos explicit_bzero(password, strlen(password)); 96536e94dc5SPeter Avalos free(password); 96618de8d7fSPeter Avalos password = NULL; 96718de8d7fSPeter Avalos while (password == NULL) { 96818de8d7fSPeter Avalos snprintf(prompt, sizeof(prompt), 96918de8d7fSPeter Avalos "Enter %.30s@%.128s's new password: ", 970856ea928SPeter Avalos authctxt->server_user, host); 97118de8d7fSPeter Avalos password = read_passphrase(prompt, RP_ALLOW_EOF); 97218de8d7fSPeter Avalos if (password == NULL) { 97318de8d7fSPeter Avalos /* bail out */ 974e9778795SPeter Avalos return 0; 97518de8d7fSPeter Avalos } 97618de8d7fSPeter Avalos snprintf(prompt, sizeof(prompt), 97718de8d7fSPeter Avalos "Retype %.30s@%.128s's new password: ", 978856ea928SPeter Avalos authctxt->server_user, host); 97918de8d7fSPeter Avalos retype = read_passphrase(prompt, 0); 98018de8d7fSPeter Avalos if (strcmp(password, retype) != 0) { 98136e94dc5SPeter Avalos explicit_bzero(password, strlen(password)); 98236e94dc5SPeter Avalos free(password); 98318de8d7fSPeter Avalos logit("Mismatch; try again, EOF to quit."); 98418de8d7fSPeter Avalos password = NULL; 98518de8d7fSPeter Avalos } 98636e94dc5SPeter Avalos explicit_bzero(retype, strlen(retype)); 98736e94dc5SPeter Avalos free(retype); 98818de8d7fSPeter Avalos } 98918de8d7fSPeter Avalos packet_put_cstring(password); 99036e94dc5SPeter Avalos explicit_bzero(password, strlen(password)); 99136e94dc5SPeter Avalos free(password); 99218de8d7fSPeter Avalos packet_add_padding(64); 99318de8d7fSPeter Avalos packet_send(); 99418de8d7fSPeter Avalos 99518de8d7fSPeter Avalos dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 99618de8d7fSPeter Avalos &input_userauth_passwd_changereq); 997e9778795SPeter Avalos return 0; 998e9778795SPeter Avalos } 999e9778795SPeter Avalos 1000e9778795SPeter Avalos static const char * 1001*ce74bacaSMatthew Dillon key_sign_encode(const struct sshkey *key) 1002e9778795SPeter Avalos { 1003e9778795SPeter Avalos struct ssh *ssh = active_state; 1004e9778795SPeter Avalos 1005*ce74bacaSMatthew Dillon if (key->type == KEY_RSA) { 1006e9778795SPeter Avalos switch (ssh->kex->rsa_sha2) { 1007e9778795SPeter Avalos case 256: 1008e9778795SPeter Avalos return "rsa-sha2-256"; 1009e9778795SPeter Avalos case 512: 1010e9778795SPeter Avalos return "rsa-sha2-512"; 1011e9778795SPeter Avalos } 1012e9778795SPeter Avalos } 1013*ce74bacaSMatthew Dillon return key_ssh_name(key); 101418de8d7fSPeter Avalos } 101518de8d7fSPeter Avalos 101618de8d7fSPeter Avalos static int 1017e9778795SPeter Avalos identity_sign(struct identity *id, u_char **sigp, size_t *lenp, 1018e9778795SPeter Avalos const u_char *data, size_t datalen, u_int compat) 101918de8d7fSPeter Avalos { 1020*ce74bacaSMatthew Dillon struct sshkey *prv; 102118de8d7fSPeter Avalos int ret; 102218de8d7fSPeter Avalos 102318de8d7fSPeter Avalos /* the agent supports this key */ 1024*ce74bacaSMatthew Dillon if (id->key != NULL && id->agent_fd != -1) 1025e9778795SPeter Avalos return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, 1026*ce74bacaSMatthew Dillon data, datalen, key_sign_encode(id->key), compat); 1027e9778795SPeter Avalos 102818de8d7fSPeter Avalos /* 102918de8d7fSPeter Avalos * we have already loaded the private key or 103018de8d7fSPeter Avalos * the private key is stored in external hardware 103118de8d7fSPeter Avalos */ 1032*ce74bacaSMatthew Dillon if (id->key != NULL && 1033*ce74bacaSMatthew Dillon (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) 1034*ce74bacaSMatthew Dillon return (sshkey_sign(id->key, sigp, lenp, data, datalen, 1035*ce74bacaSMatthew Dillon key_sign_encode(id->key), compat)); 1036*ce74bacaSMatthew Dillon 103718de8d7fSPeter Avalos /* load the private key from the file */ 1038e9778795SPeter Avalos if ((prv = load_identity_file(id)) == NULL) 1039e9778795SPeter Avalos return SSH_ERR_KEY_NOT_FOUND; 1040*ce74bacaSMatthew Dillon if (id->key != NULL && !sshkey_equal_public(prv, id->key)) { 1041*ce74bacaSMatthew Dillon error("%s: private key %s contents do not match public", 1042*ce74bacaSMatthew Dillon __func__, id->filename); 1043*ce74bacaSMatthew Dillon return SSH_ERR_KEY_NOT_FOUND; 1044*ce74bacaSMatthew Dillon } 1045*ce74bacaSMatthew Dillon ret = sshkey_sign(prv, sigp, lenp, data, datalen, 1046*ce74bacaSMatthew Dillon key_sign_encode(prv), compat); 1047e9778795SPeter Avalos sshkey_free(prv); 104818de8d7fSPeter Avalos return (ret); 104918de8d7fSPeter Avalos } 105018de8d7fSPeter Avalos 105118de8d7fSPeter Avalos static int 1052*ce74bacaSMatthew Dillon id_filename_matches(Identity *id, Identity *private_id) 1053*ce74bacaSMatthew Dillon { 1054*ce74bacaSMatthew Dillon const char *suffixes[] = { ".pub", "-cert.pub", NULL }; 1055*ce74bacaSMatthew Dillon size_t len = strlen(id->filename), plen = strlen(private_id->filename); 1056*ce74bacaSMatthew Dillon size_t i, slen; 1057*ce74bacaSMatthew Dillon 1058*ce74bacaSMatthew Dillon if (strcmp(id->filename, private_id->filename) == 0) 1059*ce74bacaSMatthew Dillon return 1; 1060*ce74bacaSMatthew Dillon for (i = 0; suffixes[i]; i++) { 1061*ce74bacaSMatthew Dillon slen = strlen(suffixes[i]); 1062*ce74bacaSMatthew Dillon if (len > slen && plen == len - slen && 1063*ce74bacaSMatthew Dillon strcmp(id->filename + (len - slen), suffixes[i]) == 0 && 1064*ce74bacaSMatthew Dillon memcmp(id->filename, private_id->filename, plen) == 0) 1065*ce74bacaSMatthew Dillon return 1; 1066*ce74bacaSMatthew Dillon } 1067*ce74bacaSMatthew Dillon return 0; 1068*ce74bacaSMatthew Dillon } 1069*ce74bacaSMatthew Dillon 1070*ce74bacaSMatthew Dillon static int 107118de8d7fSPeter Avalos sign_and_send_pubkey(Authctxt *authctxt, Identity *id) 107218de8d7fSPeter Avalos { 107318de8d7fSPeter Avalos Buffer b; 1074e9778795SPeter Avalos Identity *private_id; 107518de8d7fSPeter Avalos u_char *blob, *signature; 1076e9778795SPeter Avalos size_t slen; 1077e9778795SPeter Avalos u_int bloblen, skip = 0; 1078e9778795SPeter Avalos int matched, ret = -1, have_sig = 1; 1079856ea928SPeter Avalos char *fp; 108018de8d7fSPeter Avalos 1081e9778795SPeter Avalos if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, 1082e9778795SPeter Avalos SSH_FP_DEFAULT)) == NULL) 1083e9778795SPeter Avalos return 0; 1084e9778795SPeter Avalos debug3("%s: %s %s", __func__, key_type(id->key), fp); 108536e94dc5SPeter Avalos free(fp); 108618de8d7fSPeter Avalos 108718de8d7fSPeter Avalos if (key_to_blob(id->key, &blob, &bloblen) == 0) { 108818de8d7fSPeter Avalos /* we cannot handle this key */ 108918de8d7fSPeter Avalos debug3("sign_and_send_pubkey: cannot handle key"); 109018de8d7fSPeter Avalos return 0; 109118de8d7fSPeter Avalos } 109218de8d7fSPeter Avalos /* data to be signed */ 109318de8d7fSPeter Avalos buffer_init(&b); 109418de8d7fSPeter Avalos if (datafellows & SSH_OLD_SESSIONID) { 109518de8d7fSPeter Avalos buffer_append(&b, session_id2, session_id2_len); 109618de8d7fSPeter Avalos skip = session_id2_len; 109718de8d7fSPeter Avalos } else { 109818de8d7fSPeter Avalos buffer_put_string(&b, session_id2, session_id2_len); 109918de8d7fSPeter Avalos skip = buffer_len(&b); 110018de8d7fSPeter Avalos } 110118de8d7fSPeter Avalos buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 110218de8d7fSPeter Avalos buffer_put_cstring(&b, authctxt->server_user); 110318de8d7fSPeter Avalos buffer_put_cstring(&b, 110418de8d7fSPeter Avalos datafellows & SSH_BUG_PKSERVICE ? 110518de8d7fSPeter Avalos "ssh-userauth" : 110618de8d7fSPeter Avalos authctxt->service); 110718de8d7fSPeter Avalos if (datafellows & SSH_BUG_PKAUTH) { 110818de8d7fSPeter Avalos buffer_put_char(&b, have_sig); 110918de8d7fSPeter Avalos } else { 111018de8d7fSPeter Avalos buffer_put_cstring(&b, authctxt->method->name); 111118de8d7fSPeter Avalos buffer_put_char(&b, have_sig); 1112*ce74bacaSMatthew Dillon buffer_put_cstring(&b, key_sign_encode(id->key)); 111318de8d7fSPeter Avalos } 111418de8d7fSPeter Avalos buffer_put_string(&b, blob, bloblen); 111518de8d7fSPeter Avalos 1116e9778795SPeter Avalos /* 1117e9778795SPeter Avalos * If the key is an certificate, try to find a matching private key 1118e9778795SPeter Avalos * and use it to complete the signature. 1119e9778795SPeter Avalos * If no such private key exists, fall back to trying the certificate 1120e9778795SPeter Avalos * key itself in case it has a private half already loaded. 1121e9778795SPeter Avalos */ 1122e9778795SPeter Avalos if (key_is_cert(id->key)) { 1123e9778795SPeter Avalos matched = 0; 1124e9778795SPeter Avalos TAILQ_FOREACH(private_id, &authctxt->keys, next) { 1125e9778795SPeter Avalos if (sshkey_equal_public(id->key, private_id->key) && 1126e9778795SPeter Avalos id->key->type != private_id->key->type) { 1127e9778795SPeter Avalos id = private_id; 1128e9778795SPeter Avalos matched = 1; 1129e9778795SPeter Avalos break; 1130e9778795SPeter Avalos } 1131e9778795SPeter Avalos } 1132*ce74bacaSMatthew Dillon /* 1133*ce74bacaSMatthew Dillon * Exact key matches are preferred, but also allow 1134*ce74bacaSMatthew Dillon * filename matches for non-PKCS#11/agent keys that 1135*ce74bacaSMatthew Dillon * didn't load public keys. This supports the case 1136*ce74bacaSMatthew Dillon * of keeping just a private key file and public 1137*ce74bacaSMatthew Dillon * certificate on disk. 1138*ce74bacaSMatthew Dillon */ 1139*ce74bacaSMatthew Dillon if (!matched && !id->isprivate && id->agent_fd == -1 && 1140*ce74bacaSMatthew Dillon (id->key->flags & SSHKEY_FLAG_EXT) == 0) { 1141*ce74bacaSMatthew Dillon TAILQ_FOREACH(private_id, &authctxt->keys, next) { 1142*ce74bacaSMatthew Dillon if (private_id->key == NULL && 1143*ce74bacaSMatthew Dillon id_filename_matches(id, private_id)) { 1144*ce74bacaSMatthew Dillon id = private_id; 1145*ce74bacaSMatthew Dillon matched = 1; 1146*ce74bacaSMatthew Dillon break; 1147*ce74bacaSMatthew Dillon } 1148*ce74bacaSMatthew Dillon } 1149*ce74bacaSMatthew Dillon } 1150e9778795SPeter Avalos if (matched) { 1151e9778795SPeter Avalos debug2("%s: using private key \"%s\"%s for " 1152e9778795SPeter Avalos "certificate", __func__, id->filename, 1153e9778795SPeter Avalos id->agent_fd != -1 ? " from agent" : ""); 1154e9778795SPeter Avalos } else { 1155e9778795SPeter Avalos debug("%s: no separate private key for certificate " 1156e9778795SPeter Avalos "\"%s\"", __func__, id->filename); 1157e9778795SPeter Avalos } 1158e9778795SPeter Avalos } 1159e9778795SPeter Avalos 116018de8d7fSPeter Avalos /* generate signature */ 116118de8d7fSPeter Avalos ret = identity_sign(id, &signature, &slen, 1162e9778795SPeter Avalos buffer_ptr(&b), buffer_len(&b), datafellows); 1163e9778795SPeter Avalos if (ret != 0) { 1164e9778795SPeter Avalos if (ret != SSH_ERR_KEY_NOT_FOUND) 1165e9778795SPeter Avalos error("%s: signing failed: %s", __func__, ssh_err(ret)); 116636e94dc5SPeter Avalos free(blob); 116718de8d7fSPeter Avalos buffer_free(&b); 116818de8d7fSPeter Avalos return 0; 116918de8d7fSPeter Avalos } 117018de8d7fSPeter Avalos #ifdef DEBUG_PK 117118de8d7fSPeter Avalos buffer_dump(&b); 117218de8d7fSPeter Avalos #endif 117318de8d7fSPeter Avalos if (datafellows & SSH_BUG_PKSERVICE) { 117418de8d7fSPeter Avalos buffer_clear(&b); 117518de8d7fSPeter Avalos buffer_append(&b, session_id2, session_id2_len); 117618de8d7fSPeter Avalos skip = session_id2_len; 117718de8d7fSPeter Avalos buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 117818de8d7fSPeter Avalos buffer_put_cstring(&b, authctxt->server_user); 117918de8d7fSPeter Avalos buffer_put_cstring(&b, authctxt->service); 118018de8d7fSPeter Avalos buffer_put_cstring(&b, authctxt->method->name); 118118de8d7fSPeter Avalos buffer_put_char(&b, have_sig); 118218de8d7fSPeter Avalos if (!(datafellows & SSH_BUG_PKAUTH)) 118318de8d7fSPeter Avalos buffer_put_cstring(&b, key_ssh_name(id->key)); 118418de8d7fSPeter Avalos buffer_put_string(&b, blob, bloblen); 118518de8d7fSPeter Avalos } 118636e94dc5SPeter Avalos free(blob); 118718de8d7fSPeter Avalos 118818de8d7fSPeter Avalos /* append signature */ 118918de8d7fSPeter Avalos buffer_put_string(&b, signature, slen); 119036e94dc5SPeter Avalos free(signature); 119118de8d7fSPeter Avalos 119218de8d7fSPeter Avalos /* skip session id and packet type */ 119318de8d7fSPeter Avalos if (buffer_len(&b) < skip + 1) 119418de8d7fSPeter Avalos fatal("userauth_pubkey: internal error"); 119518de8d7fSPeter Avalos buffer_consume(&b, skip + 1); 119618de8d7fSPeter Avalos 119718de8d7fSPeter Avalos /* put remaining data from buffer into packet */ 119818de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_REQUEST); 119918de8d7fSPeter Avalos packet_put_raw(buffer_ptr(&b), buffer_len(&b)); 120018de8d7fSPeter Avalos buffer_free(&b); 120118de8d7fSPeter Avalos packet_send(); 120218de8d7fSPeter Avalos 120318de8d7fSPeter Avalos return 1; 120418de8d7fSPeter Avalos } 120518de8d7fSPeter Avalos 120618de8d7fSPeter Avalos static int 120718de8d7fSPeter Avalos send_pubkey_test(Authctxt *authctxt, Identity *id) 120818de8d7fSPeter Avalos { 120918de8d7fSPeter Avalos u_char *blob; 121018de8d7fSPeter Avalos u_int bloblen, have_sig = 0; 121118de8d7fSPeter Avalos 121218de8d7fSPeter Avalos debug3("send_pubkey_test"); 121318de8d7fSPeter Avalos 121418de8d7fSPeter Avalos if (key_to_blob(id->key, &blob, &bloblen) == 0) { 121518de8d7fSPeter Avalos /* we cannot handle this key */ 121618de8d7fSPeter Avalos debug3("send_pubkey_test: cannot handle key"); 121718de8d7fSPeter Avalos return 0; 121818de8d7fSPeter Avalos } 121918de8d7fSPeter Avalos /* register callback for USERAUTH_PK_OK message */ 122018de8d7fSPeter Avalos dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); 122118de8d7fSPeter Avalos 122218de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_REQUEST); 122318de8d7fSPeter Avalos packet_put_cstring(authctxt->server_user); 122418de8d7fSPeter Avalos packet_put_cstring(authctxt->service); 122518de8d7fSPeter Avalos packet_put_cstring(authctxt->method->name); 122618de8d7fSPeter Avalos packet_put_char(have_sig); 122718de8d7fSPeter Avalos if (!(datafellows & SSH_BUG_PKAUTH)) 1228*ce74bacaSMatthew Dillon packet_put_cstring(key_sign_encode(id->key)); 122918de8d7fSPeter Avalos packet_put_string(blob, bloblen); 123036e94dc5SPeter Avalos free(blob); 123118de8d7fSPeter Avalos packet_send(); 123218de8d7fSPeter Avalos return 1; 123318de8d7fSPeter Avalos } 123418de8d7fSPeter Avalos 1235*ce74bacaSMatthew Dillon static struct sshkey * 1236e9778795SPeter Avalos load_identity_file(Identity *id) 123718de8d7fSPeter Avalos { 1238*ce74bacaSMatthew Dillon struct sshkey *private = NULL; 1239e9778795SPeter Avalos char prompt[300], *passphrase, *comment; 1240e9778795SPeter Avalos int r, perm_ok = 0, quit = 0, i; 124118de8d7fSPeter Avalos struct stat st; 124218de8d7fSPeter Avalos 1243e9778795SPeter Avalos if (stat(id->filename, &st) < 0) { 1244e9778795SPeter Avalos (id->userprovided ? logit : debug3)("no such identity: %s: %s", 1245e9778795SPeter Avalos id->filename, strerror(errno)); 124618de8d7fSPeter Avalos return NULL; 124718de8d7fSPeter Avalos } 124818de8d7fSPeter Avalos snprintf(prompt, sizeof prompt, 1249e9778795SPeter Avalos "Enter passphrase for key '%.100s': ", id->filename); 1250e9778795SPeter Avalos for (i = 0; i <= options.number_of_password_prompts; i++) { 1251e9778795SPeter Avalos if (i == 0) 1252e9778795SPeter Avalos passphrase = ""; 1253e9778795SPeter Avalos else { 125418de8d7fSPeter Avalos passphrase = read_passphrase(prompt, 0); 1255e9778795SPeter Avalos if (*passphrase == '\0') { 125618de8d7fSPeter Avalos debug2("no passphrase given, try next key"); 1257e9778795SPeter Avalos free(passphrase); 1258e9778795SPeter Avalos break; 125918de8d7fSPeter Avalos } 1260e9778795SPeter Avalos } 1261e9778795SPeter Avalos switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename, 1262e9778795SPeter Avalos passphrase, &private, &comment, &perm_ok))) { 1263e9778795SPeter Avalos case 0: 1264e9778795SPeter Avalos break; 1265e9778795SPeter Avalos case SSH_ERR_KEY_WRONG_PASSPHRASE: 1266e9778795SPeter Avalos if (options.batch_mode) { 1267e9778795SPeter Avalos quit = 1; 1268e9778795SPeter Avalos break; 1269e9778795SPeter Avalos } 1270e9778795SPeter Avalos if (i != 0) 1271e9778795SPeter Avalos debug2("bad passphrase given, try again..."); 1272e9778795SPeter Avalos break; 1273e9778795SPeter Avalos case SSH_ERR_SYSTEM_ERROR: 1274e9778795SPeter Avalos if (errno == ENOENT) { 1275e9778795SPeter Avalos debug2("Load key \"%s\": %s", 1276e9778795SPeter Avalos id->filename, ssh_err(r)); 1277e9778795SPeter Avalos quit = 1; 1278e9778795SPeter Avalos break; 1279e9778795SPeter Avalos } 1280e9778795SPeter Avalos /* FALLTHROUGH */ 1281e9778795SPeter Avalos default: 1282e9778795SPeter Avalos error("Load key \"%s\": %s", id->filename, ssh_err(r)); 1283e9778795SPeter Avalos quit = 1; 1284e9778795SPeter Avalos break; 1285e9778795SPeter Avalos } 1286e9778795SPeter Avalos if (!quit && private != NULL && id->agent_fd == -1 && 1287e9778795SPeter Avalos !(id->key && id->isprivate)) 1288e9778795SPeter Avalos maybe_add_key_to_agent(id->filename, private, comment, 1289e9778795SPeter Avalos passphrase); 1290e9778795SPeter Avalos if (i > 0) { 129136e94dc5SPeter Avalos explicit_bzero(passphrase, strlen(passphrase)); 129236e94dc5SPeter Avalos free(passphrase); 1293e9778795SPeter Avalos } 1294e9778795SPeter Avalos free(comment); 129518de8d7fSPeter Avalos if (private != NULL || quit) 129618de8d7fSPeter Avalos break; 129718de8d7fSPeter Avalos } 129818de8d7fSPeter Avalos return private; 129918de8d7fSPeter Avalos } 130018de8d7fSPeter Avalos 130118de8d7fSPeter Avalos /* 130218de8d7fSPeter Avalos * try keys in the following order: 1303e9778795SPeter Avalos * 1. certificates listed in the config file 1304e9778795SPeter Avalos * 2. other input certificates 1305e9778795SPeter Avalos * 3. agent keys that are found in the config file 1306e9778795SPeter Avalos * 4. other agent keys 1307e9778795SPeter Avalos * 5. keys that are only listed in the config file 130818de8d7fSPeter Avalos */ 130918de8d7fSPeter Avalos static void 131018de8d7fSPeter Avalos pubkey_prepare(Authctxt *authctxt) 131118de8d7fSPeter Avalos { 1312e9778795SPeter Avalos struct identity *id, *id2, *tmp; 1313e9778795SPeter Avalos struct idlist agent, files, *preferred; 1314e9778795SPeter Avalos struct sshkey *key; 1315e9778795SPeter Avalos int agent_fd = -1, i, r, found; 1316e9778795SPeter Avalos size_t j; 1317e9778795SPeter Avalos struct ssh_identitylist *idlist; 131818de8d7fSPeter Avalos 131918de8d7fSPeter Avalos TAILQ_INIT(&agent); /* keys from the agent */ 132018de8d7fSPeter Avalos TAILQ_INIT(&files); /* keys from the config file */ 132118de8d7fSPeter Avalos preferred = &authctxt->keys; 132218de8d7fSPeter Avalos TAILQ_INIT(preferred); /* preferred order of keys */ 132318de8d7fSPeter Avalos 132436e94dc5SPeter Avalos /* list of keys stored in the filesystem and PKCS#11 */ 132518de8d7fSPeter Avalos for (i = 0; i < options.num_identity_files; i++) { 132618de8d7fSPeter Avalos key = options.identity_keys[i]; 1327856ea928SPeter Avalos if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER) 1328856ea928SPeter Avalos continue; 132918de8d7fSPeter Avalos options.identity_keys[i] = NULL; 133018de8d7fSPeter Avalos id = xcalloc(1, sizeof(*id)); 1331e9778795SPeter Avalos id->agent_fd = -1; 133218de8d7fSPeter Avalos id->key = key; 133318de8d7fSPeter Avalos id->filename = xstrdup(options.identity_files[i]); 133436e94dc5SPeter Avalos id->userprovided = options.identity_file_userprovided[i]; 133518de8d7fSPeter Avalos TAILQ_INSERT_TAIL(&files, id, next); 133618de8d7fSPeter Avalos } 1337e9778795SPeter Avalos /* list of certificates specified by user */ 1338e9778795SPeter Avalos for (i = 0; i < options.num_certificate_files; i++) { 1339e9778795SPeter Avalos key = options.certificates[i]; 1340e9778795SPeter Avalos if (!key_is_cert(key) || key->cert == NULL || 1341e9778795SPeter Avalos key->cert->type != SSH2_CERT_TYPE_USER) 1342e9778795SPeter Avalos continue; 1343e9778795SPeter Avalos id = xcalloc(1, sizeof(*id)); 1344e9778795SPeter Avalos id->agent_fd = -1; 1345e9778795SPeter Avalos id->key = key; 1346e9778795SPeter Avalos id->filename = xstrdup(options.certificate_files[i]); 1347e9778795SPeter Avalos id->userprovided = options.certificate_file_userprovided[i]; 1348e9778795SPeter Avalos TAILQ_INSERT_TAIL(preferred, id, next); 1349e9778795SPeter Avalos } 1350e9778795SPeter Avalos /* list of keys supported by the agent */ 1351e9778795SPeter Avalos if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { 1352e9778795SPeter Avalos if (r != SSH_ERR_AGENT_NOT_PRESENT) 1353e9778795SPeter Avalos debug("%s: ssh_get_authentication_socket: %s", 1354e9778795SPeter Avalos __func__, ssh_err(r)); 1355*ce74bacaSMatthew Dillon } else if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { 1356e9778795SPeter Avalos if (r != SSH_ERR_AGENT_NO_IDENTITIES) 1357e9778795SPeter Avalos debug("%s: ssh_fetch_identitylist: %s", 1358e9778795SPeter Avalos __func__, ssh_err(r)); 1359e9778795SPeter Avalos close(agent_fd); 1360e9778795SPeter Avalos } else { 1361e9778795SPeter Avalos for (j = 0; j < idlist->nkeys; j++) { 1362e9778795SPeter Avalos found = 0; 1363e9778795SPeter Avalos TAILQ_FOREACH(id, &files, next) { 1364e9778795SPeter Avalos /* 1365e9778795SPeter Avalos * agent keys from the config file are 1366e9778795SPeter Avalos * preferred 1367e9778795SPeter Avalos */ 1368e9778795SPeter Avalos if (sshkey_equal(idlist->keys[j], id->key)) { 1369e9778795SPeter Avalos TAILQ_REMOVE(&files, id, next); 1370e9778795SPeter Avalos TAILQ_INSERT_TAIL(preferred, id, next); 1371e9778795SPeter Avalos id->agent_fd = agent_fd; 1372e9778795SPeter Avalos found = 1; 1373e9778795SPeter Avalos break; 1374e9778795SPeter Avalos } 1375e9778795SPeter Avalos } 1376e9778795SPeter Avalos if (!found && !options.identities_only) { 1377e9778795SPeter Avalos id = xcalloc(1, sizeof(*id)); 1378e9778795SPeter Avalos /* XXX "steals" key/comment from idlist */ 1379e9778795SPeter Avalos id->key = idlist->keys[j]; 1380e9778795SPeter Avalos id->filename = idlist->comments[j]; 1381e9778795SPeter Avalos idlist->keys[j] = NULL; 1382e9778795SPeter Avalos idlist->comments[j] = NULL; 1383e9778795SPeter Avalos id->agent_fd = agent_fd; 1384e9778795SPeter Avalos TAILQ_INSERT_TAIL(&agent, id, next); 1385e9778795SPeter Avalos } 1386e9778795SPeter Avalos } 1387e9778795SPeter Avalos ssh_free_identitylist(idlist); 1388e9778795SPeter Avalos /* append remaining agent keys */ 1389e9778795SPeter Avalos for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { 1390e9778795SPeter Avalos TAILQ_REMOVE(&agent, id, next); 1391e9778795SPeter Avalos TAILQ_INSERT_TAIL(preferred, id, next); 1392e9778795SPeter Avalos } 1393e9778795SPeter Avalos authctxt->agent_fd = agent_fd; 1394e9778795SPeter Avalos } 139536e94dc5SPeter Avalos /* Prefer PKCS11 keys that are explicitly listed */ 139636e94dc5SPeter Avalos TAILQ_FOREACH_SAFE(id, &files, next, tmp) { 139736e94dc5SPeter Avalos if (id->key == NULL || (id->key->flags & SSHKEY_FLAG_EXT) == 0) 139836e94dc5SPeter Avalos continue; 139936e94dc5SPeter Avalos found = 0; 140036e94dc5SPeter Avalos TAILQ_FOREACH(id2, &files, next) { 140136e94dc5SPeter Avalos if (id2->key == NULL || 140236e94dc5SPeter Avalos (id2->key->flags & SSHKEY_FLAG_EXT) == 0) 140336e94dc5SPeter Avalos continue; 1404e9778795SPeter Avalos if (sshkey_equal(id->key, id2->key)) { 140536e94dc5SPeter Avalos TAILQ_REMOVE(&files, id, next); 140636e94dc5SPeter Avalos TAILQ_INSERT_TAIL(preferred, id, next); 140736e94dc5SPeter Avalos found = 1; 140836e94dc5SPeter Avalos break; 140936e94dc5SPeter Avalos } 141036e94dc5SPeter Avalos } 141136e94dc5SPeter Avalos /* If IdentitiesOnly set and key not found then don't use it */ 141236e94dc5SPeter Avalos if (!found && options.identities_only) { 141336e94dc5SPeter Avalos TAILQ_REMOVE(&files, id, next); 141436e94dc5SPeter Avalos explicit_bzero(id, sizeof(*id)); 141536e94dc5SPeter Avalos free(id); 141636e94dc5SPeter Avalos } 141736e94dc5SPeter Avalos } 141818de8d7fSPeter Avalos /* append remaining keys from the config file */ 141918de8d7fSPeter Avalos for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { 142018de8d7fSPeter Avalos TAILQ_REMOVE(&files, id, next); 142118de8d7fSPeter Avalos TAILQ_INSERT_TAIL(preferred, id, next); 142218de8d7fSPeter Avalos } 1423e9778795SPeter Avalos /* finally, filter by PubkeyAcceptedKeyTypes */ 1424e9778795SPeter Avalos TAILQ_FOREACH_SAFE(id, preferred, next, id2) { 1425e9778795SPeter Avalos if (id->key != NULL && 1426e9778795SPeter Avalos match_pattern_list(sshkey_ssh_name(id->key), 1427e9778795SPeter Avalos options.pubkey_key_types, 0) != 1) { 1428e9778795SPeter Avalos debug("Skipping %s key %s - " 1429e9778795SPeter Avalos "not in PubkeyAcceptedKeyTypes", 1430e9778795SPeter Avalos sshkey_ssh_name(id->key), id->filename); 1431e9778795SPeter Avalos TAILQ_REMOVE(preferred, id, next); 1432e9778795SPeter Avalos sshkey_free(id->key); 1433e9778795SPeter Avalos free(id->filename); 1434e9778795SPeter Avalos memset(id, 0, sizeof(*id)); 1435e9778795SPeter Avalos continue; 1436e9778795SPeter Avalos } 1437e9778795SPeter Avalos debug2("key: %s (%p)%s%s", id->filename, id->key, 1438e9778795SPeter Avalos id->userprovided ? ", explicit" : "", 1439e9778795SPeter Avalos id->agent_fd != -1 ? ", agent" : ""); 144018de8d7fSPeter Avalos } 144118de8d7fSPeter Avalos } 144218de8d7fSPeter Avalos 144318de8d7fSPeter Avalos static void 144418de8d7fSPeter Avalos pubkey_cleanup(Authctxt *authctxt) 144518de8d7fSPeter Avalos { 144618de8d7fSPeter Avalos Identity *id; 144718de8d7fSPeter Avalos 1448e9778795SPeter Avalos if (authctxt->agent_fd != -1) 1449e9778795SPeter Avalos ssh_close_authentication_socket(authctxt->agent_fd); 145018de8d7fSPeter Avalos for (id = TAILQ_FIRST(&authctxt->keys); id; 145118de8d7fSPeter Avalos id = TAILQ_FIRST(&authctxt->keys)) { 145218de8d7fSPeter Avalos TAILQ_REMOVE(&authctxt->keys, id, next); 1453e9778795SPeter Avalos sshkey_free(id->key); 145436e94dc5SPeter Avalos free(id->filename); 145536e94dc5SPeter Avalos free(id); 145618de8d7fSPeter Avalos } 145718de8d7fSPeter Avalos } 145818de8d7fSPeter Avalos 1459*ce74bacaSMatthew Dillon static void 1460*ce74bacaSMatthew Dillon pubkey_reset(Authctxt *authctxt) 1461*ce74bacaSMatthew Dillon { 1462*ce74bacaSMatthew Dillon Identity *id; 1463*ce74bacaSMatthew Dillon 1464*ce74bacaSMatthew Dillon TAILQ_FOREACH(id, &authctxt->keys, next) 1465*ce74bacaSMatthew Dillon id->tried = 0; 1466*ce74bacaSMatthew Dillon } 1467*ce74bacaSMatthew Dillon 1468e9778795SPeter Avalos static int 1469e9778795SPeter Avalos try_identity(Identity *id) 1470e9778795SPeter Avalos { 1471e9778795SPeter Avalos if (!id->key) 1472e9778795SPeter Avalos return (0); 1473e9778795SPeter Avalos if (key_type_plain(id->key->type) == KEY_RSA && 1474e9778795SPeter Avalos (datafellows & SSH_BUG_RSASIGMD5) != 0) { 1475e9778795SPeter Avalos debug("Skipped %s key %s for RSA/MD5 server", 1476e9778795SPeter Avalos key_type(id->key), id->filename); 1477e9778795SPeter Avalos return (0); 1478e9778795SPeter Avalos } 1479*ce74bacaSMatthew Dillon return 1; 1480e9778795SPeter Avalos } 1481e9778795SPeter Avalos 148218de8d7fSPeter Avalos int 148318de8d7fSPeter Avalos userauth_pubkey(Authctxt *authctxt) 148418de8d7fSPeter Avalos { 148518de8d7fSPeter Avalos Identity *id; 148618de8d7fSPeter Avalos int sent = 0; 1487*ce74bacaSMatthew Dillon char *fp; 148818de8d7fSPeter Avalos 148918de8d7fSPeter Avalos while ((id = TAILQ_FIRST(&authctxt->keys))) { 149018de8d7fSPeter Avalos if (id->tried++) 149118de8d7fSPeter Avalos return (0); 149218de8d7fSPeter Avalos /* move key to the end of the queue */ 149318de8d7fSPeter Avalos TAILQ_REMOVE(&authctxt->keys, id, next); 149418de8d7fSPeter Avalos TAILQ_INSERT_TAIL(&authctxt->keys, id, next); 149518de8d7fSPeter Avalos /* 149618de8d7fSPeter Avalos * send a test message if we have the public key. for 149718de8d7fSPeter Avalos * encrypted keys we cannot do this and have to load the 149818de8d7fSPeter Avalos * private key instead 149918de8d7fSPeter Avalos */ 150036e94dc5SPeter Avalos if (id->key != NULL) { 1501e9778795SPeter Avalos if (try_identity(id)) { 1502*ce74bacaSMatthew Dillon if ((fp = sshkey_fingerprint(id->key, 1503*ce74bacaSMatthew Dillon options.fingerprint_hash, 1504*ce74bacaSMatthew Dillon SSH_FP_DEFAULT)) == NULL) { 1505*ce74bacaSMatthew Dillon error("%s: sshkey_fingerprint failed", 1506*ce74bacaSMatthew Dillon __func__); 1507*ce74bacaSMatthew Dillon return 0; 1508*ce74bacaSMatthew Dillon } 1509*ce74bacaSMatthew Dillon debug("Offering public key: %s %s %s", 1510*ce74bacaSMatthew Dillon sshkey_type(id->key), fp, id->filename); 1511*ce74bacaSMatthew Dillon free(fp); 151218de8d7fSPeter Avalos sent = send_pubkey_test(authctxt, id); 151336e94dc5SPeter Avalos } 151436e94dc5SPeter Avalos } else { 151518de8d7fSPeter Avalos debug("Trying private key: %s", id->filename); 1516e9778795SPeter Avalos id->key = load_identity_file(id); 151718de8d7fSPeter Avalos if (id->key != NULL) { 1518e9778795SPeter Avalos if (try_identity(id)) { 151918de8d7fSPeter Avalos id->isprivate = 1; 152036e94dc5SPeter Avalos sent = sign_and_send_pubkey( 152136e94dc5SPeter Avalos authctxt, id); 152236e94dc5SPeter Avalos } 152318de8d7fSPeter Avalos key_free(id->key); 152418de8d7fSPeter Avalos id->key = NULL; 1525*ce74bacaSMatthew Dillon id->isprivate = 0; 152618de8d7fSPeter Avalos } 152718de8d7fSPeter Avalos } 152818de8d7fSPeter Avalos if (sent) 152918de8d7fSPeter Avalos return (sent); 153018de8d7fSPeter Avalos } 153118de8d7fSPeter Avalos return (0); 153218de8d7fSPeter Avalos } 153318de8d7fSPeter Avalos 153418de8d7fSPeter Avalos /* 153518de8d7fSPeter Avalos * Send userauth request message specifying keyboard-interactive method. 153618de8d7fSPeter Avalos */ 153718de8d7fSPeter Avalos int 153818de8d7fSPeter Avalos userauth_kbdint(Authctxt *authctxt) 153918de8d7fSPeter Avalos { 154018de8d7fSPeter Avalos static int attempt = 0; 154118de8d7fSPeter Avalos 154218de8d7fSPeter Avalos if (attempt++ >= options.number_of_password_prompts) 154318de8d7fSPeter Avalos return 0; 154418de8d7fSPeter Avalos /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */ 154518de8d7fSPeter Avalos if (attempt > 1 && !authctxt->info_req_seen) { 154618de8d7fSPeter Avalos debug3("userauth_kbdint: disable: no info_req_seen"); 154718de8d7fSPeter Avalos dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL); 154818de8d7fSPeter Avalos return 0; 154918de8d7fSPeter Avalos } 155018de8d7fSPeter Avalos 155118de8d7fSPeter Avalos debug2("userauth_kbdint"); 155218de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_REQUEST); 155318de8d7fSPeter Avalos packet_put_cstring(authctxt->server_user); 155418de8d7fSPeter Avalos packet_put_cstring(authctxt->service); 155518de8d7fSPeter Avalos packet_put_cstring(authctxt->method->name); 155618de8d7fSPeter Avalos packet_put_cstring(""); /* lang */ 155718de8d7fSPeter Avalos packet_put_cstring(options.kbd_interactive_devices ? 155818de8d7fSPeter Avalos options.kbd_interactive_devices : ""); 155918de8d7fSPeter Avalos packet_send(); 156018de8d7fSPeter Avalos 156118de8d7fSPeter Avalos dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); 156218de8d7fSPeter Avalos return 1; 156318de8d7fSPeter Avalos } 156418de8d7fSPeter Avalos 156518de8d7fSPeter Avalos /* 156618de8d7fSPeter Avalos * parse INFO_REQUEST, prompt user and send INFO_RESPONSE 156718de8d7fSPeter Avalos */ 1568e9778795SPeter Avalos int 1569*ce74bacaSMatthew Dillon input_userauth_info_req(int type, u_int32_t seq, struct ssh *ssh) 157018de8d7fSPeter Avalos { 1571*ce74bacaSMatthew Dillon Authctxt *authctxt = ssh->authctxt; 157218de8d7fSPeter Avalos char *name, *inst, *lang, *prompt, *response; 157318de8d7fSPeter Avalos u_int num_prompts, i; 157418de8d7fSPeter Avalos int echo = 0; 157518de8d7fSPeter Avalos 157618de8d7fSPeter Avalos debug2("input_userauth_info_req"); 157718de8d7fSPeter Avalos 157818de8d7fSPeter Avalos if (authctxt == NULL) 157918de8d7fSPeter Avalos fatal("input_userauth_info_req: no authentication context"); 158018de8d7fSPeter Avalos 158118de8d7fSPeter Avalos authctxt->info_req_seen = 1; 158218de8d7fSPeter Avalos 158318de8d7fSPeter Avalos name = packet_get_string(NULL); 158418de8d7fSPeter Avalos inst = packet_get_string(NULL); 158518de8d7fSPeter Avalos lang = packet_get_string(NULL); 158618de8d7fSPeter Avalos if (strlen(name) > 0) 158718de8d7fSPeter Avalos logit("%s", name); 158818de8d7fSPeter Avalos if (strlen(inst) > 0) 158918de8d7fSPeter Avalos logit("%s", inst); 159036e94dc5SPeter Avalos free(name); 159136e94dc5SPeter Avalos free(inst); 159236e94dc5SPeter Avalos free(lang); 159318de8d7fSPeter Avalos 159418de8d7fSPeter Avalos num_prompts = packet_get_int(); 159518de8d7fSPeter Avalos /* 159618de8d7fSPeter Avalos * Begin to build info response packet based on prompts requested. 159718de8d7fSPeter Avalos * We commit to providing the correct number of responses, so if 159818de8d7fSPeter Avalos * further on we run into a problem that prevents this, we have to 159918de8d7fSPeter Avalos * be sure and clean this up and send a correct error response. 160018de8d7fSPeter Avalos */ 160118de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE); 160218de8d7fSPeter Avalos packet_put_int(num_prompts); 160318de8d7fSPeter Avalos 160418de8d7fSPeter Avalos debug2("input_userauth_info_req: num_prompts %d", num_prompts); 160518de8d7fSPeter Avalos for (i = 0; i < num_prompts; i++) { 160618de8d7fSPeter Avalos prompt = packet_get_string(NULL); 160718de8d7fSPeter Avalos echo = packet_get_char(); 160818de8d7fSPeter Avalos 160918de8d7fSPeter Avalos response = read_passphrase(prompt, echo ? RP_ECHO : 0); 161018de8d7fSPeter Avalos 161118de8d7fSPeter Avalos packet_put_cstring(response); 161236e94dc5SPeter Avalos explicit_bzero(response, strlen(response)); 161336e94dc5SPeter Avalos free(response); 161436e94dc5SPeter Avalos free(prompt); 161518de8d7fSPeter Avalos } 161618de8d7fSPeter Avalos packet_check_eom(); /* done with parsing incoming message. */ 161718de8d7fSPeter Avalos 161818de8d7fSPeter Avalos packet_add_padding(64); 161918de8d7fSPeter Avalos packet_send(); 1620e9778795SPeter Avalos return 0; 162118de8d7fSPeter Avalos } 162218de8d7fSPeter Avalos 162318de8d7fSPeter Avalos static int 1624e9778795SPeter Avalos ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, 1625e9778795SPeter Avalos const u_char *data, size_t datalen) 162618de8d7fSPeter Avalos { 1627e9778795SPeter Avalos struct sshbuf *b; 162818de8d7fSPeter Avalos struct stat st; 162918de8d7fSPeter Avalos pid_t pid; 1630e9778795SPeter Avalos int i, r, to[2], from[2], status, sock = packet_get_connection_in(); 1631e9778795SPeter Avalos u_char rversion = 0, version = 2; 1632e9778795SPeter Avalos void (*osigchld)(int); 163318de8d7fSPeter Avalos 1634e9778795SPeter Avalos *sigp = NULL; 1635e9778795SPeter Avalos *lenp = 0; 163618de8d7fSPeter Avalos 163718de8d7fSPeter Avalos if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { 1638e9778795SPeter Avalos error("%s: not installed: %s", __func__, strerror(errno)); 163918de8d7fSPeter Avalos return -1; 164018de8d7fSPeter Avalos } 1641e9778795SPeter Avalos if (fflush(stdout) != 0) { 1642e9778795SPeter Avalos error("%s: fflush: %s", __func__, strerror(errno)); 1643e9778795SPeter Avalos return -1; 1644e9778795SPeter Avalos } 164518de8d7fSPeter Avalos if (pipe(to) < 0) { 1646e9778795SPeter Avalos error("%s: pipe: %s", __func__, strerror(errno)); 164718de8d7fSPeter Avalos return -1; 164818de8d7fSPeter Avalos } 164918de8d7fSPeter Avalos if (pipe(from) < 0) { 1650e9778795SPeter Avalos error("%s: pipe: %s", __func__, strerror(errno)); 165118de8d7fSPeter Avalos return -1; 165218de8d7fSPeter Avalos } 165318de8d7fSPeter Avalos if ((pid = fork()) < 0) { 1654e9778795SPeter Avalos error("%s: fork: %s", __func__, strerror(errno)); 165518de8d7fSPeter Avalos return -1; 165618de8d7fSPeter Avalos } 1657e9778795SPeter Avalos osigchld = signal(SIGCHLD, SIG_DFL); 165818de8d7fSPeter Avalos if (pid == 0) { 1659856ea928SPeter Avalos /* keep the socket on exec */ 1660e9778795SPeter Avalos fcntl(sock, F_SETFD, 0); 166118de8d7fSPeter Avalos permanently_drop_suid(getuid()); 166218de8d7fSPeter Avalos close(from[0]); 166318de8d7fSPeter Avalos if (dup2(from[1], STDOUT_FILENO) < 0) 1664e9778795SPeter Avalos fatal("%s: dup2: %s", __func__, strerror(errno)); 166518de8d7fSPeter Avalos close(to[1]); 166618de8d7fSPeter Avalos if (dup2(to[0], STDIN_FILENO) < 0) 1667e9778795SPeter Avalos fatal("%s: dup2: %s", __func__, strerror(errno)); 166818de8d7fSPeter Avalos close(from[1]); 166918de8d7fSPeter Avalos close(to[0]); 1670e9778795SPeter Avalos /* Close everything but stdio and the socket */ 1671e9778795SPeter Avalos for (i = STDERR_FILENO + 1; i < sock; i++) 1672e9778795SPeter Avalos close(i); 1673e9778795SPeter Avalos closefrom(sock + 1); 1674e9778795SPeter Avalos debug3("%s: [child] pid=%ld, exec %s", 1675e9778795SPeter Avalos __func__, (long)getpid(), _PATH_SSH_KEY_SIGN); 1676e9778795SPeter Avalos execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *)NULL); 1677e9778795SPeter Avalos fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN, 167818de8d7fSPeter Avalos strerror(errno)); 167918de8d7fSPeter Avalos } 168018de8d7fSPeter Avalos close(from[1]); 168118de8d7fSPeter Avalos close(to[0]); 168218de8d7fSPeter Avalos 1683e9778795SPeter Avalos if ((b = sshbuf_new()) == NULL) 1684e9778795SPeter Avalos fatal("%s: sshbuf_new failed", __func__); 1685e9778795SPeter Avalos /* send # of sock, data to be signed */ 1686*ce74bacaSMatthew Dillon if ((r = sshbuf_put_u32(b, sock)) != 0 || 1687e9778795SPeter Avalos (r = sshbuf_put_string(b, data, datalen)) != 0) 1688e9778795SPeter Avalos fatal("%s: buffer error: %s", __func__, ssh_err(r)); 1689e9778795SPeter Avalos if (ssh_msg_send(to[1], version, b) == -1) 1690e9778795SPeter Avalos fatal("%s: couldn't send request", __func__); 1691e9778795SPeter Avalos sshbuf_reset(b); 1692e9778795SPeter Avalos r = ssh_msg_recv(from[0], b); 169318de8d7fSPeter Avalos close(from[0]); 169418de8d7fSPeter Avalos close(to[1]); 1695e9778795SPeter Avalos if (r < 0) { 1696e9778795SPeter Avalos error("%s: no reply", __func__); 1697e9778795SPeter Avalos goto fail; 1698e9778795SPeter Avalos } 169918de8d7fSPeter Avalos 1700e9778795SPeter Avalos errno = 0; 1701e9778795SPeter Avalos while (waitpid(pid, &status, 0) < 0) { 1702e9778795SPeter Avalos if (errno != EINTR) { 1703e9778795SPeter Avalos error("%s: waitpid %ld: %s", 1704e9778795SPeter Avalos __func__, (long)pid, strerror(errno)); 1705e9778795SPeter Avalos goto fail; 1706e9778795SPeter Avalos } 1707e9778795SPeter Avalos } 1708e9778795SPeter Avalos if (!WIFEXITED(status)) { 1709e9778795SPeter Avalos error("%s: exited abnormally", __func__); 1710e9778795SPeter Avalos goto fail; 1711e9778795SPeter Avalos } 1712e9778795SPeter Avalos if (WEXITSTATUS(status) != 0) { 1713e9778795SPeter Avalos error("%s: exited with status %d", 1714e9778795SPeter Avalos __func__, WEXITSTATUS(status)); 1715e9778795SPeter Avalos goto fail; 1716e9778795SPeter Avalos } 1717e9778795SPeter Avalos if ((r = sshbuf_get_u8(b, &rversion)) != 0) { 1718e9778795SPeter Avalos error("%s: buffer error: %s", __func__, ssh_err(r)); 1719e9778795SPeter Avalos goto fail; 1720e9778795SPeter Avalos } 1721e9778795SPeter Avalos if (rversion != version) { 1722e9778795SPeter Avalos error("%s: bad version", __func__); 1723e9778795SPeter Avalos goto fail; 1724e9778795SPeter Avalos } 1725e9778795SPeter Avalos if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) { 1726e9778795SPeter Avalos error("%s: buffer error: %s", __func__, ssh_err(r)); 1727e9778795SPeter Avalos fail: 1728e9778795SPeter Avalos signal(SIGCHLD, osigchld); 1729e9778795SPeter Avalos sshbuf_free(b); 173018de8d7fSPeter Avalos return -1; 173118de8d7fSPeter Avalos } 1732e9778795SPeter Avalos signal(SIGCHLD, osigchld); 1733e9778795SPeter Avalos sshbuf_free(b); 173418de8d7fSPeter Avalos 173518de8d7fSPeter Avalos return 0; 173618de8d7fSPeter Avalos } 173718de8d7fSPeter Avalos 173818de8d7fSPeter Avalos int 173918de8d7fSPeter Avalos userauth_hostbased(Authctxt *authctxt) 174018de8d7fSPeter Avalos { 1741e9778795SPeter Avalos struct ssh *ssh = active_state; 1742e9778795SPeter Avalos struct sshkey *private = NULL; 1743e9778795SPeter Avalos struct sshbuf *b = NULL; 174418de8d7fSPeter Avalos const char *service; 1745e9778795SPeter Avalos u_char *sig = NULL, *keyblob = NULL; 1746e9778795SPeter Avalos char *fp = NULL, *chost = NULL, *lname = NULL; 1747e9778795SPeter Avalos size_t siglen = 0, keylen = 0; 1748e9778795SPeter Avalos int i, r, success = 0; 1749e9778795SPeter Avalos 1750e9778795SPeter Avalos if (authctxt->ktypes == NULL) { 1751e9778795SPeter Avalos authctxt->oktypes = xstrdup(options.hostbased_key_types); 1752e9778795SPeter Avalos authctxt->ktypes = authctxt->oktypes; 1753e9778795SPeter Avalos } 1754e9778795SPeter Avalos 1755e9778795SPeter Avalos /* 1756e9778795SPeter Avalos * Work through each listed type pattern in HostbasedKeyTypes, 1757e9778795SPeter Avalos * trying each hostkey that matches the type in turn. 1758e9778795SPeter Avalos */ 1759e9778795SPeter Avalos for (;;) { 1760e9778795SPeter Avalos if (authctxt->active_ktype == NULL) 1761e9778795SPeter Avalos authctxt->active_ktype = strsep(&authctxt->ktypes, ","); 1762e9778795SPeter Avalos if (authctxt->active_ktype == NULL || 1763e9778795SPeter Avalos *authctxt->active_ktype == '\0') 1764e9778795SPeter Avalos break; 1765e9778795SPeter Avalos debug3("%s: trying key type %s", __func__, 1766e9778795SPeter Avalos authctxt->active_ktype); 176718de8d7fSPeter Avalos 176818de8d7fSPeter Avalos /* check for a useful key */ 1769e9778795SPeter Avalos private = NULL; 1770e9778795SPeter Avalos for (i = 0; i < authctxt->sensitive->nkeys; i++) { 1771e9778795SPeter Avalos if (authctxt->sensitive->keys[i] == NULL || 1772e9778795SPeter Avalos authctxt->sensitive->keys[i]->type == KEY_UNSPEC) 1773e9778795SPeter Avalos continue; 1774e9778795SPeter Avalos if (match_pattern_list( 1775e9778795SPeter Avalos sshkey_ssh_name(authctxt->sensitive->keys[i]), 1776e9778795SPeter Avalos authctxt->active_ktype, 0) != 1) 1777e9778795SPeter Avalos continue; 177818de8d7fSPeter Avalos /* we take and free the key */ 1779e9778795SPeter Avalos private = authctxt->sensitive->keys[i]; 1780e9778795SPeter Avalos authctxt->sensitive->keys[i] = NULL; 178118de8d7fSPeter Avalos break; 178218de8d7fSPeter Avalos } 1783e9778795SPeter Avalos /* Found one */ 1784e9778795SPeter Avalos if (private != NULL) 1785e9778795SPeter Avalos break; 1786e9778795SPeter Avalos /* No more keys of this type; advance */ 1787e9778795SPeter Avalos authctxt->active_ktype = NULL; 178818de8d7fSPeter Avalos } 1789e9778795SPeter Avalos if (private == NULL) { 1790e9778795SPeter Avalos free(authctxt->oktypes); 1791e9778795SPeter Avalos authctxt->oktypes = authctxt->ktypes = NULL; 1792e9778795SPeter Avalos authctxt->active_ktype = NULL; 179318de8d7fSPeter Avalos debug("No more client hostkeys for hostbased authentication."); 1794e9778795SPeter Avalos goto out; 179518de8d7fSPeter Avalos } 1796e9778795SPeter Avalos 1797e9778795SPeter Avalos if ((fp = sshkey_fingerprint(private, options.fingerprint_hash, 1798e9778795SPeter Avalos SSH_FP_DEFAULT)) == NULL) { 1799e9778795SPeter Avalos error("%s: sshkey_fingerprint failed", __func__); 1800e9778795SPeter Avalos goto out; 180118de8d7fSPeter Avalos } 1802e9778795SPeter Avalos debug("%s: trying hostkey %s %s", 1803e9778795SPeter Avalos __func__, sshkey_ssh_name(private), fp); 1804e9778795SPeter Avalos 180518de8d7fSPeter Avalos /* figure out a name for the client host */ 1806e9778795SPeter Avalos if ((lname = get_local_name(packet_get_connection_in())) == NULL) { 1807e9778795SPeter Avalos error("%s: cannot get local ipaddr/name", __func__); 1808e9778795SPeter Avalos goto out; 180918de8d7fSPeter Avalos } 1810e9778795SPeter Avalos 1811e9778795SPeter Avalos /* XXX sshbuf_put_stringf? */ 1812e9778795SPeter Avalos xasprintf(&chost, "%s.", lname); 1813e9778795SPeter Avalos debug2("%s: chost %s", __func__, chost); 181418de8d7fSPeter Avalos 181518de8d7fSPeter Avalos service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : 181618de8d7fSPeter Avalos authctxt->service; 181718de8d7fSPeter Avalos 1818e9778795SPeter Avalos /* construct data */ 1819e9778795SPeter Avalos if ((b = sshbuf_new()) == NULL) { 1820e9778795SPeter Avalos error("%s: sshbuf_new failed", __func__); 1821e9778795SPeter Avalos goto out; 1822e9778795SPeter Avalos } 1823e9778795SPeter Avalos if ((r = sshkey_to_blob(private, &keyblob, &keylen)) != 0) { 1824e9778795SPeter Avalos error("%s: sshkey_to_blob: %s", __func__, ssh_err(r)); 1825e9778795SPeter Avalos goto out; 1826e9778795SPeter Avalos } 1827e9778795SPeter Avalos if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || 1828e9778795SPeter Avalos (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1829e9778795SPeter Avalos (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || 1830e9778795SPeter Avalos (r = sshbuf_put_cstring(b, service)) != 0 || 1831e9778795SPeter Avalos (r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 || 1832e9778795SPeter Avalos (r = sshbuf_put_cstring(b, key_ssh_name(private))) != 0 || 1833e9778795SPeter Avalos (r = sshbuf_put_string(b, keyblob, keylen)) != 0 || 1834e9778795SPeter Avalos (r = sshbuf_put_cstring(b, chost)) != 0 || 1835e9778795SPeter Avalos (r = sshbuf_put_cstring(b, authctxt->local_user)) != 0) { 1836e9778795SPeter Avalos error("%s: buffer error: %s", __func__, ssh_err(r)); 1837e9778795SPeter Avalos goto out; 1838e9778795SPeter Avalos } 1839e9778795SPeter Avalos 1840e9778795SPeter Avalos #ifdef DEBUG_PK 1841e9778795SPeter Avalos sshbuf_dump(b, stderr); 1842e9778795SPeter Avalos #endif 1843e9778795SPeter Avalos if (authctxt->sensitive->external_keysign) 1844e9778795SPeter Avalos r = ssh_keysign(private, &sig, &siglen, 1845e9778795SPeter Avalos sshbuf_ptr(b), sshbuf_len(b)); 1846e9778795SPeter Avalos else if ((r = sshkey_sign(private, &sig, &siglen, 1847e9778795SPeter Avalos sshbuf_ptr(b), sshbuf_len(b), NULL, datafellows)) != 0) 1848e9778795SPeter Avalos debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); 1849e9778795SPeter Avalos if (r != 0) { 1850e9778795SPeter Avalos error("sign using hostkey %s %s failed", 1851e9778795SPeter Avalos sshkey_ssh_name(private), fp); 1852e9778795SPeter Avalos goto out; 1853e9778795SPeter Avalos } 1854e9778795SPeter Avalos if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 1855e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || 1856e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || 1857e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || 1858e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, key_ssh_name(private))) != 0 || 1859e9778795SPeter Avalos (r = sshpkt_put_string(ssh, keyblob, keylen)) != 0 || 1860e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, chost)) != 0 || 1861e9778795SPeter Avalos (r = sshpkt_put_cstring(ssh, authctxt->local_user)) != 0 || 1862e9778795SPeter Avalos (r = sshpkt_put_string(ssh, sig, siglen)) != 0 || 1863e9778795SPeter Avalos (r = sshpkt_send(ssh)) != 0) { 1864e9778795SPeter Avalos error("%s: packet error: %s", __func__, ssh_err(r)); 1865e9778795SPeter Avalos goto out; 1866e9778795SPeter Avalos } 1867e9778795SPeter Avalos success = 1; 1868e9778795SPeter Avalos 1869e9778795SPeter Avalos out: 1870e9778795SPeter Avalos if (sig != NULL) { 1871e9778795SPeter Avalos explicit_bzero(sig, siglen); 1872e9778795SPeter Avalos free(sig); 1873e9778795SPeter Avalos } 1874e9778795SPeter Avalos free(keyblob); 1875e9778795SPeter Avalos free(lname); 1876e9778795SPeter Avalos free(fp); 1877e9778795SPeter Avalos free(chost); 1878e9778795SPeter Avalos sshkey_free(private); 1879e9778795SPeter Avalos sshbuf_free(b); 1880e9778795SPeter Avalos 1881e9778795SPeter Avalos return success; 188218de8d7fSPeter Avalos } 188318de8d7fSPeter Avalos 188418de8d7fSPeter Avalos /* find auth method */ 188518de8d7fSPeter Avalos 188618de8d7fSPeter Avalos /* 188718de8d7fSPeter Avalos * given auth method name, if configurable options permit this method fill 188818de8d7fSPeter Avalos * in auth_ident field and return true, otherwise return false. 188918de8d7fSPeter Avalos */ 189018de8d7fSPeter Avalos static int 189118de8d7fSPeter Avalos authmethod_is_enabled(Authmethod *method) 189218de8d7fSPeter Avalos { 189318de8d7fSPeter Avalos if (method == NULL) 189418de8d7fSPeter Avalos return 0; 189518de8d7fSPeter Avalos /* return false if options indicate this method is disabled */ 189618de8d7fSPeter Avalos if (method->enabled == NULL || *method->enabled == 0) 189718de8d7fSPeter Avalos return 0; 189818de8d7fSPeter Avalos /* return false if batch mode is enabled but method needs interactive mode */ 189918de8d7fSPeter Avalos if (method->batch_flag != NULL && *method->batch_flag != 0) 190018de8d7fSPeter Avalos return 0; 190118de8d7fSPeter Avalos return 1; 190218de8d7fSPeter Avalos } 190318de8d7fSPeter Avalos 190418de8d7fSPeter Avalos static Authmethod * 190518de8d7fSPeter Avalos authmethod_lookup(const char *name) 190618de8d7fSPeter Avalos { 190718de8d7fSPeter Avalos Authmethod *method = NULL; 190818de8d7fSPeter Avalos if (name != NULL) 190918de8d7fSPeter Avalos for (method = authmethods; method->name != NULL; method++) 191018de8d7fSPeter Avalos if (strcmp(name, method->name) == 0) 191118de8d7fSPeter Avalos return method; 191218de8d7fSPeter Avalos debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); 191318de8d7fSPeter Avalos return NULL; 191418de8d7fSPeter Avalos } 191518de8d7fSPeter Avalos 191618de8d7fSPeter Avalos /* XXX internal state */ 191718de8d7fSPeter Avalos static Authmethod *current = NULL; 191818de8d7fSPeter Avalos static char *supported = NULL; 191918de8d7fSPeter Avalos static char *preferred = NULL; 192018de8d7fSPeter Avalos 192118de8d7fSPeter Avalos /* 192218de8d7fSPeter Avalos * Given the authentication method list sent by the server, return the 192318de8d7fSPeter Avalos * next method we should try. If the server initially sends a nil list, 192418de8d7fSPeter Avalos * use a built-in default list. 192518de8d7fSPeter Avalos */ 192618de8d7fSPeter Avalos static Authmethod * 192718de8d7fSPeter Avalos authmethod_get(char *authlist) 192818de8d7fSPeter Avalos { 192918de8d7fSPeter Avalos char *name = NULL; 193018de8d7fSPeter Avalos u_int next; 193118de8d7fSPeter Avalos 193218de8d7fSPeter Avalos /* Use a suitable default if we're passed a nil list. */ 193318de8d7fSPeter Avalos if (authlist == NULL || strlen(authlist) == 0) 193418de8d7fSPeter Avalos authlist = options.preferred_authentications; 193518de8d7fSPeter Avalos 193618de8d7fSPeter Avalos if (supported == NULL || strcmp(authlist, supported) != 0) { 193718de8d7fSPeter Avalos debug3("start over, passed a different list %s", authlist); 193836e94dc5SPeter Avalos free(supported); 193918de8d7fSPeter Avalos supported = xstrdup(authlist); 194018de8d7fSPeter Avalos preferred = options.preferred_authentications; 194118de8d7fSPeter Avalos debug3("preferred %s", preferred); 194218de8d7fSPeter Avalos current = NULL; 194318de8d7fSPeter Avalos } else if (current != NULL && authmethod_is_enabled(current)) 194418de8d7fSPeter Avalos return current; 194518de8d7fSPeter Avalos 194618de8d7fSPeter Avalos for (;;) { 194718de8d7fSPeter Avalos if ((name = match_list(preferred, supported, &next)) == NULL) { 194818de8d7fSPeter Avalos debug("No more authentication methods to try."); 194918de8d7fSPeter Avalos current = NULL; 195018de8d7fSPeter Avalos return NULL; 195118de8d7fSPeter Avalos } 195218de8d7fSPeter Avalos preferred += next; 195318de8d7fSPeter Avalos debug3("authmethod_lookup %s", name); 195418de8d7fSPeter Avalos debug3("remaining preferred: %s", preferred); 195518de8d7fSPeter Avalos if ((current = authmethod_lookup(name)) != NULL && 195618de8d7fSPeter Avalos authmethod_is_enabled(current)) { 195718de8d7fSPeter Avalos debug3("authmethod_is_enabled %s", name); 195818de8d7fSPeter Avalos debug("Next authentication method: %s", name); 195936e94dc5SPeter Avalos free(name); 196018de8d7fSPeter Avalos return current; 196118de8d7fSPeter Avalos } 196236e94dc5SPeter Avalos free(name); 196318de8d7fSPeter Avalos } 196418de8d7fSPeter Avalos } 196518de8d7fSPeter Avalos 196618de8d7fSPeter Avalos static char * 196718de8d7fSPeter Avalos authmethods_get(void) 196818de8d7fSPeter Avalos { 196918de8d7fSPeter Avalos Authmethod *method = NULL; 197018de8d7fSPeter Avalos Buffer b; 197118de8d7fSPeter Avalos char *list; 197218de8d7fSPeter Avalos 197318de8d7fSPeter Avalos buffer_init(&b); 197418de8d7fSPeter Avalos for (method = authmethods; method->name != NULL; method++) { 197518de8d7fSPeter Avalos if (authmethod_is_enabled(method)) { 197618de8d7fSPeter Avalos if (buffer_len(&b) > 0) 197718de8d7fSPeter Avalos buffer_append(&b, ",", 1); 197818de8d7fSPeter Avalos buffer_append(&b, method->name, strlen(method->name)); 197918de8d7fSPeter Avalos } 198018de8d7fSPeter Avalos } 1981e9778795SPeter Avalos if ((list = sshbuf_dup_string(&b)) == NULL) 1982e9778795SPeter Avalos fatal("%s: sshbuf_dup_string failed", __func__); 198318de8d7fSPeter Avalos buffer_free(&b); 198418de8d7fSPeter Avalos return list; 198518de8d7fSPeter Avalos } 1986cb5eb4f1SPeter Avalos 1987