X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/7cac2b656d969b64094f20b40ddcaca5ac1ca924..33ffb56699279fbe303872628e5aa8c60a7a92a1:/openssh/sshconnect1.c diff --git a/openssh/sshconnect1.c b/openssh/sshconnect1.c index 8d358e1..fd07bbf 100644 --- a/openssh/sshconnect1.c +++ b/openssh/sshconnect1.c @@ -1,3 +1,4 @@ +/* $OpenBSD: sshconnect1.c,v 1.70 2006/11/06 21:25:28 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -13,41 +14,40 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.56 2003/08/28 12:54:34 markus Exp $"); + +#include +#include #include #include +#include +#include +#include +#include +#include +#include + +#include "xmalloc.h" #include "ssh.h" #include "ssh1.h" -#include "xmalloc.h" #include "rsa.h" #include "buffer.h" #include "packet.h" -#include "mpaux.h" +#include "key.h" +#include "cipher.h" +#include "kex.h" #include "uidswap.h" #include "log.h" #include "readconf.h" -#include "key.h" #include "authfd.h" #include "sshconnect.h" #include "authfile.h" -#include "readpass.h" -#include "cipher.h" +#include "misc.h" #include "canohost.h" +#include "hostfile.h" #include "auth.h" -#ifdef GSSAPI -#include "ssh-gss.h" -#include "bufaux.h" - -/* - * MD5 hash of host and session keys for verification. This is filled - * in in ssh_login() and then checked in try_gssapi_authentication(). - */ -unsigned char ssh_key_digest[16]; -#endif /* GSSAPI */ - /* Session id for the current session. */ u_char session_id[16]; u_int supported_authentications = 0; @@ -95,7 +95,7 @@ try_agent_authentication(void) /* Wait for server's response. */ type = packet_read(); - /* The server sends failure if it doesn\'t like our key or + /* The server sends failure if it doesn't like our key or does not support RSA authentication. */ if (type == SSH_SMSG_FAILURE) { debug("Server refused our key."); @@ -173,7 +173,7 @@ respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv) /* Compute the response. */ /* The response is MD5 of decrypted challenge plus session id. */ len = BN_num_bytes(challenge); - if (len <= 0 || len > sizeof(buf)) + if (len <= 0 || (u_int)len > sizeof(buf)) packet_disconnect( "respond_to_rsa_challenge: bad challenge length %d", len); @@ -208,7 +208,7 @@ try_rsa_authentication(int idx) BIGNUM *challenge; Key *public, *private; char buf[300], *passphrase, *comment, *authfile; - int i, type, quit; + int i, perm_ok = 1, type, quit; public = options.identity_keys[idx]; authfile = options.identity_files[idx]; @@ -226,8 +226,8 @@ try_rsa_authentication(int idx) type = packet_read(); /* - * The server responds with failure if it doesn\'t like our key or - * doesn\'t support RSA authentication. + * The server responds with failure if it doesn't like our key or + * doesn't support RSA authentication. */ if (type == SSH_SMSG_FAILURE) { debug("Server refused our key."); @@ -254,15 +254,16 @@ try_rsa_authentication(int idx) if (public->flags & KEY_FLAG_EXT) private = public; else - private = key_load_private_type(KEY_RSA1, authfile, "", NULL); - if (private == NULL && !options.batch_mode) { + private = key_load_private_type(KEY_RSA1, authfile, "", NULL, + &perm_ok); + if (private == NULL && !options.batch_mode && perm_ok) { snprintf(buf, sizeof(buf), "Enter passphrase for RSA key '%.100s': ", comment); for (i = 0; i < options.number_of_password_prompts; i++) { passphrase = read_passphrase(buf, 0); if (strcmp(passphrase, "") != 0) { private = key_load_private_type(KEY_RSA1, - authfile, passphrase, NULL); + authfile, passphrase, NULL, NULL); quit = 0; } else { debug2("no passphrase given, try next key"); @@ -279,7 +280,7 @@ try_rsa_authentication(int idx) xfree(comment); if (private == NULL) { - if (!options.batch_mode) + if (!options.batch_mode && perm_ok) error("Bad passphrase."); /* Send a dummy response packet to avoid protocol error. */ @@ -472,401 +473,6 @@ try_password_authentication(char *prompt) return 0; } -#ifdef GSSAPI -#ifdef GSI -static gss_OID_desc gsioid={9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"}; -char * get_gsi_name() -{ - gss_name_t pname = GSS_C_NO_NAME; - gss_buffer_desc tmpname; - gss_buffer_t tmpnamed = &tmpname; - char *retname=NULL; - gss_OID_set oidset; - gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; - Gssctxt *ctx = NULL; - - ssh_gssapi_build_ctx(&ctx); - - gss_create_empty_oid_set(&ctx->minor,&oidset); - gss_add_oid_set_member(&ctx->minor,&gsioid,&oidset); - ssh_gssapi_set_oid(ctx,&gsioid); - ctx->major = gss_acquire_cred(&ctx->minor, - GSS_C_NO_NAME, - GSS_C_INDEFINITE, - oidset, - GSS_C_INITIATE, - &gss_cred, - NULL, - NULL); - - if (ctx->major != GSS_S_COMPLETE) { - goto cleanup; - } - - debug("calling gss_inquire_cred"); - ctx->major = gss_inquire_cred(&ctx->minor, - gss_cred, - &pname, - NULL, - NULL, - NULL); - if (ctx->major != GSS_S_COMPLETE) { - goto cleanup; - } - - ctx->major = gss_display_name(&ctx->minor, - pname, - tmpnamed, - NULL); - if (ctx->major != GSS_S_COMPLETE) { - goto cleanup; - } - debug("gss_display_name finsished"); - retname = xmalloc(tmpname.length + 1); - memcpy(retname, tmpname.value, tmpname.length); - retname[tmpname.length] = '\0'; - - gss_release_name(&ctx->minor, &pname); - gss_release_buffer(&ctx->minor, tmpnamed); - - cleanup: - if (!retname) { - debug("Failed to set GSI username from credentials"); - ssh_gssapi_error(ctx); - } - if (ctx) ssh_gssapi_delete_ctx(&ctx); - return retname; -} -#endif /* GSI */ - -int try_gssapi_authentication(char *host, Options *options) -{ - char *service_name = NULL; - gss_buffer_desc name_tok; - gss_buffer_desc send_tok; - gss_buffer_desc recv_tok; - gss_buffer_desc *token_ptr; - gss_name_t target_name = NULL; - gss_ctx_id_t gss_context; - gss_OID_desc mech_oid; - gss_OID name_type; - gss_OID_set gss_mechs, my_mechs; - int my_mech_num, i; - int ret_stat = 0; /* 1 == success */ - OM_uint32 req_flags = 0; - OM_uint32 ret_flags; - int type; - char *xhost; - unsigned int slen; - Gssctxt *ctx = NULL; - - ssh_gssapi_build_ctx(&ctx); - - xhost = xstrdup(get_canonical_hostname(1)); - resolve_localhost(&xhost); - - /* - * Default flags - */ - req_flags |= GSS_C_REPLAY_FLAG; - - /* Do mutual authentication */ - req_flags |= GSS_C_MUTUAL_FLAG; - - service_name = (char *) xmalloc(strlen("host") + - strlen(xhost) + - 2 /* 1 for '@', 1 for NUL */); - - sprintf(service_name, "host@%s", xhost); - - xfree(xhost); - xhost = NULL; - - name_type = GSS_C_NT_HOSTBASED_SERVICE; - - debug("Service name is %s", service_name); - - /* Forward credentials? */ - if(options->gss_deleg_creds) { - debug("Delegating GSSAPI credentials"); - req_flags |= GSS_C_DELEG_FLAG; - } - - debug("req_flags = %u", (unsigned int)req_flags); - - name_tok.value = service_name; - name_tok.length = strlen(service_name) + 1; - ctx->major = gss_import_name(&ctx->minor, &name_tok, - name_type, &target_name); - - free(service_name); - service_name = NULL; - - if (ctx->major != GSS_S_COMPLETE) { - ssh_gssapi_error(ctx); - goto cleanup; - } - - ctx->major = gss_indicate_mechs(&ctx->minor, &gss_mechs); - - if (ctx->major != GSS_S_COMPLETE) { - ssh_gssapi_error(ctx); - goto cleanup; - } - - /* The GSSAPI supports the mechs in gss_mechs, but which ones do - we have credentials for? We only get one try, so we don't want - to propose a mechanism we know is going to fail. */ - ctx->major = gss_create_empty_oid_set(&ctx->minor, &my_mechs); - for (i=0; icount; i++) { - if (ssh_gssapi_check_mechanism(&(gss_mechs->elements[i]), host)) { - ctx->major = gss_add_oid_set_member(&ctx->minor, - &(gss_mechs->elements[i]), - &my_mechs); - } - } - - if (my_mechs->count == 0) { - debug("No GSSAPI mechanisms."); - goto cleanup; - } - - /* - * Send over a packet to the daemon, letting it know we're doing - * GSSAPI and our mech_oid(s). - */ - debug("Sending mech oid(s) to server"); - packet_start(SSH_CMSG_AUTH_GSSAPI); - packet_put_int(my_mechs->count); /* Number of mechs we're sending */ -#ifdef GSI - { - int present; - /* Send GSI before Kerberos, because if GSI fails, we can always - fall back and try regular Kerberos authentication with our - Kerberos cred. */ - ctx->major = gss_test_oid_set_member(&ctx->minor, &gsioid, - my_mechs, &present); - if (present) { - packet_put_string(gsioid.elements,gsioid.length); - } - } -#endif - for (my_mech_num = 0; my_mech_num < my_mechs->count; my_mech_num++) { -#ifdef GSI - /* Skip GSI. We already sent it above. */ - if ((my_mechs->elements[my_mech_num].length == - gsioid.length) && - memcmp(my_mechs->elements[my_mech_num].elements, - gsioid.elements, - my_mechs->elements[my_mech_num].length) == 0) { - continue; - } -#endif - packet_put_string(my_mechs->elements[my_mech_num].elements, - my_mechs->elements[my_mech_num].length); - } - packet_send(); - packet_write_wait(); - - /* - * Get reply from the daemon to see if our mech was acceptable - */ - type = packet_read(); - - switch (type) { - case SSH_SMSG_AUTH_GSSAPI_RESPONSE: - debug("Server accepted mechanism"); - /* Successful negotiation */ - break; - - case SSH_MSG_AUTH_GSSAPI_ABORT: - case SSH_SMSG_FAILURE: - debug("Unable to negotiate GSSAPI mechanism type with server"); - packet_get_all(); - goto cleanup; - - default: - packet_disconnect("Protocol error during GSSAPI authentication:" - " packet type %d received", - type); - /* Does not return */ - } - - /* Read the mechanism the server returned */ - mech_oid.elements = packet_get_string(&slen); - mech_oid.length = slen; /* safe typecast */ - packet_get_all(); - - ssh_gssapi_set_oid(ctx, &mech_oid); - - /* - * Perform the context-establishement loop. - * - * On each pass through the loop, token_ptr points to the token - * to send to the server (or GSS_C_NO_BUFFER on the first pass). - * Every generated token is stored in send_tok which is then - * transmitted to the server; every received token is stored in - * recv_tok, which token_ptr is then set to, to be processed by - * the next call to gss_init_sec_context. - * - * GSS-API guarantees that send_tok's length will be non-zero - * if and only if the server is expecting another token from us, - * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if - * and only if the server has another token to send us. - */ - - token_ptr = GSS_C_NO_BUFFER; - gss_context = GSS_C_NO_CONTEXT; - - do { - ctx->major = - gss_init_sec_context(&ctx->minor, - GSS_C_NO_CREDENTIAL, - &gss_context, - target_name, - ctx->oid, - req_flags, - 0, - NULL, /* no channel bindings */ - token_ptr, - NULL, /* ignore mech type */ - &send_tok, - &ret_flags, - NULL); /* ignore time_rec */ - - if (token_ptr != GSS_C_NO_BUFFER) - (void) gss_release_buffer(&ctx->minor, &recv_tok); - - if (ctx->major != GSS_S_COMPLETE && ctx->major != GSS_S_CONTINUE_NEEDED) { - ssh_gssapi_error(ctx); - - /* Send an abort message */ - packet_start(SSH_MSG_AUTH_GSSAPI_ABORT); - packet_send(); - packet_write_wait(); - - goto cleanup; - } - - if (send_tok.length != 0) { - debug("Sending authenticaton token..."); - packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN); - packet_put_string((char *) send_tok.value, send_tok.length); - packet_send(); - packet_write_wait(); - - (void) gss_release_buffer(&ctx->minor, &send_tok); - } - - if (ctx->major == GSS_S_CONTINUE_NEEDED) { - - debug("Continue needed. Reading response..."); - - type = packet_read(); - - switch(type) { - - case SSH_MSG_AUTH_GSSAPI_TOKEN: - /* This is what we expected */ - break; - - case SSH_MSG_AUTH_GSSAPI_ABORT: - case SSH_SMSG_FAILURE: - debug("Server aborted GSSAPI authentication."); - packet_get_all(); - goto cleanup; - - default: - packet_disconnect("Protocol error during GSSAPI authentication:" - " packet type %d received", - type); - /* Does not return */ - } - - recv_tok.value = packet_get_string(&slen); - recv_tok.length=slen; /* safe typecast */ - packet_get_all(); - token_ptr = &recv_tok; - } - } while (ctx->major == GSS_S_CONTINUE_NEEDED); - - /* Success */ - ret_stat = 1; - - debug("GSSAPI authentication successful"); - - /* - * Read hash of host and server keys and make sure it - * matches what we got earlier. - */ - debug("Reading hash of server and host keys..."); - type = packet_read(); - - if (type == SSH_MSG_AUTH_GSSAPI_ABORT || type == SSH_SMSG_FAILURE) { - debug("Server aborted GSSAPI authentication."); - packet_get_all(); - ret_stat = 0; - goto cleanup; - - } else if (type == SSH_SMSG_AUTH_GSSAPI_HASH) { - gss_buffer_desc wrapped_buf; - gss_buffer_desc unwrapped_buf; - int conf_state; - gss_qop_t qop_state; - - - wrapped_buf.value = packet_get_string(&slen); - wrapped_buf.length=slen; /* safe typecast */ - packet_get_all(); - - ctx->major = gss_unwrap(&ctx->minor, - gss_context, - &wrapped_buf, - &unwrapped_buf, - &conf_state, - &qop_state); - - if (ctx->major != GSS_S_COMPLETE) { - ssh_gssapi_error(ctx); - packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: " - "Unwrapping of hash failed."); - } - - if (unwrapped_buf.length != sizeof(ssh_key_digest)) { - packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: " - "Size of key hashes do not match (%d != %d)!", - (int)unwrapped_buf.length, - (int)sizeof(ssh_key_digest)); - } - - if (memcmp(ssh_key_digest, unwrapped_buf.value, sizeof(ssh_key_digest)) != 0) { - packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: " - "Hashes don't match!"); - } - - debug("Verified SSHD keys through GSSAPI-secured channel."); - - gss_release_buffer(&ctx->minor, &unwrapped_buf); - - } else { - packet_disconnect("Protocol error during GSSAPI authentication:" - "packet type %d received", type); - /* Does not return */ - } - - - cleanup: - if (target_name != NULL) - (void) gss_release_name(&ctx->minor, &target_name); - if (ctx) - ssh_gssapi_delete_ctx(&ctx); - - return ret_stat; -} - -#endif /* GSSAPI */ - - /* * SSH1 key exchange */ @@ -882,7 +488,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr) u_char cookie[8]; u_int supported_ciphers; u_int server_flags, client_flags; - u_int32_t rand = 0; + u_int32_t rnd = 0; debug("Waiting for server public key."); @@ -918,45 +524,6 @@ ssh_kex(char *host, struct sockaddr *hostaddr) logit("Warning: This may be due to an old implementation of ssh."); } -#ifdef GSSAPI - { - MD5_CTX md5context; - Buffer buf; - unsigned char *data; - unsigned int data_len; - - /* - * Hash the server and host keys. Later we will check them against - * a hash sent over a secure channel to make sure they are legit. - */ - debug("Calculating MD5 hash of server and host keys..."); - - /* Write all the keys to a temporary buffer */ - buffer_init(&buf); - - /* Server key */ - buffer_put_bignum(&buf, server_key->rsa->e); - buffer_put_bignum(&buf, server_key->rsa->n); - - /* Host key */ - buffer_put_bignum(&buf, host_key->rsa->e); - buffer_put_bignum(&buf, host_key->rsa->n); - - /* Get the resulting data */ - data = (unsigned char *) buffer_ptr(&buf); - data_len = buffer_len(&buf); - - /* And hash it */ - MD5_Init(&md5context); - MD5_Update(&md5context, data, data_len); - MD5_Final(ssh_key_digest, &md5context); - - /* Clean up */ - buffer_clear(&buf); - buffer_free(&buf); - } -#endif /* GSSAPI */ - /* Get protocol flags. */ server_flags = packet_get_int(); packet_set_protocol_flags(server_flags); @@ -973,7 +540,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr) client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN; - compute_session_id(session_id, cookie, host_key->rsa->n, server_key->rsa->n); + derive_ssh1_session_id(host_key->rsa->n, server_key->rsa->n, cookie, session_id); /* Generate a session key. */ arc4random_stir(); @@ -985,9 +552,9 @@ ssh_kex(char *host, struct sockaddr *hostaddr) */ for (i = 0; i < 32; i++) { if (i % 4 == 0) - rand = arc4random(); - session_key[i] = rand & 0xff; - rand >>= 8; + rnd = arc4random(); + session_key[i] = rnd & 0xff; + rnd >>= 8; } /* @@ -996,14 +563,20 @@ ssh_kex(char *host, struct sockaddr *hostaddr) * the first 16 bytes of the session id. */ if ((key = BN_new()) == NULL) - fatal("respond_to_rsa_challenge: BN_new failed"); - BN_set_word(key, 0); + fatal("ssh_kex: BN_new failed"); + if (BN_set_word(key, 0) == 0) + fatal("ssh_kex: BN_set_word failed"); for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { - BN_lshift(key, key, 8); - if (i < 16) - BN_add_word(key, session_key[i] ^ session_id[i]); - else - BN_add_word(key, session_key[i]); + if (BN_lshift(key, key, 8) == 0) + fatal("ssh_kex: BN_lshift failed"); + if (i < 16) { + if (BN_add_word(key, session_key[i] ^ session_id[i]) + == 0) + fatal("ssh_kex: BN_add_word failed"); + } else { + if (BN_add_word(key, session_key[i]) == 0) + fatal("ssh_kex: BN_add_word failed"); + } } /* @@ -1043,7 +616,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr) if (options.cipher == SSH_CIPHER_NOT_SET) { if (cipher_mask_ssh1(1) & supported_ciphers & (1 << ssh_cipher_default)) options.cipher = ssh_cipher_default; - } else if (options.cipher == SSH_CIPHER_ILLEGAL || + } else if (options.cipher == SSH_CIPHER_INVALID || !(cipher_mask_ssh1(1) & (1 << options.cipher))) { logit("No valid SSH1 cipher, using %.100s instead.", cipher_name(ssh_cipher_default)); @@ -1099,67 +672,17 @@ void ssh_userauth1(const char *local_user, const char *server_user, char *host, Sensitive *sensitive) { -#ifdef GSSAPI -#ifdef GSI - const char *save_server_user = NULL; -#endif /* GSI */ -#endif /* GSSAPI */ - int i, type; if (supported_authentications == 0) fatal("ssh_userauth1: server supports no auth methods"); -#ifdef GSSAPI -#ifdef GSI - /* if no user given, tack on the subject name after the server_user. - * This will allow us to run gridmap early to get real user - * This name will start with /C= - */ - if ((supported_authentications & (1 << SSH_AUTH_GSSAPI)) && - options.gss_authentication) { - char * retname; - char * newname; - - - save_server_user = server_user; - - retname = get_gsi_name(); - - if (retname) { - debug("passing gssapi name '%s'", retname); - if (server_user) { - newname = (char *) malloc(strlen(retname) + strlen(server_user) + 4); - if (newname) { - strcpy(newname, server_user); - if(options.implicit) { - strcat(newname,":i:"); - } else { - strcat(newname,":x:"); - } - strcat(newname, retname); - server_user = newname; - free(retname); - } - } - } - debug("server_user %s", server_user); - } -#endif /* GSI */ -#endif /* GSSAPI */ - /* Send the name of the user to log in as on the server. */ packet_start(SSH_CMSG_USER); packet_put_cstring(server_user); packet_send(); packet_write_wait(); -#if defined(GSI) - if(save_server_user) - { - server_user = save_server_user; - } -#endif /* * The server should respond with success if no authentication is * needed (the user has no password). Otherwise the server responds @@ -1173,32 +696,6 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, if (type != SSH_SMSG_FAILURE) packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", type); -#ifdef GSSAPI - /* Try GSSAPI authentication */ - if ((supported_authentications & (1 << SSH_AUTH_GSSAPI)) && - options.gss_authentication) - { - char *canonhost; - int gssapi_succeeded; - debug("Trying GSSAPI authentication..."); - canonhost = xstrdup(get_canonical_hostname(1)); - resolve_localhost(&canonhost); - gssapi_succeeded = try_gssapi_authentication(canonhost, &options); - xfree(canonhost); - canonhost=NULL; - - if (gssapi_succeeded) { - type = packet_read(); - if (type == SSH_SMSG_SUCCESS) - goto success; - if (type != SSH_SMSG_FAILURE) - packet_disconnect("Protocol error: got %d in response to GSSAPI auth", type); - } - - debug("GSSAPI authentication failed"); - } -#endif /* GSSAPI */ - /* * Try .rhosts or /etc/hosts.equiv authentication with RSA host * authentication.