1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 2000 Markus Friedl. All rights reserved. 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 5*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 6*0Sstevel@tonic-gate * are met: 7*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 8*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 9*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 10*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 11*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16*0Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17*0Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19*0Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20*0Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21*0Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22*0Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23*0Sstevel@tonic-gate */ 24*0Sstevel@tonic-gate /* 25*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 26*0Sstevel@tonic-gate * Use is subject to license terms. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include "includes.h" 30*0Sstevel@tonic-gate RCSID("$OpenBSD: sshconnect2.c,v 1.107 2002/07/01 19:48:46 markus Exp $"); 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include "ssh.h" 35*0Sstevel@tonic-gate #include "ssh2.h" 36*0Sstevel@tonic-gate #include "xmalloc.h" 37*0Sstevel@tonic-gate #include "buffer.h" 38*0Sstevel@tonic-gate #include "packet.h" 39*0Sstevel@tonic-gate #include "compat.h" 40*0Sstevel@tonic-gate #include "bufaux.h" 41*0Sstevel@tonic-gate #include "cipher.h" 42*0Sstevel@tonic-gate #include "kex.h" 43*0Sstevel@tonic-gate #include "myproposal.h" 44*0Sstevel@tonic-gate #include "sshconnect.h" 45*0Sstevel@tonic-gate #include "authfile.h" 46*0Sstevel@tonic-gate #include "dh.h" 47*0Sstevel@tonic-gate #include "authfd.h" 48*0Sstevel@tonic-gate #include "log.h" 49*0Sstevel@tonic-gate #include "readconf.h" 50*0Sstevel@tonic-gate #include "readpass.h" 51*0Sstevel@tonic-gate #include "match.h" 52*0Sstevel@tonic-gate #include "dispatch.h" 53*0Sstevel@tonic-gate #include "canohost.h" 54*0Sstevel@tonic-gate #include "msg.h" 55*0Sstevel@tonic-gate #include "pathnames.h" 56*0Sstevel@tonic-gate #include "g11n.h" 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate #ifdef GSSAPI 59*0Sstevel@tonic-gate #include "ssh-gss.h" 60*0Sstevel@tonic-gate extern Gssctxt *xxx_gssctxt; 61*0Sstevel@tonic-gate #endif /* GSSAPI */ 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* import */ 64*0Sstevel@tonic-gate extern char *client_version_string; 65*0Sstevel@tonic-gate extern char *server_version_string; 66*0Sstevel@tonic-gate extern Options options; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * SSH2 key exchange 70*0Sstevel@tonic-gate */ 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate u_char *session_id2 = NULL; 73*0Sstevel@tonic-gate int session_id2_len = 0; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate char *xxx_host; 76*0Sstevel@tonic-gate struct sockaddr *xxx_hostaddr; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate Kex *xxx_kex = NULL; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate static int 81*0Sstevel@tonic-gate verify_host_key_callback(Key *hostkey) 82*0Sstevel@tonic-gate { 83*0Sstevel@tonic-gate if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) 84*0Sstevel@tonic-gate fatal("Host key verification failed."); 85*0Sstevel@tonic-gate return 0; 86*0Sstevel@tonic-gate } 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate static int 89*0Sstevel@tonic-gate accept_host_key_callback(Key *hostkey) 90*0Sstevel@tonic-gate { 91*0Sstevel@tonic-gate if (accept_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) 92*0Sstevel@tonic-gate log("GSS-API authenticated host key addition to " 93*0Sstevel@tonic-gate "known_hosts file failed"); 94*0Sstevel@tonic-gate return 0; 95*0Sstevel@tonic-gate } 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate void 98*0Sstevel@tonic-gate ssh_kex2(char *host, struct sockaddr *hostaddr) 99*0Sstevel@tonic-gate { 100*0Sstevel@tonic-gate Kex *kex; 101*0Sstevel@tonic-gate Kex_hook_func kex_hook = NULL; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate xxx_host = host; 104*0Sstevel@tonic-gate xxx_hostaddr = hostaddr; 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate #ifdef GSSAPI 107*0Sstevel@tonic-gate /* Add the GSSAPI mechanisms currently supported on this client to 108*0Sstevel@tonic-gate * the key exchange algorithm proposal */ 109*0Sstevel@tonic-gate if (options.gss_keyex) 110*0Sstevel@tonic-gate kex_hook = ssh_gssapi_client_kex_hook; 111*0Sstevel@tonic-gate #endif /* GSSAPI */ 112*0Sstevel@tonic-gate if (options.ciphers == (char *)-1) { 113*0Sstevel@tonic-gate log("No valid ciphers for protocol version 2 given, using defaults."); 114*0Sstevel@tonic-gate options.ciphers = NULL; 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate if (options.ciphers != NULL) { 117*0Sstevel@tonic-gate myproposal[PROPOSAL_ENC_ALGS_CTOS] = 118*0Sstevel@tonic-gate myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate myproposal[PROPOSAL_ENC_ALGS_CTOS] = 121*0Sstevel@tonic-gate compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); 122*0Sstevel@tonic-gate myproposal[PROPOSAL_ENC_ALGS_STOC] = 123*0Sstevel@tonic-gate compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); 124*0Sstevel@tonic-gate if (options.compression) { 125*0Sstevel@tonic-gate myproposal[PROPOSAL_COMP_ALGS_CTOS] = 126*0Sstevel@tonic-gate myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib,none"; 127*0Sstevel@tonic-gate } else { 128*0Sstevel@tonic-gate myproposal[PROPOSAL_COMP_ALGS_CTOS] = 129*0Sstevel@tonic-gate myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib"; 130*0Sstevel@tonic-gate } 131*0Sstevel@tonic-gate if (options.macs != NULL) { 132*0Sstevel@tonic-gate myproposal[PROPOSAL_MAC_ALGS_CTOS] = 133*0Sstevel@tonic-gate myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate if (options.hostkeyalgorithms != NULL) 136*0Sstevel@tonic-gate myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 137*0Sstevel@tonic-gate options.hostkeyalgorithms; 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate if (datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS) { 140*0Sstevel@tonic-gate char *locale = setlocale(LC_ALL, ""); 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate /* Solaris 9 SSHD expects a locale, not a langtag list */ 143*0Sstevel@tonic-gate myproposal[PROPOSAL_LANG_CTOS] = ""; 144*0Sstevel@tonic-gate if (locale != NULL && *locale != '\0' && 145*0Sstevel@tonic-gate strcmp(locale, "C") != 0) 146*0Sstevel@tonic-gate myproposal[PROPOSAL_LANG_CTOS] = locale; 147*0Sstevel@tonic-gate } else { 148*0Sstevel@tonic-gate myproposal[PROPOSAL_LANG_CTOS] = g11n_getlangs(); 149*0Sstevel@tonic-gate } 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate /* Same languages proposal for both directions */ 152*0Sstevel@tonic-gate if (myproposal[PROPOSAL_LANG_CTOS] == NULL) { 153*0Sstevel@tonic-gate myproposal[PROPOSAL_LANG_CTOS] = ""; 154*0Sstevel@tonic-gate myproposal[PROPOSAL_LANG_STOC] = ""; 155*0Sstevel@tonic-gate } else { 156*0Sstevel@tonic-gate myproposal[PROPOSAL_LANG_STOC] = 157*0Sstevel@tonic-gate myproposal[PROPOSAL_LANG_CTOS]; 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate /* start key exchange */ 161*0Sstevel@tonic-gate kex = kex_setup(host, myproposal, kex_hook); 162*0Sstevel@tonic-gate kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 163*0Sstevel@tonic-gate kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 164*0Sstevel@tonic-gate #ifdef GSSAPI 165*0Sstevel@tonic-gate kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; 166*0Sstevel@tonic-gate kex->options.gss_deleg_creds = options.gss_deleg_creds; 167*0Sstevel@tonic-gate #endif /* GSSAPI */ 168*0Sstevel@tonic-gate kex->client_version_string=client_version_string; 169*0Sstevel@tonic-gate kex->server_version_string=server_version_string; 170*0Sstevel@tonic-gate kex->verify_host_key=&verify_host_key_callback; 171*0Sstevel@tonic-gate kex->accept_host_key=&accept_host_key_callback; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate xxx_kex = kex; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate session_id2 = kex->session_id; 178*0Sstevel@tonic-gate session_id2_len = kex->session_id_len; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate #ifdef DEBUG_KEXDH 181*0Sstevel@tonic-gate /* send 1st encrypted/maced/compressed message */ 182*0Sstevel@tonic-gate packet_start(SSH2_MSG_IGNORE); 183*0Sstevel@tonic-gate packet_put_cstring("markus"); 184*0Sstevel@tonic-gate packet_send(); 185*0Sstevel@tonic-gate packet_write_wait(); 186*0Sstevel@tonic-gate #endif 187*0Sstevel@tonic-gate debug("done: ssh_kex2."); 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate /* 191*0Sstevel@tonic-gate * Authenticate user 192*0Sstevel@tonic-gate */ 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate typedef struct Authctxt Authctxt; 195*0Sstevel@tonic-gate typedef struct Authmethod Authmethod; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate typedef int sign_cb_fn( 198*0Sstevel@tonic-gate Authctxt *authctxt, Key *key, 199*0Sstevel@tonic-gate u_char **sigp, u_int *lenp, u_char *data, u_int datalen); 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate struct Authctxt { 202*0Sstevel@tonic-gate const char *server_user; 203*0Sstevel@tonic-gate const char *local_user; 204*0Sstevel@tonic-gate const char *host; 205*0Sstevel@tonic-gate const char *service; 206*0Sstevel@tonic-gate Authmethod *method; 207*0Sstevel@tonic-gate int success; 208*0Sstevel@tonic-gate char *authlist; 209*0Sstevel@tonic-gate /* pubkey */ 210*0Sstevel@tonic-gate Key *last_key; 211*0Sstevel@tonic-gate sign_cb_fn *last_key_sign; 212*0Sstevel@tonic-gate int last_key_hint; 213*0Sstevel@tonic-gate AuthenticationConnection *agent; 214*0Sstevel@tonic-gate /* hostbased */ 215*0Sstevel@tonic-gate Sensitive *sensitive; 216*0Sstevel@tonic-gate /* kbd-interactive */ 217*0Sstevel@tonic-gate int info_req_seen; 218*0Sstevel@tonic-gate /* generic */ 219*0Sstevel@tonic-gate void *methoddata; 220*0Sstevel@tonic-gate }; 221*0Sstevel@tonic-gate struct Authmethod { 222*0Sstevel@tonic-gate char *name; /* string to compare against server's list */ 223*0Sstevel@tonic-gate int (*userauth)(Authctxt *authctxt); 224*0Sstevel@tonic-gate void (*cleanup)(Authctxt *authctxt); 225*0Sstevel@tonic-gate int *enabled; /* flag in option struct that enables method */ 226*0Sstevel@tonic-gate int *batch_flag; /* flag in option struct that disables method */ 227*0Sstevel@tonic-gate }; 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate void input_userauth_success(int, u_int32_t, void *); 230*0Sstevel@tonic-gate void input_userauth_failure(int, u_int32_t, void *); 231*0Sstevel@tonic-gate void input_userauth_banner(int, u_int32_t, void *); 232*0Sstevel@tonic-gate void input_userauth_error(int, u_int32_t, void *); 233*0Sstevel@tonic-gate void input_userauth_info_req(int, u_int32_t, void *); 234*0Sstevel@tonic-gate void input_userauth_pk_ok(int, u_int32_t, void *); 235*0Sstevel@tonic-gate void input_userauth_passwd_changereq(int, u_int32_t, void *); 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate int userauth_none(Authctxt *); 238*0Sstevel@tonic-gate int userauth_pubkey(Authctxt *); 239*0Sstevel@tonic-gate int userauth_passwd(Authctxt *); 240*0Sstevel@tonic-gate int userauth_kbdint(Authctxt *); 241*0Sstevel@tonic-gate int userauth_hostbased(Authctxt *); 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate #ifdef GSSAPI 244*0Sstevel@tonic-gate static int userauth_gssapi_keyex(Authctxt *authctxt); 245*0Sstevel@tonic-gate static int userauth_gssapi(Authctxt *authctxt); 246*0Sstevel@tonic-gate static void userauth_gssapi_cleanup(Authctxt *authctxt); 247*0Sstevel@tonic-gate static void input_gssapi_response(int type, u_int32_t, void *); 248*0Sstevel@tonic-gate static void input_gssapi_token(int type, u_int32_t, void *); 249*0Sstevel@tonic-gate static void input_gssapi_hash(int type, u_int32_t, void *); 250*0Sstevel@tonic-gate static void input_gssapi_error(int, u_int32_t, void *); 251*0Sstevel@tonic-gate static void input_gssapi_errtok(int, u_int32_t, void *); 252*0Sstevel@tonic-gate #endif /* GSSAPI */ 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate void userauth(Authctxt *, char *); 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *); 257*0Sstevel@tonic-gate static void clear_auth_state(Authctxt *); 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate static Authmethod *authmethod_get(char *authlist); 260*0Sstevel@tonic-gate static Authmethod *authmethod_lookup(const char *name); 261*0Sstevel@tonic-gate static char *authmethods_get(void); 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate Authmethod authmethods[] = { 264*0Sstevel@tonic-gate #ifdef GSSAPI 265*0Sstevel@tonic-gate {"gssapi-keyex", 266*0Sstevel@tonic-gate userauth_gssapi_keyex, 267*0Sstevel@tonic-gate userauth_gssapi_cleanup, 268*0Sstevel@tonic-gate &options.gss_keyex, 269*0Sstevel@tonic-gate NULL}, 270*0Sstevel@tonic-gate {"gssapi-with-mic", 271*0Sstevel@tonic-gate userauth_gssapi, 272*0Sstevel@tonic-gate userauth_gssapi_cleanup, 273*0Sstevel@tonic-gate &options.gss_authentication, 274*0Sstevel@tonic-gate NULL}, 275*0Sstevel@tonic-gate #endif /* GSSAPI */ 276*0Sstevel@tonic-gate {"hostbased", 277*0Sstevel@tonic-gate userauth_hostbased, 278*0Sstevel@tonic-gate NULL, 279*0Sstevel@tonic-gate &options.hostbased_authentication, 280*0Sstevel@tonic-gate NULL}, 281*0Sstevel@tonic-gate {"publickey", 282*0Sstevel@tonic-gate userauth_pubkey, 283*0Sstevel@tonic-gate NULL, 284*0Sstevel@tonic-gate &options.pubkey_authentication, 285*0Sstevel@tonic-gate NULL}, 286*0Sstevel@tonic-gate {"keyboard-interactive", 287*0Sstevel@tonic-gate userauth_kbdint, 288*0Sstevel@tonic-gate NULL, 289*0Sstevel@tonic-gate &options.kbd_interactive_authentication, 290*0Sstevel@tonic-gate &options.batch_mode}, 291*0Sstevel@tonic-gate {"password", 292*0Sstevel@tonic-gate userauth_passwd, 293*0Sstevel@tonic-gate NULL, 294*0Sstevel@tonic-gate &options.password_authentication, 295*0Sstevel@tonic-gate &options.batch_mode}, 296*0Sstevel@tonic-gate {"none", 297*0Sstevel@tonic-gate userauth_none, 298*0Sstevel@tonic-gate NULL, 299*0Sstevel@tonic-gate NULL, 300*0Sstevel@tonic-gate NULL}, 301*0Sstevel@tonic-gate {NULL, NULL, NULL, NULL, NULL} 302*0Sstevel@tonic-gate }; 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate void 305*0Sstevel@tonic-gate ssh_userauth2(const char *local_user, const char *server_user, char *host, 306*0Sstevel@tonic-gate Sensitive *sensitive) 307*0Sstevel@tonic-gate { 308*0Sstevel@tonic-gate Authctxt authctxt; 309*0Sstevel@tonic-gate int type; 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate if (options.challenge_response_authentication) 312*0Sstevel@tonic-gate options.kbd_interactive_authentication = 1; 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate packet_start(SSH2_MSG_SERVICE_REQUEST); 315*0Sstevel@tonic-gate packet_put_cstring("ssh-userauth"); 316*0Sstevel@tonic-gate packet_send(); 317*0Sstevel@tonic-gate debug("send SSH2_MSG_SERVICE_REQUEST"); 318*0Sstevel@tonic-gate packet_write_wait(); 319*0Sstevel@tonic-gate type = packet_read(); 320*0Sstevel@tonic-gate if (type != SSH2_MSG_SERVICE_ACCEPT) 321*0Sstevel@tonic-gate fatal("Server denied authentication request: %d", type); 322*0Sstevel@tonic-gate if (packet_remaining() > 0) { 323*0Sstevel@tonic-gate char *reply = packet_get_string(NULL); 324*0Sstevel@tonic-gate debug2("service_accept: %s", reply); 325*0Sstevel@tonic-gate xfree(reply); 326*0Sstevel@tonic-gate } else { 327*0Sstevel@tonic-gate debug2("buggy server: service_accept w/o service"); 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate packet_check_eom(); 330*0Sstevel@tonic-gate debug("got SSH2_MSG_SERVICE_ACCEPT"); 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate if (options.preferred_authentications == NULL) 333*0Sstevel@tonic-gate options.preferred_authentications = authmethods_get(); 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate /* setup authentication context */ 336*0Sstevel@tonic-gate memset(&authctxt, 0, sizeof(authctxt)); 337*0Sstevel@tonic-gate authctxt.agent = ssh_get_authentication_connection(); 338*0Sstevel@tonic-gate authctxt.server_user = server_user; 339*0Sstevel@tonic-gate authctxt.local_user = local_user; 340*0Sstevel@tonic-gate authctxt.host = host; 341*0Sstevel@tonic-gate authctxt.service = "ssh-connection"; /* service name */ 342*0Sstevel@tonic-gate authctxt.success = 0; 343*0Sstevel@tonic-gate authctxt.method = authmethod_lookup("none"); 344*0Sstevel@tonic-gate authctxt.authlist = NULL; 345*0Sstevel@tonic-gate authctxt.methoddata = NULL; 346*0Sstevel@tonic-gate authctxt.sensitive = sensitive; 347*0Sstevel@tonic-gate authctxt.info_req_seen = 0; 348*0Sstevel@tonic-gate if (authctxt.method == NULL) 349*0Sstevel@tonic-gate fatal("ssh_userauth2: internal error: cannot send userauth none request"); 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate /* initial userauth request */ 352*0Sstevel@tonic-gate userauth_none(&authctxt); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate dispatch_init(&input_userauth_error); 355*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); 356*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); 357*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); 358*0Sstevel@tonic-gate dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate if (authctxt.agent != NULL) 361*0Sstevel@tonic-gate ssh_close_authentication_connection(authctxt.agent); 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate debug("Authentication succeeded (%s)", authctxt.method->name); 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate void 366*0Sstevel@tonic-gate userauth(Authctxt *authctxt, char *authlist) 367*0Sstevel@tonic-gate { 368*0Sstevel@tonic-gate if (authctxt->method != NULL && 369*0Sstevel@tonic-gate authctxt->method->cleanup != NULL) 370*0Sstevel@tonic-gate authctxt->method->cleanup(authctxt); 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate if (authlist == NULL) { 373*0Sstevel@tonic-gate authlist = authctxt->authlist; 374*0Sstevel@tonic-gate } else { 375*0Sstevel@tonic-gate if (authctxt->authlist) 376*0Sstevel@tonic-gate xfree(authctxt->authlist); 377*0Sstevel@tonic-gate authctxt->authlist = authlist; 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate for (;;) { 380*0Sstevel@tonic-gate Authmethod *method = authmethod_get(authlist); 381*0Sstevel@tonic-gate if (method == NULL) 382*0Sstevel@tonic-gate fatal("Permission denied (%s).", authlist); 383*0Sstevel@tonic-gate authctxt->method = method; 384*0Sstevel@tonic-gate if (method->userauth(authctxt) != 0) { 385*0Sstevel@tonic-gate debug2("we sent a %s packet, wait for reply", method->name); 386*0Sstevel@tonic-gate break; 387*0Sstevel@tonic-gate } else { 388*0Sstevel@tonic-gate debug2("we did not send a packet, disable method"); 389*0Sstevel@tonic-gate method->enabled = NULL; 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate void 395*0Sstevel@tonic-gate input_userauth_error(int type, u_int32_t seq, void *ctxt) 396*0Sstevel@tonic-gate { 397*0Sstevel@tonic-gate fatal("input_userauth_error: bad message during authentication: " 398*0Sstevel@tonic-gate "type %d", type); 399*0Sstevel@tonic-gate } 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate void 402*0Sstevel@tonic-gate input_userauth_banner(int type, u_int32_t seq, void *ctxt) 403*0Sstevel@tonic-gate { 404*0Sstevel@tonic-gate char *msg, *lang; 405*0Sstevel@tonic-gate debug3("input_userauth_banner"); 406*0Sstevel@tonic-gate msg = packet_get_string(NULL); 407*0Sstevel@tonic-gate lang = packet_get_string(NULL); 408*0Sstevel@tonic-gate fprintf(stderr, "%s", msg); 409*0Sstevel@tonic-gate xfree(msg); 410*0Sstevel@tonic-gate xfree(lang); 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate void 414*0Sstevel@tonic-gate input_userauth_success(int type, u_int32_t seq, void *ctxt) 415*0Sstevel@tonic-gate { 416*0Sstevel@tonic-gate Authctxt *authctxt = ctxt; 417*0Sstevel@tonic-gate if (authctxt == NULL) 418*0Sstevel@tonic-gate fatal("input_userauth_success: no authentication context"); 419*0Sstevel@tonic-gate if (authctxt->authlist) 420*0Sstevel@tonic-gate xfree(authctxt->authlist); 421*0Sstevel@tonic-gate if (authctxt->method != NULL && 422*0Sstevel@tonic-gate authctxt->method->cleanup != NULL) 423*0Sstevel@tonic-gate authctxt->method->cleanup(authctxt); 424*0Sstevel@tonic-gate clear_auth_state(authctxt); 425*0Sstevel@tonic-gate authctxt->success = 1; /* break out */ 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate void 429*0Sstevel@tonic-gate input_userauth_failure(int type, u_int32_t seq, void *ctxt) 430*0Sstevel@tonic-gate { 431*0Sstevel@tonic-gate Authctxt *authctxt = ctxt; 432*0Sstevel@tonic-gate char *authlist = NULL; 433*0Sstevel@tonic-gate int partial; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate if (authctxt == NULL) 436*0Sstevel@tonic-gate fatal("input_userauth_failure: no authentication context"); 437*0Sstevel@tonic-gate 438*0Sstevel@tonic-gate authlist = packet_get_string(NULL); 439*0Sstevel@tonic-gate partial = packet_get_char(); 440*0Sstevel@tonic-gate packet_check_eom(); 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate if (partial != 0) 443*0Sstevel@tonic-gate log("Authenticated with partial success."); 444*0Sstevel@tonic-gate debug("Authentications that can continue: %s", authlist); 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate clear_auth_state(authctxt); 447*0Sstevel@tonic-gate userauth(authctxt, authlist); 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate void 450*0Sstevel@tonic-gate input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) 451*0Sstevel@tonic-gate { 452*0Sstevel@tonic-gate Authctxt *authctxt = ctxt; 453*0Sstevel@tonic-gate Key *key = NULL; 454*0Sstevel@tonic-gate Buffer b; 455*0Sstevel@tonic-gate int pktype, sent = 0; 456*0Sstevel@tonic-gate u_int alen, blen; 457*0Sstevel@tonic-gate char *pkalg, *fp; 458*0Sstevel@tonic-gate u_char *pkblob; 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate if (authctxt == NULL) 461*0Sstevel@tonic-gate fatal("input_userauth_pk_ok: no authentication context"); 462*0Sstevel@tonic-gate if (datafellows & SSH_BUG_PKOK) { 463*0Sstevel@tonic-gate /* this is similar to SSH_BUG_PKAUTH */ 464*0Sstevel@tonic-gate debug2("input_userauth_pk_ok: SSH_BUG_PKOK"); 465*0Sstevel@tonic-gate pkblob = packet_get_string(&blen); 466*0Sstevel@tonic-gate buffer_init(&b); 467*0Sstevel@tonic-gate buffer_append(&b, pkblob, blen); 468*0Sstevel@tonic-gate pkalg = buffer_get_string(&b, &alen); 469*0Sstevel@tonic-gate buffer_free(&b); 470*0Sstevel@tonic-gate } else { 471*0Sstevel@tonic-gate pkalg = packet_get_string(&alen); 472*0Sstevel@tonic-gate pkblob = packet_get_string(&blen); 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate packet_check_eom(); 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate debug("Server accepts key: pkalg %s blen %u lastkey %p hint %d", 477*0Sstevel@tonic-gate pkalg, blen, authctxt->last_key, authctxt->last_key_hint); 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate do { 480*0Sstevel@tonic-gate if (authctxt->last_key == NULL || 481*0Sstevel@tonic-gate authctxt->last_key_sign == NULL) { 482*0Sstevel@tonic-gate debug("no last key or no sign cb"); 483*0Sstevel@tonic-gate break; 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { 486*0Sstevel@tonic-gate debug("unknown pkalg %s", pkalg); 487*0Sstevel@tonic-gate break; 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate if ((key = key_from_blob(pkblob, blen)) == NULL) { 490*0Sstevel@tonic-gate debug("no key from blob. pkalg %s", pkalg); 491*0Sstevel@tonic-gate break; 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate if (key->type != pktype) { 494*0Sstevel@tonic-gate error("input_userauth_pk_ok: type mismatch " 495*0Sstevel@tonic-gate "for decoded key (received %d, expected %d)", 496*0Sstevel@tonic-gate key->type, pktype); 497*0Sstevel@tonic-gate break; 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); 500*0Sstevel@tonic-gate debug2("input_userauth_pk_ok: fp %s", fp); 501*0Sstevel@tonic-gate xfree(fp); 502*0Sstevel@tonic-gate if (!key_equal(key, authctxt->last_key)) { 503*0Sstevel@tonic-gate debug("key != last_key"); 504*0Sstevel@tonic-gate break; 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate sent = sign_and_send_pubkey(authctxt, key, 507*0Sstevel@tonic-gate authctxt->last_key_sign); 508*0Sstevel@tonic-gate } while (0); 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate if (key != NULL) 511*0Sstevel@tonic-gate key_free(key); 512*0Sstevel@tonic-gate xfree(pkalg); 513*0Sstevel@tonic-gate xfree(pkblob); 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate /* unregister */ 516*0Sstevel@tonic-gate clear_auth_state(authctxt); 517*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL); 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* try another method if we did not send a packet */ 520*0Sstevel@tonic-gate if (sent == 0) 521*0Sstevel@tonic-gate userauth(authctxt, NULL); 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate #ifdef GSSAPI 526*0Sstevel@tonic-gate int 527*0Sstevel@tonic-gate userauth_gssapi(Authctxt *authctxt) 528*0Sstevel@tonic-gate { 529*0Sstevel@tonic-gate Gssctxt *gssctxt = NULL; 530*0Sstevel@tonic-gate static int initialized = 0; 531*0Sstevel@tonic-gate static int mech_idx = 0; 532*0Sstevel@tonic-gate static gss_OID_set supported = GSS_C_NULL_OID_SET; 533*0Sstevel@tonic-gate gss_OID mech = GSS_C_NULL_OID; 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /* Things work better if we send one mechanism at a time, rather 536*0Sstevel@tonic-gate * than them all at once. This means that if we fail at some point 537*0Sstevel@tonic-gate * in the middle of a negotiation, we can come back and try something 538*0Sstevel@tonic-gate * different. */ 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate if (datafellows & SSH_OLD_GSSAPI) return 0; 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate /* Before we offer a mechanism, check that we can support it. Don't 543*0Sstevel@tonic-gate * bother trying to get credentials - as the standard fallback will 544*0Sstevel@tonic-gate * deal with that kind of failure. 545*0Sstevel@tonic-gate */ 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate if (!initialized) { 548*0Sstevel@tonic-gate initialized = 1; 549*0Sstevel@tonic-gate ssh_gssapi_client_mechs(authctxt->host, &supported); 550*0Sstevel@tonic-gate if (supported == GSS_C_NULL_OID_SET || supported->count == 0) 551*0Sstevel@tonic-gate return (0); 552*0Sstevel@tonic-gate } else if (supported != GSS_C_NULL_OID_SET) { 553*0Sstevel@tonic-gate /* Try next mech, if any */ 554*0Sstevel@tonic-gate mech_idx++; 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate if (mech_idx >= supported->count) 557*0Sstevel@tonic-gate return (0); 558*0Sstevel@tonic-gate } else { 559*0Sstevel@tonic-gate return (0); 560*0Sstevel@tonic-gate } 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate mech = &supported->elements[mech_idx]; 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate ssh_gssapi_build_ctx(&gssctxt, 1, mech); 565*0Sstevel@tonic-gate authctxt->methoddata=(void *)gssctxt; 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_REQUEST); 568*0Sstevel@tonic-gate packet_put_cstring(authctxt->server_user); 569*0Sstevel@tonic-gate packet_put_cstring(authctxt->service); 570*0Sstevel@tonic-gate packet_put_cstring(authctxt->method->name); 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate packet_put_int(1); 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate /* The newest gsskeyex draft stipulates that OIDs should 575*0Sstevel@tonic-gate * be DER encoded, so we need to add the object type and 576*0Sstevel@tonic-gate * length information back on */ 577*0Sstevel@tonic-gate if (datafellows & SSH_BUG_GSSAPI_BER) { 578*0Sstevel@tonic-gate packet_put_string(mech->elements, mech->length); 579*0Sstevel@tonic-gate } else { 580*0Sstevel@tonic-gate packet_put_int((mech->length)+2); 581*0Sstevel@tonic-gate packet_put_char(0x06); 582*0Sstevel@tonic-gate packet_put_char(mech->length); 583*0Sstevel@tonic-gate packet_put_raw(mech->elements, mech->length); 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate packet_send(); 587*0Sstevel@tonic-gate packet_write_wait(); 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response); 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate return 1; 592*0Sstevel@tonic-gate } 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate void 595*0Sstevel@tonic-gate input_gssapi_response(int type, u_int32_t plen, void *ctxt) 596*0Sstevel@tonic-gate { 597*0Sstevel@tonic-gate Authctxt *authctxt = ctxt; 598*0Sstevel@tonic-gate Gssctxt *gssctxt; 599*0Sstevel@tonic-gate OM_uint32 status,ms; 600*0Sstevel@tonic-gate u_int oidlen; 601*0Sstevel@tonic-gate char *oidv; 602*0Sstevel@tonic-gate gss_buffer_desc send_tok; 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate if (authctxt == NULL) 605*0Sstevel@tonic-gate fatal("input_gssapi_response: no authentication context"); 606*0Sstevel@tonic-gate gssctxt = authctxt->methoddata; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate /* Setup our OID */ 609*0Sstevel@tonic-gate oidv=packet_get_string(&oidlen); 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate if (datafellows & SSH_BUG_GSSAPI_BER) { 612*0Sstevel@tonic-gate if (!ssh_gssapi_check_mech_oid(gssctxt,oidv,oidlen)) { 613*0Sstevel@tonic-gate gss_OID oid; 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate oid = ssh_gssapi_make_oid(oidlen, oidv); 616*0Sstevel@tonic-gate debug("Server returned different OID (%s) than expected (%s)", 617*0Sstevel@tonic-gate ssh_gssapi_oid_to_str(oid), 618*0Sstevel@tonic-gate ssh_gssapi_oid_to_str(gssctxt->desired_mech)); 619*0Sstevel@tonic-gate ssh_gssapi_release_oid(&oid); 620*0Sstevel@tonic-gate clear_auth_state(authctxt); 621*0Sstevel@tonic-gate userauth(authctxt,NULL); 622*0Sstevel@tonic-gate return; 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate } else { 625*0Sstevel@tonic-gate if(oidv[0]!=0x06 || oidv[1]!=oidlen-2) { 626*0Sstevel@tonic-gate debug("Badly encoded mechanism OID received"); 627*0Sstevel@tonic-gate clear_auth_state(authctxt); 628*0Sstevel@tonic-gate userauth(authctxt,NULL); 629*0Sstevel@tonic-gate return; 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate if (!ssh_gssapi_check_mech_oid(gssctxt,oidv+2,oidlen-2)) { 632*0Sstevel@tonic-gate gss_OID oid; 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate oid = ssh_gssapi_make_oid(oidlen-2, oidv+2); 635*0Sstevel@tonic-gate debug("Server returned different OID (%s) than expected (%s)", 636*0Sstevel@tonic-gate ssh_gssapi_oid_to_str(oid), 637*0Sstevel@tonic-gate ssh_gssapi_oid_to_str(gssctxt->desired_mech)); 638*0Sstevel@tonic-gate clear_auth_state(authctxt); 639*0Sstevel@tonic-gate userauth(authctxt,NULL); 640*0Sstevel@tonic-gate return; 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate packet_check_eom(); 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,&input_gssapi_token); 647*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,&input_gssapi_error); 648*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,&input_gssapi_errtok); 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate status = ssh_gssapi_init_ctx(gssctxt, authctxt->host, 651*0Sstevel@tonic-gate options.gss_deleg_creds, 652*0Sstevel@tonic-gate GSS_C_NO_BUFFER, &send_tok); 653*0Sstevel@tonic-gate if (GSS_ERROR(status)) { 654*0Sstevel@tonic-gate if (send_tok.length>0) { 655*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); 656*0Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); 657*0Sstevel@tonic-gate packet_send(); 658*0Sstevel@tonic-gate packet_write_wait(); 659*0Sstevel@tonic-gate } 660*0Sstevel@tonic-gate /* Start again with next method on list */ 661*0Sstevel@tonic-gate debug("Trying to start again"); 662*0Sstevel@tonic-gate clear_auth_state(authctxt); 663*0Sstevel@tonic-gate userauth(authctxt,NULL); 664*0Sstevel@tonic-gate return; 665*0Sstevel@tonic-gate } 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate /* We must have data to send */ 668*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); 669*0Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); 670*0Sstevel@tonic-gate packet_send(); 671*0Sstevel@tonic-gate packet_write_wait(); 672*0Sstevel@tonic-gate gss_release_buffer(&ms, &send_tok); 673*0Sstevel@tonic-gate } 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate void 676*0Sstevel@tonic-gate input_gssapi_token(int type, u_int32_t plen, void *ctxt) 677*0Sstevel@tonic-gate { 678*0Sstevel@tonic-gate Authctxt *authctxt = ctxt; 679*0Sstevel@tonic-gate Gssctxt *gssctxt; 680*0Sstevel@tonic-gate gss_buffer_desc send_tok, recv_tok, g_mic_data; 681*0Sstevel@tonic-gate Buffer mic_data; 682*0Sstevel@tonic-gate OM_uint32 status; 683*0Sstevel@tonic-gate u_int slen; 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL) 686*0Sstevel@tonic-gate fatal("input_gssapi_response: no authentication context"); 687*0Sstevel@tonic-gate gssctxt = authctxt->methoddata; 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate recv_tok.value=packet_get_string(&slen); 690*0Sstevel@tonic-gate recv_tok.length=slen; /* safe typecast */ 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate status=ssh_gssapi_init_ctx(gssctxt, authctxt->host, 693*0Sstevel@tonic-gate options.gss_deleg_creds, 694*0Sstevel@tonic-gate &recv_tok, &send_tok); 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate packet_check_eom(); 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate if (GSS_ERROR(status)) { 699*0Sstevel@tonic-gate if (send_tok.length>0) { 700*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); 701*0Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); 702*0Sstevel@tonic-gate packet_send(); 703*0Sstevel@tonic-gate packet_write_wait(); 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate /* Start again with the next method in the list */ 706*0Sstevel@tonic-gate clear_auth_state(authctxt); 707*0Sstevel@tonic-gate userauth(authctxt,NULL); 708*0Sstevel@tonic-gate return; 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate if (send_tok.length>0) { 712*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); 713*0Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); 714*0Sstevel@tonic-gate packet_send(); 715*0Sstevel@tonic-gate packet_write_wait(); 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate if (status != GSS_S_COMPLETE) 719*0Sstevel@tonic-gate return; 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate /* Make data buffer to MIC */ 722*0Sstevel@tonic-gate buffer_init(&mic_data); 723*0Sstevel@tonic-gate buffer_put_string(&mic_data, session_id2, session_id2_len); 724*0Sstevel@tonic-gate buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST); 725*0Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->server_user); 726*0Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->service); 727*0Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->method->name); 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate /* Make MIC */ 730*0Sstevel@tonic-gate g_mic_data.value = buffer_ptr(&mic_data); 731*0Sstevel@tonic-gate g_mic_data.length = buffer_len(&mic_data); 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate status = ssh_gssapi_get_mic(gssctxt, &g_mic_data, &send_tok); 734*0Sstevel@tonic-gate buffer_clear(&mic_data); 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate if (GSS_ERROR(status) || send_tok.length == 0) { 737*0Sstevel@tonic-gate /* 738*0Sstevel@tonic-gate * Oops, now what? There's no error token... 739*0Sstevel@tonic-gate * Next userauth 740*0Sstevel@tonic-gate */ 741*0Sstevel@tonic-gate debug("GSS_GetMIC() failed! - " 742*0Sstevel@tonic-gate "Abandoning GSSAPI userauth"); 743*0Sstevel@tonic-gate clear_auth_state(authctxt); 744*0Sstevel@tonic-gate userauth(authctxt,NULL); 745*0Sstevel@tonic-gate return; 746*0Sstevel@tonic-gate } 747*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC); 748*0Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); 749*0Sstevel@tonic-gate packet_send(); 750*0Sstevel@tonic-gate packet_write_wait(); 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate void 754*0Sstevel@tonic-gate input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) 755*0Sstevel@tonic-gate { 756*0Sstevel@tonic-gate OM_uint32 min_status; 757*0Sstevel@tonic-gate Authctxt *authctxt = ctxt; 758*0Sstevel@tonic-gate Gssctxt *gssctxt; 759*0Sstevel@tonic-gate gss_buffer_desc send_tok, recv_tok; 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate if (authctxt == NULL) 762*0Sstevel@tonic-gate fatal("input_gssapi_response: no authentication context"); 763*0Sstevel@tonic-gate gssctxt = authctxt->methoddata; 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate recv_tok.value=packet_get_string(&recv_tok.length); 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate /* Stick it into GSSAPI and see what it says */ 768*0Sstevel@tonic-gate (void) ssh_gssapi_init_ctx(gssctxt, authctxt->host, 769*0Sstevel@tonic-gate options.gss_deleg_creds, 770*0Sstevel@tonic-gate &recv_tok, &send_tok); 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate xfree(recv_tok.value); 773*0Sstevel@tonic-gate (void) gss_release_buffer(&min_status, &send_tok); 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate debug("Server sent a GSS-API error token during GSS userauth -- %s", 776*0Sstevel@tonic-gate ssh_gssapi_last_error(gssctxt, NULL, NULL)); 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate packet_check_eom(); 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate /* We can't send a packet to the server */ 781*0Sstevel@tonic-gate 782*0Sstevel@tonic-gate /* The draft says that we should wait for the server to fail 783*0Sstevel@tonic-gate * before starting the next authentication. So, we clear the 784*0Sstevel@tonic-gate * state, but don't do anything else 785*0Sstevel@tonic-gate */ 786*0Sstevel@tonic-gate clear_auth_state(authctxt); 787*0Sstevel@tonic-gate return; 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate void 791*0Sstevel@tonic-gate input_gssapi_error(int type, u_int32_t plen, void *ctxt) 792*0Sstevel@tonic-gate { 793*0Sstevel@tonic-gate OM_uint32 maj,min; 794*0Sstevel@tonic-gate char *msg; 795*0Sstevel@tonic-gate char *lang; 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate maj = packet_get_int(); 798*0Sstevel@tonic-gate min = packet_get_int(); 799*0Sstevel@tonic-gate msg = packet_get_string(NULL); 800*0Sstevel@tonic-gate lang = packet_get_string(NULL); 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate packet_check_eom(); 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate fprintf(stderr, "Server GSSAPI Error:\n%s (%d, %d)\n", msg, maj, min); 805*0Sstevel@tonic-gate xfree(msg); 806*0Sstevel@tonic-gate xfree(lang); 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate int 810*0Sstevel@tonic-gate userauth_gssapi_keyex(Authctxt *authctxt) 811*0Sstevel@tonic-gate { 812*0Sstevel@tonic-gate Gssctxt *gssctxt; 813*0Sstevel@tonic-gate gss_buffer_desc send_tok; 814*0Sstevel@tonic-gate OM_uint32 status; 815*0Sstevel@tonic-gate static int attempt = 0; 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL) 818*0Sstevel@tonic-gate fatal("input_gssapi_response: no authentication context"); 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate if (xxx_gssctxt == NULL || xxx_gssctxt->context == GSS_C_NO_CONTEXT) 821*0Sstevel@tonic-gate return 0; 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate if (strcmp(authctxt->method->name, "gssapi-keyex") == 0) 824*0Sstevel@tonic-gate authctxt->methoddata = gssctxt = xxx_gssctxt; 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate if (attempt++ >= 1) 827*0Sstevel@tonic-gate return 0; 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate if (strcmp(authctxt->method->name, "gssapi-keyex") == 0) { 830*0Sstevel@tonic-gate gss_buffer_desc g_mic_data; 831*0Sstevel@tonic-gate Buffer mic_data; 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate debug2("Authenticating with GSS-API context from key exchange (w/ MIC)"); 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate /* Make data buffer to MIC */ 836*0Sstevel@tonic-gate buffer_init(&mic_data); 837*0Sstevel@tonic-gate buffer_put_string(&mic_data, session_id2, session_id2_len); 838*0Sstevel@tonic-gate buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST); 839*0Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->server_user); 840*0Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->service); 841*0Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->method->name); 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate /* Make MIC */ 844*0Sstevel@tonic-gate g_mic_data.value = buffer_ptr(&mic_data); 845*0Sstevel@tonic-gate g_mic_data.length = buffer_len(&mic_data); 846*0Sstevel@tonic-gate status = ssh_gssapi_get_mic(gssctxt, &g_mic_data, &send_tok); 847*0Sstevel@tonic-gate buffer_clear(&mic_data); 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate if (GSS_ERROR(status) || send_tok.length == 0) { 850*0Sstevel@tonic-gate /* 851*0Sstevel@tonic-gate * Oops, now what? There's no error token... 852*0Sstevel@tonic-gate * Next userauth 853*0Sstevel@tonic-gate */ 854*0Sstevel@tonic-gate debug("GSS_GetMIC() failed! - " 855*0Sstevel@tonic-gate "Abandoning GSSAPI userauth"); 856*0Sstevel@tonic-gate clear_auth_state(authctxt); 857*0Sstevel@tonic-gate userauth(authctxt,NULL); 858*0Sstevel@tonic-gate return 0; 859*0Sstevel@tonic-gate } 860*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_REQUEST); 861*0Sstevel@tonic-gate packet_put_cstring(authctxt->server_user); 862*0Sstevel@tonic-gate packet_put_cstring(authctxt->service); 863*0Sstevel@tonic-gate packet_put_cstring(authctxt->method->name); 864*0Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); /* MIC */ 865*0Sstevel@tonic-gate packet_send(); 866*0Sstevel@tonic-gate packet_write_wait(); 867*0Sstevel@tonic-gate (void) gss_release_buffer(&status, &send_tok); 868*0Sstevel@tonic-gate } else if (strcmp(authctxt->method->name, "external-keyx") == 0) { 869*0Sstevel@tonic-gate debug2("Authentication with deprecated \"external-keyx\"" 870*0Sstevel@tonic-gate " method not supported"); 871*0Sstevel@tonic-gate return 0; 872*0Sstevel@tonic-gate } 873*0Sstevel@tonic-gate return 1; 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate static 877*0Sstevel@tonic-gate void 878*0Sstevel@tonic-gate userauth_gssapi_cleanup(Authctxt *authctxt) 879*0Sstevel@tonic-gate { 880*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,NULL); 881*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL); 882*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,NULL); 883*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,NULL); 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate if (authctxt == NULL || 886*0Sstevel@tonic-gate authctxt->method == NULL || 887*0Sstevel@tonic-gate authctxt->methoddata == NULL) 888*0Sstevel@tonic-gate return; 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate if (strncmp(authctxt->method->name, "gssapi", strlen("gssapi")) == 0) { 891*0Sstevel@tonic-gate ssh_gssapi_delete_ctx((Gssctxt **)&authctxt->methoddata); 892*0Sstevel@tonic-gate } 893*0Sstevel@tonic-gate } 894*0Sstevel@tonic-gate #endif /* GSSAPI */ 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate int 897*0Sstevel@tonic-gate userauth_none(Authctxt *authctxt) 898*0Sstevel@tonic-gate { 899*0Sstevel@tonic-gate /* initial userauth request */ 900*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_REQUEST); 901*0Sstevel@tonic-gate packet_put_cstring(authctxt->server_user); 902*0Sstevel@tonic-gate packet_put_cstring(authctxt->service); 903*0Sstevel@tonic-gate packet_put_cstring(authctxt->method->name); 904*0Sstevel@tonic-gate packet_send(); 905*0Sstevel@tonic-gate return 1; 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate } 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate int 910*0Sstevel@tonic-gate userauth_passwd(Authctxt *authctxt) 911*0Sstevel@tonic-gate { 912*0Sstevel@tonic-gate static int attempt = 0; 913*0Sstevel@tonic-gate char prompt[150]; 914*0Sstevel@tonic-gate char *password; 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate if (attempt++ >= options.number_of_password_prompts) 917*0Sstevel@tonic-gate return 0; 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate if (attempt != 1) 920*0Sstevel@tonic-gate error("Permission denied, please try again."); 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate snprintf(prompt, sizeof(prompt), gettext("%.30s@%.128s's password: "), 923*0Sstevel@tonic-gate authctxt->server_user, authctxt->host); 924*0Sstevel@tonic-gate password = read_passphrase(prompt, 0); 925*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_REQUEST); 926*0Sstevel@tonic-gate packet_put_cstring(authctxt->server_user); 927*0Sstevel@tonic-gate packet_put_cstring(authctxt->service); 928*0Sstevel@tonic-gate packet_put_cstring(authctxt->method->name); 929*0Sstevel@tonic-gate packet_put_char(0); 930*0Sstevel@tonic-gate packet_put_cstring(password); 931*0Sstevel@tonic-gate memset(password, 0, strlen(password)); 932*0Sstevel@tonic-gate xfree(password); 933*0Sstevel@tonic-gate packet_add_padding(64); 934*0Sstevel@tonic-gate packet_send(); 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 937*0Sstevel@tonic-gate &input_userauth_passwd_changereq); 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate return 1; 940*0Sstevel@tonic-gate } 941*0Sstevel@tonic-gate /* 942*0Sstevel@tonic-gate * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST 943*0Sstevel@tonic-gate */ 944*0Sstevel@tonic-gate void 945*0Sstevel@tonic-gate input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) 946*0Sstevel@tonic-gate { 947*0Sstevel@tonic-gate Authctxt *authctxt = ctxt; 948*0Sstevel@tonic-gate char *info, *lang, *password = NULL, *retype = NULL; 949*0Sstevel@tonic-gate char prompt[150]; 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate debug2("input_userauth_passwd_changereq"); 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate if (authctxt == NULL) 954*0Sstevel@tonic-gate fatal("input_userauth_passwd_changereq: " 955*0Sstevel@tonic-gate "no authentication context"); 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate info = packet_get_string(NULL); 958*0Sstevel@tonic-gate lang = packet_get_string(NULL); 959*0Sstevel@tonic-gate if (strlen(info) > 0) 960*0Sstevel@tonic-gate log("%s", info); 961*0Sstevel@tonic-gate xfree(info); 962*0Sstevel@tonic-gate xfree(lang); 963*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_REQUEST); 964*0Sstevel@tonic-gate packet_put_cstring(authctxt->server_user); 965*0Sstevel@tonic-gate packet_put_cstring(authctxt->service); 966*0Sstevel@tonic-gate packet_put_cstring(authctxt->method->name); 967*0Sstevel@tonic-gate packet_put_char(1); /* additional info */ 968*0Sstevel@tonic-gate snprintf(prompt, sizeof(prompt), 969*0Sstevel@tonic-gate gettext("Enter %.30s@%.128s's old password: "), 970*0Sstevel@tonic-gate authctxt->server_user, authctxt->host); 971*0Sstevel@tonic-gate password = read_passphrase(prompt, 0); 972*0Sstevel@tonic-gate packet_put_cstring(password); 973*0Sstevel@tonic-gate memset(password, 0, strlen(password)); 974*0Sstevel@tonic-gate xfree(password); 975*0Sstevel@tonic-gate password = NULL; 976*0Sstevel@tonic-gate while (password == NULL) { 977*0Sstevel@tonic-gate snprintf(prompt, sizeof(prompt), 978*0Sstevel@tonic-gate gettext("Enter %.30s@%.128s's new password: "), 979*0Sstevel@tonic-gate authctxt->server_user, authctxt->host); 980*0Sstevel@tonic-gate password = read_passphrase(prompt, RP_ALLOW_EOF); 981*0Sstevel@tonic-gate if (password == NULL) { 982*0Sstevel@tonic-gate /* bail out */ 983*0Sstevel@tonic-gate return; 984*0Sstevel@tonic-gate } 985*0Sstevel@tonic-gate snprintf(prompt, sizeof(prompt), 986*0Sstevel@tonic-gate gettext("Retype %.30s@%.128s's new password: "), 987*0Sstevel@tonic-gate authctxt->server_user, authctxt->host); 988*0Sstevel@tonic-gate retype = read_passphrase(prompt, 0); 989*0Sstevel@tonic-gate if (strcmp(password, retype) != 0) { 990*0Sstevel@tonic-gate memset(password, 0, strlen(password)); 991*0Sstevel@tonic-gate xfree(password); 992*0Sstevel@tonic-gate log("Mismatch; try again, EOF to quit."); 993*0Sstevel@tonic-gate password = NULL; 994*0Sstevel@tonic-gate } 995*0Sstevel@tonic-gate memset(retype, 0, strlen(retype)); 996*0Sstevel@tonic-gate xfree(retype); 997*0Sstevel@tonic-gate } 998*0Sstevel@tonic-gate packet_put_cstring(password); 999*0Sstevel@tonic-gate memset(password, 0, strlen(password)); 1000*0Sstevel@tonic-gate xfree(password); 1001*0Sstevel@tonic-gate packet_add_padding(64); 1002*0Sstevel@tonic-gate packet_send(); 1003*0Sstevel@tonic-gate 1004*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 1005*0Sstevel@tonic-gate &input_userauth_passwd_changereq); 1006*0Sstevel@tonic-gate } 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate static void 1009*0Sstevel@tonic-gate clear_auth_state(Authctxt *authctxt) 1010*0Sstevel@tonic-gate { 1011*0Sstevel@tonic-gate /* XXX clear authentication state */ 1012*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL); 1013*0Sstevel@tonic-gate #ifdef GSSAPI 1014*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,NULL); 1015*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL); 1016*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,NULL); 1017*0Sstevel@tonic-gate #endif /* GSSAPI */ 1018*0Sstevel@tonic-gate 1019*0Sstevel@tonic-gate if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) { 1020*0Sstevel@tonic-gate debug3("clear_auth_state: key_free %p", authctxt->last_key); 1021*0Sstevel@tonic-gate key_free(authctxt->last_key); 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate authctxt->last_key = NULL; 1024*0Sstevel@tonic-gate authctxt->last_key_hint = -2; 1025*0Sstevel@tonic-gate authctxt->last_key_sign = NULL; 1026*0Sstevel@tonic-gate } 1027*0Sstevel@tonic-gate 1028*0Sstevel@tonic-gate static int 1029*0Sstevel@tonic-gate sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) 1030*0Sstevel@tonic-gate { 1031*0Sstevel@tonic-gate Buffer b; 1032*0Sstevel@tonic-gate u_char *blob, *signature; 1033*0Sstevel@tonic-gate u_int bloblen, slen; 1034*0Sstevel@tonic-gate int skip = 0; 1035*0Sstevel@tonic-gate int ret = -1; 1036*0Sstevel@tonic-gate int have_sig = 1; 1037*0Sstevel@tonic-gate 1038*0Sstevel@tonic-gate debug3("sign_and_send_pubkey"); 1039*0Sstevel@tonic-gate 1040*0Sstevel@tonic-gate if (key_to_blob(k, &blob, &bloblen) == 0) { 1041*0Sstevel@tonic-gate /* we cannot handle this key */ 1042*0Sstevel@tonic-gate debug3("sign_and_send_pubkey: cannot handle key"); 1043*0Sstevel@tonic-gate return 0; 1044*0Sstevel@tonic-gate } 1045*0Sstevel@tonic-gate /* data to be signed */ 1046*0Sstevel@tonic-gate buffer_init(&b); 1047*0Sstevel@tonic-gate if (datafellows & SSH_OLD_SESSIONID) { 1048*0Sstevel@tonic-gate buffer_append(&b, session_id2, session_id2_len); 1049*0Sstevel@tonic-gate skip = session_id2_len; 1050*0Sstevel@tonic-gate } else { 1051*0Sstevel@tonic-gate buffer_put_string(&b, session_id2, session_id2_len); 1052*0Sstevel@tonic-gate skip = buffer_len(&b); 1053*0Sstevel@tonic-gate } 1054*0Sstevel@tonic-gate buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 1055*0Sstevel@tonic-gate buffer_put_cstring(&b, authctxt->server_user); 1056*0Sstevel@tonic-gate buffer_put_cstring(&b, 1057*0Sstevel@tonic-gate datafellows & SSH_BUG_PKSERVICE ? 1058*0Sstevel@tonic-gate "ssh-userauth" : 1059*0Sstevel@tonic-gate authctxt->service); 1060*0Sstevel@tonic-gate if (datafellows & SSH_BUG_PKAUTH) { 1061*0Sstevel@tonic-gate buffer_put_char(&b, have_sig); 1062*0Sstevel@tonic-gate } else { 1063*0Sstevel@tonic-gate buffer_put_cstring(&b, authctxt->method->name); 1064*0Sstevel@tonic-gate buffer_put_char(&b, have_sig); 1065*0Sstevel@tonic-gate buffer_put_cstring(&b, key_ssh_name(k)); 1066*0Sstevel@tonic-gate } 1067*0Sstevel@tonic-gate buffer_put_string(&b, blob, bloblen); 1068*0Sstevel@tonic-gate 1069*0Sstevel@tonic-gate /* generate signature */ 1070*0Sstevel@tonic-gate ret = (*sign_callback)(authctxt, k, &signature, &slen, 1071*0Sstevel@tonic-gate buffer_ptr(&b), buffer_len(&b)); 1072*0Sstevel@tonic-gate if (ret == -1) { 1073*0Sstevel@tonic-gate xfree(blob); 1074*0Sstevel@tonic-gate buffer_free(&b); 1075*0Sstevel@tonic-gate return 0; 1076*0Sstevel@tonic-gate } 1077*0Sstevel@tonic-gate #ifdef DEBUG_PK 1078*0Sstevel@tonic-gate buffer_dump(&b); 1079*0Sstevel@tonic-gate #endif 1080*0Sstevel@tonic-gate if (datafellows & SSH_BUG_PKSERVICE) { 1081*0Sstevel@tonic-gate buffer_clear(&b); 1082*0Sstevel@tonic-gate buffer_append(&b, session_id2, session_id2_len); 1083*0Sstevel@tonic-gate skip = session_id2_len; 1084*0Sstevel@tonic-gate buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 1085*0Sstevel@tonic-gate buffer_put_cstring(&b, authctxt->server_user); 1086*0Sstevel@tonic-gate buffer_put_cstring(&b, authctxt->service); 1087*0Sstevel@tonic-gate buffer_put_cstring(&b, authctxt->method->name); 1088*0Sstevel@tonic-gate buffer_put_char(&b, have_sig); 1089*0Sstevel@tonic-gate if (!(datafellows & SSH_BUG_PKAUTH)) 1090*0Sstevel@tonic-gate buffer_put_cstring(&b, key_ssh_name(k)); 1091*0Sstevel@tonic-gate buffer_put_string(&b, blob, bloblen); 1092*0Sstevel@tonic-gate } 1093*0Sstevel@tonic-gate xfree(blob); 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate /* append signature */ 1096*0Sstevel@tonic-gate buffer_put_string(&b, signature, slen); 1097*0Sstevel@tonic-gate xfree(signature); 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate /* skip session id and packet type */ 1100*0Sstevel@tonic-gate if (buffer_len(&b) < skip + 1) 1101*0Sstevel@tonic-gate fatal("userauth_pubkey: internal error"); 1102*0Sstevel@tonic-gate buffer_consume(&b, skip + 1); 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate /* put remaining data from buffer into packet */ 1105*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_REQUEST); 1106*0Sstevel@tonic-gate packet_put_raw(buffer_ptr(&b), buffer_len(&b)); 1107*0Sstevel@tonic-gate buffer_free(&b); 1108*0Sstevel@tonic-gate packet_send(); 1109*0Sstevel@tonic-gate 1110*0Sstevel@tonic-gate return 1; 1111*0Sstevel@tonic-gate } 1112*0Sstevel@tonic-gate 1113*0Sstevel@tonic-gate static int 1114*0Sstevel@tonic-gate send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback, 1115*0Sstevel@tonic-gate int hint) 1116*0Sstevel@tonic-gate { 1117*0Sstevel@tonic-gate u_char *blob; 1118*0Sstevel@tonic-gate u_int bloblen, have_sig = 0; 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate debug3("send_pubkey_test"); 1121*0Sstevel@tonic-gate 1122*0Sstevel@tonic-gate if (key_to_blob(k, &blob, &bloblen) == 0) { 1123*0Sstevel@tonic-gate /* we cannot handle this key */ 1124*0Sstevel@tonic-gate debug3("send_pubkey_test: cannot handle key"); 1125*0Sstevel@tonic-gate return 0; 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate /* register callback for USERAUTH_PK_OK message */ 1128*0Sstevel@tonic-gate authctxt->last_key_sign = sign_callback; 1129*0Sstevel@tonic-gate authctxt->last_key_hint = hint; 1130*0Sstevel@tonic-gate authctxt->last_key = k; 1131*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); 1132*0Sstevel@tonic-gate 1133*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_REQUEST); 1134*0Sstevel@tonic-gate packet_put_cstring(authctxt->server_user); 1135*0Sstevel@tonic-gate packet_put_cstring(authctxt->service); 1136*0Sstevel@tonic-gate packet_put_cstring(authctxt->method->name); 1137*0Sstevel@tonic-gate packet_put_char(have_sig); 1138*0Sstevel@tonic-gate if (!(datafellows & SSH_BUG_PKAUTH)) 1139*0Sstevel@tonic-gate packet_put_cstring(key_ssh_name(k)); 1140*0Sstevel@tonic-gate packet_put_string(blob, bloblen); 1141*0Sstevel@tonic-gate xfree(blob); 1142*0Sstevel@tonic-gate packet_send(); 1143*0Sstevel@tonic-gate return 1; 1144*0Sstevel@tonic-gate } 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate static Key * 1147*0Sstevel@tonic-gate load_identity_file(char *filename) 1148*0Sstevel@tonic-gate { 1149*0Sstevel@tonic-gate Key *private; 1150*0Sstevel@tonic-gate char prompt[300], *passphrase; 1151*0Sstevel@tonic-gate int quit, i; 1152*0Sstevel@tonic-gate struct stat st; 1153*0Sstevel@tonic-gate 1154*0Sstevel@tonic-gate if (stat(filename, &st) < 0) { 1155*0Sstevel@tonic-gate debug3("no such identity: %s", filename); 1156*0Sstevel@tonic-gate return NULL; 1157*0Sstevel@tonic-gate } 1158*0Sstevel@tonic-gate private = key_load_private_type(KEY_UNSPEC, filename, "", NULL); 1159*0Sstevel@tonic-gate if (private == NULL) { 1160*0Sstevel@tonic-gate if (options.batch_mode) 1161*0Sstevel@tonic-gate return NULL; 1162*0Sstevel@tonic-gate snprintf(prompt, sizeof prompt, 1163*0Sstevel@tonic-gate gettext("Enter passphrase for key '%.100s': "), filename); 1164*0Sstevel@tonic-gate for (i = 0; i < options.number_of_password_prompts; i++) { 1165*0Sstevel@tonic-gate passphrase = read_passphrase(prompt, 0); 1166*0Sstevel@tonic-gate if (strcmp(passphrase, "") != 0) { 1167*0Sstevel@tonic-gate private = key_load_private_type(KEY_UNSPEC, filename, 1168*0Sstevel@tonic-gate passphrase, NULL); 1169*0Sstevel@tonic-gate quit = 0; 1170*0Sstevel@tonic-gate } else { 1171*0Sstevel@tonic-gate debug2("no passphrase given, try next key"); 1172*0Sstevel@tonic-gate quit = 1; 1173*0Sstevel@tonic-gate } 1174*0Sstevel@tonic-gate memset(passphrase, 0, strlen(passphrase)); 1175*0Sstevel@tonic-gate xfree(passphrase); 1176*0Sstevel@tonic-gate if (private != NULL || quit) 1177*0Sstevel@tonic-gate break; 1178*0Sstevel@tonic-gate debug2("bad passphrase given, try again..."); 1179*0Sstevel@tonic-gate } 1180*0Sstevel@tonic-gate } 1181*0Sstevel@tonic-gate return private; 1182*0Sstevel@tonic-gate } 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate static int 1185*0Sstevel@tonic-gate identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp, 1186*0Sstevel@tonic-gate u_char *data, u_int datalen) 1187*0Sstevel@tonic-gate { 1188*0Sstevel@tonic-gate Key *private; 1189*0Sstevel@tonic-gate int idx, ret; 1190*0Sstevel@tonic-gate 1191*0Sstevel@tonic-gate idx = authctxt->last_key_hint; 1192*0Sstevel@tonic-gate if (idx < 0) 1193*0Sstevel@tonic-gate return -1; 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate /* private key is stored in external hardware */ 1196*0Sstevel@tonic-gate if (options.identity_keys[idx]->flags & KEY_FLAG_EXT) 1197*0Sstevel@tonic-gate return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen); 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate private = load_identity_file(options.identity_files[idx]); 1200*0Sstevel@tonic-gate if (private == NULL) 1201*0Sstevel@tonic-gate return -1; 1202*0Sstevel@tonic-gate ret = key_sign(private, sigp, lenp, data, datalen); 1203*0Sstevel@tonic-gate key_free(private); 1204*0Sstevel@tonic-gate return ret; 1205*0Sstevel@tonic-gate } 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate static int 1208*0Sstevel@tonic-gate agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp, 1209*0Sstevel@tonic-gate u_char *data, u_int datalen) 1210*0Sstevel@tonic-gate { 1211*0Sstevel@tonic-gate return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen); 1212*0Sstevel@tonic-gate } 1213*0Sstevel@tonic-gate 1214*0Sstevel@tonic-gate static int 1215*0Sstevel@tonic-gate key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp, 1216*0Sstevel@tonic-gate u_char *data, u_int datalen) 1217*0Sstevel@tonic-gate { 1218*0Sstevel@tonic-gate return key_sign(key, sigp, lenp, data, datalen); 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate 1221*0Sstevel@tonic-gate static int 1222*0Sstevel@tonic-gate userauth_pubkey_agent(Authctxt *authctxt) 1223*0Sstevel@tonic-gate { 1224*0Sstevel@tonic-gate static int called = 0; 1225*0Sstevel@tonic-gate int ret = 0; 1226*0Sstevel@tonic-gate char *comment; 1227*0Sstevel@tonic-gate Key *k; 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate if (called == 0) { 1230*0Sstevel@tonic-gate if (ssh_get_num_identities(authctxt->agent, 2) == 0) 1231*0Sstevel@tonic-gate debug2("userauth_pubkey_agent: no keys at all"); 1232*0Sstevel@tonic-gate called = 1; 1233*0Sstevel@tonic-gate } 1234*0Sstevel@tonic-gate k = ssh_get_next_identity(authctxt->agent, &comment, 2); 1235*0Sstevel@tonic-gate if (k == NULL) { 1236*0Sstevel@tonic-gate debug2("userauth_pubkey_agent: no more keys"); 1237*0Sstevel@tonic-gate } else { 1238*0Sstevel@tonic-gate debug("Offering agent key: %s", comment); 1239*0Sstevel@tonic-gate xfree(comment); 1240*0Sstevel@tonic-gate ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1); 1241*0Sstevel@tonic-gate if (ret == 0) 1242*0Sstevel@tonic-gate key_free(k); 1243*0Sstevel@tonic-gate } 1244*0Sstevel@tonic-gate if (ret == 0) 1245*0Sstevel@tonic-gate debug2("userauth_pubkey_agent: no message sent"); 1246*0Sstevel@tonic-gate return ret; 1247*0Sstevel@tonic-gate } 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate int 1250*0Sstevel@tonic-gate userauth_pubkey(Authctxt *authctxt) 1251*0Sstevel@tonic-gate { 1252*0Sstevel@tonic-gate static int idx = 0; 1253*0Sstevel@tonic-gate int sent = 0; 1254*0Sstevel@tonic-gate Key *key; 1255*0Sstevel@tonic-gate char *filename; 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate if (authctxt->agent != NULL) { 1258*0Sstevel@tonic-gate do { 1259*0Sstevel@tonic-gate sent = userauth_pubkey_agent(authctxt); 1260*0Sstevel@tonic-gate } while (!sent && authctxt->agent->howmany > 0); 1261*0Sstevel@tonic-gate } 1262*0Sstevel@tonic-gate while (!sent && idx < options.num_identity_files) { 1263*0Sstevel@tonic-gate key = options.identity_keys[idx]; 1264*0Sstevel@tonic-gate filename = options.identity_files[idx]; 1265*0Sstevel@tonic-gate if (key == NULL) { 1266*0Sstevel@tonic-gate debug("Trying private key: %s", filename); 1267*0Sstevel@tonic-gate key = load_identity_file(filename); 1268*0Sstevel@tonic-gate if (key != NULL) { 1269*0Sstevel@tonic-gate sent = sign_and_send_pubkey(authctxt, key, 1270*0Sstevel@tonic-gate key_sign_cb); 1271*0Sstevel@tonic-gate key_free(key); 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate } else if (key->type != KEY_RSA1) { 1274*0Sstevel@tonic-gate debug("Trying public key: %s", filename); 1275*0Sstevel@tonic-gate sent = send_pubkey_test(authctxt, key, 1276*0Sstevel@tonic-gate identity_sign_cb, idx); 1277*0Sstevel@tonic-gate } 1278*0Sstevel@tonic-gate idx++; 1279*0Sstevel@tonic-gate } 1280*0Sstevel@tonic-gate return sent; 1281*0Sstevel@tonic-gate } 1282*0Sstevel@tonic-gate 1283*0Sstevel@tonic-gate /* 1284*0Sstevel@tonic-gate * Send userauth request message specifying keyboard-interactive method. 1285*0Sstevel@tonic-gate */ 1286*0Sstevel@tonic-gate int 1287*0Sstevel@tonic-gate userauth_kbdint(Authctxt *authctxt) 1288*0Sstevel@tonic-gate { 1289*0Sstevel@tonic-gate static int attempt = 0; 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate if (attempt++ >= options.number_of_password_prompts) 1292*0Sstevel@tonic-gate return 0; 1293*0Sstevel@tonic-gate /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */ 1294*0Sstevel@tonic-gate if (attempt > 1 && !authctxt->info_req_seen) { 1295*0Sstevel@tonic-gate debug3("userauth_kbdint: disable: no info_req_seen"); 1296*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL); 1297*0Sstevel@tonic-gate return 0; 1298*0Sstevel@tonic-gate } 1299*0Sstevel@tonic-gate 1300*0Sstevel@tonic-gate debug2("userauth_kbdint"); 1301*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_REQUEST); 1302*0Sstevel@tonic-gate packet_put_cstring(authctxt->server_user); 1303*0Sstevel@tonic-gate packet_put_cstring(authctxt->service); 1304*0Sstevel@tonic-gate packet_put_cstring(authctxt->method->name); 1305*0Sstevel@tonic-gate packet_put_cstring(""); /* lang */ 1306*0Sstevel@tonic-gate packet_put_cstring(options.kbd_interactive_devices ? 1307*0Sstevel@tonic-gate options.kbd_interactive_devices : ""); 1308*0Sstevel@tonic-gate packet_send(); 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); 1311*0Sstevel@tonic-gate return 1; 1312*0Sstevel@tonic-gate } 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate /* 1315*0Sstevel@tonic-gate * parse INFO_REQUEST, prompt user and send INFO_RESPONSE 1316*0Sstevel@tonic-gate */ 1317*0Sstevel@tonic-gate void 1318*0Sstevel@tonic-gate input_userauth_info_req(int type, u_int32_t seq, void *ctxt) 1319*0Sstevel@tonic-gate { 1320*0Sstevel@tonic-gate Authctxt *authctxt = ctxt; 1321*0Sstevel@tonic-gate char *name, *inst, *lang, *prompt, *response; 1322*0Sstevel@tonic-gate u_int num_prompts, i; 1323*0Sstevel@tonic-gate int echo = 0; 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate debug2("input_userauth_info_req"); 1326*0Sstevel@tonic-gate 1327*0Sstevel@tonic-gate if (authctxt == NULL) 1328*0Sstevel@tonic-gate fatal("input_userauth_info_req: no authentication context"); 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate authctxt->info_req_seen = 1; 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate name = packet_get_string(NULL); 1333*0Sstevel@tonic-gate inst = packet_get_string(NULL); 1334*0Sstevel@tonic-gate lang = packet_get_string(NULL); 1335*0Sstevel@tonic-gate if (strlen(name) > 0) 1336*0Sstevel@tonic-gate log("%s", name); 1337*0Sstevel@tonic-gate if (strlen(inst) > 0) 1338*0Sstevel@tonic-gate log("%s", inst); 1339*0Sstevel@tonic-gate xfree(name); 1340*0Sstevel@tonic-gate xfree(inst); 1341*0Sstevel@tonic-gate xfree(lang); 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate num_prompts = packet_get_int(); 1344*0Sstevel@tonic-gate /* 1345*0Sstevel@tonic-gate * Begin to build info response packet based on prompts requested. 1346*0Sstevel@tonic-gate * We commit to providing the correct number of responses, so if 1347*0Sstevel@tonic-gate * further on we run into a problem that prevents this, we have to 1348*0Sstevel@tonic-gate * be sure and clean this up and send a correct error response. 1349*0Sstevel@tonic-gate */ 1350*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE); 1351*0Sstevel@tonic-gate packet_put_int(num_prompts); 1352*0Sstevel@tonic-gate 1353*0Sstevel@tonic-gate debug2("input_userauth_info_req: num_prompts %d", num_prompts); 1354*0Sstevel@tonic-gate for (i = 0; i < num_prompts; i++) { 1355*0Sstevel@tonic-gate prompt = packet_get_string(NULL); 1356*0Sstevel@tonic-gate echo = packet_get_char(); 1357*0Sstevel@tonic-gate 1358*0Sstevel@tonic-gate response = read_passphrase(prompt, echo ? RP_ECHO : 0); 1359*0Sstevel@tonic-gate 1360*0Sstevel@tonic-gate packet_put_cstring(response); 1361*0Sstevel@tonic-gate memset(response, 0, strlen(response)); 1362*0Sstevel@tonic-gate xfree(response); 1363*0Sstevel@tonic-gate xfree(prompt); 1364*0Sstevel@tonic-gate } 1365*0Sstevel@tonic-gate packet_check_eom(); /* done with parsing incoming message. */ 1366*0Sstevel@tonic-gate 1367*0Sstevel@tonic-gate packet_add_padding(64); 1368*0Sstevel@tonic-gate packet_send(); 1369*0Sstevel@tonic-gate } 1370*0Sstevel@tonic-gate 1371*0Sstevel@tonic-gate static int 1372*0Sstevel@tonic-gate ssh_keysign(Key *key, u_char **sigp, u_int *lenp, 1373*0Sstevel@tonic-gate u_char *data, u_int datalen) 1374*0Sstevel@tonic-gate { 1375*0Sstevel@tonic-gate Buffer b; 1376*0Sstevel@tonic-gate struct stat st; 1377*0Sstevel@tonic-gate pid_t pid; 1378*0Sstevel@tonic-gate int to[2], from[2], status, version = 2; 1379*0Sstevel@tonic-gate 1380*0Sstevel@tonic-gate debug2("ssh_keysign called"); 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { 1383*0Sstevel@tonic-gate error("ssh_keysign: no installed: %s", strerror(errno)); 1384*0Sstevel@tonic-gate return -1; 1385*0Sstevel@tonic-gate } 1386*0Sstevel@tonic-gate if (fflush(stdout) != 0) 1387*0Sstevel@tonic-gate error("ssh_keysign: fflush: %s", strerror(errno)); 1388*0Sstevel@tonic-gate if (pipe(to) < 0) { 1389*0Sstevel@tonic-gate error("ssh_keysign: pipe: %s", strerror(errno)); 1390*0Sstevel@tonic-gate return -1; 1391*0Sstevel@tonic-gate } 1392*0Sstevel@tonic-gate if (pipe(from) < 0) { 1393*0Sstevel@tonic-gate error("ssh_keysign: pipe: %s", strerror(errno)); 1394*0Sstevel@tonic-gate return -1; 1395*0Sstevel@tonic-gate } 1396*0Sstevel@tonic-gate if ((pid = fork()) < 0) { 1397*0Sstevel@tonic-gate error("ssh_keysign: fork: %s", strerror(errno)); 1398*0Sstevel@tonic-gate return -1; 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate if (pid == 0) { 1401*0Sstevel@tonic-gate seteuid(getuid()); 1402*0Sstevel@tonic-gate setuid(getuid()); 1403*0Sstevel@tonic-gate close(from[0]); 1404*0Sstevel@tonic-gate if (dup2(from[1], STDOUT_FILENO) < 0) 1405*0Sstevel@tonic-gate fatal("ssh_keysign: dup2: %s", strerror(errno)); 1406*0Sstevel@tonic-gate close(to[1]); 1407*0Sstevel@tonic-gate if (dup2(to[0], STDIN_FILENO) < 0) 1408*0Sstevel@tonic-gate fatal("ssh_keysign: dup2: %s", strerror(errno)); 1409*0Sstevel@tonic-gate close(from[1]); 1410*0Sstevel@tonic-gate close(to[0]); 1411*0Sstevel@tonic-gate execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); 1412*0Sstevel@tonic-gate fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN, 1413*0Sstevel@tonic-gate strerror(errno)); 1414*0Sstevel@tonic-gate } 1415*0Sstevel@tonic-gate close(from[1]); 1416*0Sstevel@tonic-gate close(to[0]); 1417*0Sstevel@tonic-gate 1418*0Sstevel@tonic-gate buffer_init(&b); 1419*0Sstevel@tonic-gate buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */ 1420*0Sstevel@tonic-gate buffer_put_string(&b, data, datalen); 1421*0Sstevel@tonic-gate ssh_msg_send(to[1], version, &b); 1422*0Sstevel@tonic-gate 1423*0Sstevel@tonic-gate if (ssh_msg_recv(from[0], &b) < 0) { 1424*0Sstevel@tonic-gate error("ssh_keysign: no reply"); 1425*0Sstevel@tonic-gate buffer_clear(&b); 1426*0Sstevel@tonic-gate return -1; 1427*0Sstevel@tonic-gate } 1428*0Sstevel@tonic-gate close(from[0]); 1429*0Sstevel@tonic-gate close(to[1]); 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate while (waitpid(pid, &status, 0) < 0) 1432*0Sstevel@tonic-gate if (errno != EINTR) 1433*0Sstevel@tonic-gate break; 1434*0Sstevel@tonic-gate 1435*0Sstevel@tonic-gate if (buffer_get_char(&b) != version) { 1436*0Sstevel@tonic-gate error("ssh_keysign: bad version"); 1437*0Sstevel@tonic-gate buffer_clear(&b); 1438*0Sstevel@tonic-gate return -1; 1439*0Sstevel@tonic-gate } 1440*0Sstevel@tonic-gate *sigp = buffer_get_string(&b, lenp); 1441*0Sstevel@tonic-gate buffer_clear(&b); 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate return 0; 1444*0Sstevel@tonic-gate } 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate int 1447*0Sstevel@tonic-gate userauth_hostbased(Authctxt *authctxt) 1448*0Sstevel@tonic-gate { 1449*0Sstevel@tonic-gate Key *private = NULL; 1450*0Sstevel@tonic-gate Sensitive *sensitive = authctxt->sensitive; 1451*0Sstevel@tonic-gate Buffer b; 1452*0Sstevel@tonic-gate u_char *signature, *blob; 1453*0Sstevel@tonic-gate char *chost, *pkalg, *p; 1454*0Sstevel@tonic-gate const char *service; 1455*0Sstevel@tonic-gate u_int blen, slen; 1456*0Sstevel@tonic-gate int ok, i, len, found = 0; 1457*0Sstevel@tonic-gate static int last_hostkey = -1; 1458*0Sstevel@tonic-gate 1459*0Sstevel@tonic-gate /* check for a useful key */ 1460*0Sstevel@tonic-gate for (i = 0; i < sensitive->nkeys; i++) { 1461*0Sstevel@tonic-gate private = sensitive->keys[i]; 1462*0Sstevel@tonic-gate if (private && private->type != KEY_RSA1 && i > last_hostkey) { 1463*0Sstevel@tonic-gate found = 1; 1464*0Sstevel@tonic-gate last_hostkey = i; 1465*0Sstevel@tonic-gate /* we take and free the key */ 1466*0Sstevel@tonic-gate sensitive->keys[i] = NULL; 1467*0Sstevel@tonic-gate break; 1468*0Sstevel@tonic-gate } 1469*0Sstevel@tonic-gate } 1470*0Sstevel@tonic-gate if (!found) { 1471*0Sstevel@tonic-gate debug("No more client hostkeys for hostbased authentication"); 1472*0Sstevel@tonic-gate return 0; 1473*0Sstevel@tonic-gate } 1474*0Sstevel@tonic-gate if (key_to_blob(private, &blob, &blen) == 0) { 1475*0Sstevel@tonic-gate key_free(private); 1476*0Sstevel@tonic-gate return 0; 1477*0Sstevel@tonic-gate } 1478*0Sstevel@tonic-gate /* figure out a name for the client host */ 1479*0Sstevel@tonic-gate p = get_local_name(packet_get_connection_in()); 1480*0Sstevel@tonic-gate if (p == NULL) { 1481*0Sstevel@tonic-gate error("userauth_hostbased: cannot get local ipaddr/name"); 1482*0Sstevel@tonic-gate key_free(private); 1483*0Sstevel@tonic-gate return 0; 1484*0Sstevel@tonic-gate } 1485*0Sstevel@tonic-gate 1486*0Sstevel@tonic-gate service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : 1487*0Sstevel@tonic-gate authctxt->service; 1488*0Sstevel@tonic-gate pkalg = xstrdup(key_ssh_name(private)); 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate len = strlen(p) + 2; 1491*0Sstevel@tonic-gate chost = xmalloc(len); 1492*0Sstevel@tonic-gate strlcpy(chost, p, len); 1493*0Sstevel@tonic-gate strlcat(chost, ".", len); 1494*0Sstevel@tonic-gate xfree(p); 1495*0Sstevel@tonic-gate debug2("userauth_hostbased: chost %s, pkalg %s", chost, pkalg); 1496*0Sstevel@tonic-gate 1497*0Sstevel@tonic-gate buffer_init(&b); 1498*0Sstevel@tonic-gate /* construct data */ 1499*0Sstevel@tonic-gate buffer_put_string(&b, session_id2, session_id2_len); 1500*0Sstevel@tonic-gate buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 1501*0Sstevel@tonic-gate buffer_put_cstring(&b, authctxt->server_user); 1502*0Sstevel@tonic-gate buffer_put_cstring(&b, service); 1503*0Sstevel@tonic-gate buffer_put_cstring(&b, authctxt->method->name); 1504*0Sstevel@tonic-gate buffer_put_cstring(&b, pkalg); 1505*0Sstevel@tonic-gate buffer_put_string(&b, blob, blen); 1506*0Sstevel@tonic-gate buffer_put_cstring(&b, chost); 1507*0Sstevel@tonic-gate buffer_put_cstring(&b, authctxt->local_user); 1508*0Sstevel@tonic-gate #ifdef DEBUG_PK 1509*0Sstevel@tonic-gate buffer_dump(&b); 1510*0Sstevel@tonic-gate #endif 1511*0Sstevel@tonic-gate if (sensitive->external_keysign) 1512*0Sstevel@tonic-gate ok = ssh_keysign(private, &signature, &slen, 1513*0Sstevel@tonic-gate buffer_ptr(&b), buffer_len(&b)); 1514*0Sstevel@tonic-gate else 1515*0Sstevel@tonic-gate ok = key_sign(private, &signature, &slen, 1516*0Sstevel@tonic-gate buffer_ptr(&b), buffer_len(&b)); 1517*0Sstevel@tonic-gate key_free(private); 1518*0Sstevel@tonic-gate buffer_free(&b); 1519*0Sstevel@tonic-gate if (ok != 0) { 1520*0Sstevel@tonic-gate error("key_sign failed"); 1521*0Sstevel@tonic-gate xfree(chost); 1522*0Sstevel@tonic-gate xfree(pkalg); 1523*0Sstevel@tonic-gate return 0; 1524*0Sstevel@tonic-gate } 1525*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_REQUEST); 1526*0Sstevel@tonic-gate packet_put_cstring(authctxt->server_user); 1527*0Sstevel@tonic-gate packet_put_cstring(authctxt->service); 1528*0Sstevel@tonic-gate packet_put_cstring(authctxt->method->name); 1529*0Sstevel@tonic-gate packet_put_cstring(pkalg); 1530*0Sstevel@tonic-gate packet_put_string(blob, blen); 1531*0Sstevel@tonic-gate packet_put_cstring(chost); 1532*0Sstevel@tonic-gate packet_put_cstring(authctxt->local_user); 1533*0Sstevel@tonic-gate packet_put_string(signature, slen); 1534*0Sstevel@tonic-gate memset(signature, 's', slen); 1535*0Sstevel@tonic-gate xfree(signature); 1536*0Sstevel@tonic-gate xfree(chost); 1537*0Sstevel@tonic-gate xfree(pkalg); 1538*0Sstevel@tonic-gate 1539*0Sstevel@tonic-gate packet_send(); 1540*0Sstevel@tonic-gate return 1; 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate 1543*0Sstevel@tonic-gate /* find auth method */ 1544*0Sstevel@tonic-gate 1545*0Sstevel@tonic-gate /* 1546*0Sstevel@tonic-gate * given auth method name, if configurable options permit this method fill 1547*0Sstevel@tonic-gate * in auth_ident field and return true, otherwise return false. 1548*0Sstevel@tonic-gate */ 1549*0Sstevel@tonic-gate static int 1550*0Sstevel@tonic-gate authmethod_is_enabled(Authmethod *method) 1551*0Sstevel@tonic-gate { 1552*0Sstevel@tonic-gate if (method == NULL) 1553*0Sstevel@tonic-gate return 0; 1554*0Sstevel@tonic-gate /* return false if options indicate this method is disabled */ 1555*0Sstevel@tonic-gate if (method->enabled == NULL || *method->enabled == 0) 1556*0Sstevel@tonic-gate return 0; 1557*0Sstevel@tonic-gate /* return false if batch mode is enabled but method needs interactive mode */ 1558*0Sstevel@tonic-gate if (method->batch_flag != NULL && *method->batch_flag != 0) 1559*0Sstevel@tonic-gate return 0; 1560*0Sstevel@tonic-gate return 1; 1561*0Sstevel@tonic-gate } 1562*0Sstevel@tonic-gate 1563*0Sstevel@tonic-gate static Authmethod * 1564*0Sstevel@tonic-gate authmethod_lookup(const char *name) 1565*0Sstevel@tonic-gate { 1566*0Sstevel@tonic-gate Authmethod *method = NULL; 1567*0Sstevel@tonic-gate if (name != NULL) { 1568*0Sstevel@tonic-gate for (method = authmethods; method->name != NULL; method++) { 1569*0Sstevel@tonic-gate if (strcmp(name, method->name) == 0) 1570*0Sstevel@tonic-gate return method; 1571*0Sstevel@tonic-gate } 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); 1574*0Sstevel@tonic-gate return NULL; 1575*0Sstevel@tonic-gate } 1576*0Sstevel@tonic-gate 1577*0Sstevel@tonic-gate /* XXX internal state */ 1578*0Sstevel@tonic-gate static Authmethod *current = NULL; 1579*0Sstevel@tonic-gate static char *supported = NULL; 1580*0Sstevel@tonic-gate static char *preferred = NULL; 1581*0Sstevel@tonic-gate 1582*0Sstevel@tonic-gate /* 1583*0Sstevel@tonic-gate * Given the authentication method list sent by the server, return the 1584*0Sstevel@tonic-gate * next method we should try. If the server initially sends a nil list, 1585*0Sstevel@tonic-gate * use a built-in default list. 1586*0Sstevel@tonic-gate */ 1587*0Sstevel@tonic-gate static Authmethod * 1588*0Sstevel@tonic-gate authmethod_get(char *authlist) 1589*0Sstevel@tonic-gate { 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gate char *name = NULL; 1592*0Sstevel@tonic-gate u_int next; 1593*0Sstevel@tonic-gate 1594*0Sstevel@tonic-gate /* Use a suitable default if we're passed a nil list. */ 1595*0Sstevel@tonic-gate if (authlist == NULL || strlen(authlist) == 0) 1596*0Sstevel@tonic-gate authlist = options.preferred_authentications; 1597*0Sstevel@tonic-gate 1598*0Sstevel@tonic-gate if (supported == NULL || strcmp(authlist, supported) != 0) { 1599*0Sstevel@tonic-gate debug3("start over, passed a different list %s", authlist); 1600*0Sstevel@tonic-gate if (supported != NULL) 1601*0Sstevel@tonic-gate xfree(supported); 1602*0Sstevel@tonic-gate supported = xstrdup(authlist); 1603*0Sstevel@tonic-gate preferred = options.preferred_authentications; 1604*0Sstevel@tonic-gate debug3("preferred %s", preferred); 1605*0Sstevel@tonic-gate current = NULL; 1606*0Sstevel@tonic-gate } else if (current != NULL && authmethod_is_enabled(current)) 1607*0Sstevel@tonic-gate return current; 1608*0Sstevel@tonic-gate 1609*0Sstevel@tonic-gate for (;;) { 1610*0Sstevel@tonic-gate if ((name = match_list(preferred, supported, &next)) == NULL) { 1611*0Sstevel@tonic-gate debug("No more authentication methods to try."); 1612*0Sstevel@tonic-gate current = NULL; 1613*0Sstevel@tonic-gate return NULL; 1614*0Sstevel@tonic-gate } 1615*0Sstevel@tonic-gate preferred += next; 1616*0Sstevel@tonic-gate debug3("authmethod_lookup %s", name); 1617*0Sstevel@tonic-gate debug3("remaining preferred: %s", preferred); 1618*0Sstevel@tonic-gate if ((current = authmethod_lookup(name)) != NULL && 1619*0Sstevel@tonic-gate authmethod_is_enabled(current)) { 1620*0Sstevel@tonic-gate debug3("authmethod_is_enabled %s", name); 1621*0Sstevel@tonic-gate debug("Next authentication method: %s", name); 1622*0Sstevel@tonic-gate return current; 1623*0Sstevel@tonic-gate } 1624*0Sstevel@tonic-gate } 1625*0Sstevel@tonic-gate } 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate static char * 1628*0Sstevel@tonic-gate authmethods_get(void) 1629*0Sstevel@tonic-gate { 1630*0Sstevel@tonic-gate Authmethod *method = NULL; 1631*0Sstevel@tonic-gate Buffer b; 1632*0Sstevel@tonic-gate char *list; 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gate buffer_init(&b); 1635*0Sstevel@tonic-gate for (method = authmethods; method->name != NULL; method++) { 1636*0Sstevel@tonic-gate if (authmethod_is_enabled(method)) { 1637*0Sstevel@tonic-gate if (buffer_len(&b) > 0) 1638*0Sstevel@tonic-gate buffer_append(&b, ",", 1); 1639*0Sstevel@tonic-gate buffer_append(&b, method->name, strlen(method->name)); 1640*0Sstevel@tonic-gate } 1641*0Sstevel@tonic-gate } 1642*0Sstevel@tonic-gate buffer_append(&b, "\0", 1); 1643*0Sstevel@tonic-gate list = xstrdup(buffer_ptr(&b)); 1644*0Sstevel@tonic-gate buffer_free(&b); 1645*0Sstevel@tonic-gate return list; 1646*0Sstevel@tonic-gate } 1647