X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/700318f39b6ee399768d0ed0ee2b2935410c8b0b..b5afdff53b51d529e596da3b4c2aa5ee14cc8b08:/openssh/auth1.c diff --git a/openssh/auth1.c b/openssh/auth1.c index 1f6fcb2..1801661 100644 --- a/openssh/auth1.c +++ b/openssh/auth1.c @@ -1,3 +1,4 @@ +/* $OpenBSD: auth1.c,v 1.73 2008/07/04 23:30:16 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -10,52 +11,221 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth1.c,v 1.40 2002/04/10 08:21:47 markus Exp $"); +#include + +#include +#include +#include +#include +#include + +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "rsa.h" #include "ssh1.h" #include "packet.h" #include "buffer.h" -#include "mpaux.h" #include "log.h" #include "servconf.h" #include "compat.h" +#include "key.h" +#include "hostfile.h" #include "auth.h" #include "channels.h" #include "session.h" #include "uidswap.h" +#ifdef GSSAPI +#include "ssh-gss.h" +#endif #include "monitor_wrap.h" +#include "buffer.h" /* import */ extern ServerOptions options; +extern Buffer loginmsg; + +static int auth1_process_password(Authctxt *, char *, size_t); +static int auth1_process_rsa(Authctxt *, char *, size_t); +static int auth1_process_rhosts_rsa(Authctxt *, char *, size_t); +static int auth1_process_tis_challenge(Authctxt *, char *, size_t); +static int auth1_process_tis_response(Authctxt *, char *, size_t); + +static char *client_user = NULL; /* Used to fill in remote user for PAM */ + +struct AuthMethod1 { + int type; + char *name; + int *enabled; + int (*method)(Authctxt *, char *, size_t); +}; + +const struct AuthMethod1 auth1_methods[] = { + { + SSH_CMSG_AUTH_PASSWORD, "password", + &options.password_authentication, auth1_process_password + }, + { + SSH_CMSG_AUTH_RSA, "rsa", + &options.rsa_authentication, auth1_process_rsa + }, + { + SSH_CMSG_AUTH_RHOSTS_RSA, "rhosts-rsa", + &options.rhosts_rsa_authentication, auth1_process_rhosts_rsa + }, + { + SSH_CMSG_AUTH_TIS, "challenge-response", + &options.challenge_response_authentication, + auth1_process_tis_challenge + }, + { + SSH_CMSG_AUTH_TIS_RESPONSE, "challenge-response", + &options.challenge_response_authentication, + auth1_process_tis_response + }, + { -1, NULL, NULL, NULL} +}; + +static const struct AuthMethod1 +*lookup_authmethod1(int type) +{ + int i; + + for (i = 0; auth1_methods[i].name != NULL; i++) + if (auth1_methods[i].type == type) + return (&(auth1_methods[i])); + + return (NULL); +} -/* - * convert ssh auth msg type into description - */ static char * get_authname(int type) { - static char buf[1024]; - switch (type) { - case SSH_CMSG_AUTH_PASSWORD: - return "password"; - case SSH_CMSG_AUTH_RSA: - return "rsa"; - case SSH_CMSG_AUTH_RHOSTS_RSA: - return "rhosts-rsa"; - case SSH_CMSG_AUTH_RHOSTS: - return "rhosts"; - case SSH_CMSG_AUTH_TIS: - case SSH_CMSG_AUTH_TIS_RESPONSE: - return "challenge-response"; -#if defined(KRB4) || defined(KRB5) - case SSH_CMSG_AUTH_KERBEROS: - return "kerberos"; -#endif + const struct AuthMethod1 *a; + static char buf[64]; + + if ((a = lookup_authmethod1(type)) != NULL) + return (a->name); + snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type); + return (buf); +} + +/*ARGSUSED*/ +static int +auth1_process_password(Authctxt *authctxt, char *info, size_t infolen) +{ + int authenticated = 0; + char *password; + u_int dlen; + + /* + * Read user password. It is in plain text, but was + * transmitted over the encrypted channel so it is + * not visible to an outside observer. + */ + password = packet_get_string(&dlen); + packet_check_eom(); + + /* Try authentication with the password. */ + authenticated = PRIVSEP(auth_password(authctxt, password)); + + memset(password, 0, dlen); + xfree(password); + + return (authenticated); +} + +/*ARGSUSED*/ +static int +auth1_process_rsa(Authctxt *authctxt, char *info, size_t infolen) +{ + int authenticated = 0; + BIGNUM *n; + + /* RSA authentication requested. */ + if ((n = BN_new()) == NULL) + fatal("do_authloop: BN_new failed"); + packet_get_bignum(n); + packet_check_eom(); + authenticated = auth_rsa(authctxt, n); + BN_clear_free(n); + + return (authenticated); +} + +/*ARGSUSED*/ +static int +auth1_process_rhosts_rsa(Authctxt *authctxt, char *info, size_t infolen) +{ + int keybits, authenticated = 0; + u_int bits; + Key *client_host_key; + u_int ulen; + + /* + * Get client user name. Note that we just have to + * trust the client; root on the client machine can + * claim to be any user. + */ + client_user = packet_get_string(&ulen); + + /* Get the client host key. */ + client_host_key = key_new(KEY_RSA1); + bits = packet_get_int(); + packet_get_bignum(client_host_key->rsa->e); + packet_get_bignum(client_host_key->rsa->n); + + keybits = BN_num_bits(client_host_key->rsa->n); + if (keybits < 0 || bits != (u_int)keybits) { + verbose("Warning: keysize mismatch for client_host_key: " + "actual %d, announced %d", + BN_num_bits(client_host_key->rsa->n), bits); } - snprintf(buf, sizeof buf, "bad-auth-msg-%d", type); - return buf; + packet_check_eom(); + + authenticated = auth_rhosts_rsa(authctxt, client_user, + client_host_key); + key_free(client_host_key); + + snprintf(info, infolen, " ruser %.100s", client_user); + + return (authenticated); +} + +/*ARGSUSED*/ +static int +auth1_process_tis_challenge(Authctxt *authctxt, char *info, size_t infolen) +{ + char *challenge; + + if ((challenge = get_challenge(authctxt)) == NULL) + return (0); + + debug("sending challenge '%s'", challenge); + packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); + packet_put_cstring(challenge); + xfree(challenge); + packet_send(); + packet_write_wait(); + + return (-1); +} + +/*ARGSUSED*/ +static int +auth1_process_tis_response(Authctxt *authctxt, char *info, size_t infolen) +{ + int authenticated = 0; + char *response; + u_int dlen; + + response = packet_get_string(&dlen); + packet_check_eom(); + authenticated = verify_response(authctxt, response); + memset(response, 'r', dlen); + xfree(response); + + return (authenticated); } /* @@ -66,27 +236,26 @@ static void do_authloop(Authctxt *authctxt) { int authenticated = 0; - u_int bits; - Key *client_host_key; - BIGNUM *n; - char *client_user, *password; char info[1024]; - u_int dlen; - u_int ulen; - int type = 0; - struct passwd *pw = authctxt->pw; + int prev = 0, type = 0; + const struct AuthMethod1 *meth; debug("Attempting authentication for %s%.100s.", - authctxt->valid ? "" : "illegal user ", authctxt->user); + authctxt->valid ? "" : "invalid user ", authctxt->user); /* If the user has no password, accept authentication immediately. */ if (options.password_authentication && -#if defined(KRB4) || defined(KRB5) +#ifdef KRB5 (!options.kerberos_authentication || options.kerberos_or_local_passwd) && #endif PRIVSEP(auth_password(authctxt, ""))) { - auth_log(authctxt, 1, "without authentication", ""); - return; +#ifdef USE_PAM + if (options.use_pam && (PRIVSEP(do_pam_account()))) +#endif + { + auth_log(authctxt, 1, "without authentication", ""); + return; + } } /* Indicate that authentication is needed. */ @@ -94,8 +263,6 @@ do_authloop(Authctxt *authctxt) packet_send(); packet_write_wait(); - client_user = NULL; - for (;;) { /* default to fail */ authenticated = 0; @@ -103,185 +270,37 @@ do_authloop(Authctxt *authctxt) info[0] = '\0'; /* Get a packet from the client. */ + prev = type; type = packet_read(); - /* Process the packet. */ - switch (type) { - -#if defined(KRB4) || defined(KRB5) - case SSH_CMSG_AUTH_KERBEROS: - if (!options.kerberos_authentication) { - verbose("Kerberos authentication disabled."); - } else { - char *kdata = packet_get_string(&dlen); - packet_check_eom(); - - if (kdata[0] == 4) { /* KRB_PROT_VERSION */ -#ifdef KRB4 - KTEXT_ST tkt; - - tkt.length = dlen; - if (tkt.length < MAX_KTXT_LEN) - memcpy(tkt.dat, kdata, tkt.length); - - if (auth_krb4(authctxt, &tkt, &client_user)) { - authenticated = 1; - snprintf(info, sizeof(info), - " tktuser %.100s", - client_user); - } -#endif /* KRB4 */ - } else { -#ifdef KRB5 - krb5_data tkt; - tkt.length = dlen; - tkt.data = kdata; - - if (auth_krb5(authctxt, &tkt, &client_user)) { - authenticated = 1; - snprintf(info, sizeof(info), - " tktuser %.100s", - client_user); - } -#endif /* KRB5 */ - } - xfree(kdata); - } - break; -#endif /* KRB4 || KRB5 */ - -#if defined(AFS) || defined(KRB5) - /* XXX - punt on backward compatibility here. */ - case SSH_CMSG_HAVE_KERBEROS_TGT: - packet_send_debug("Kerberos TGT passing disabled before authentication."); - break; -#ifdef AFS - case SSH_CMSG_HAVE_AFS_TOKEN: - packet_send_debug("AFS token passing disabled before authentication."); - break; -#endif /* AFS */ -#endif /* AFS || KRB5 */ - - case SSH_CMSG_AUTH_RHOSTS: - if (!options.rhosts_authentication) { - verbose("Rhosts authentication disabled."); - break; - } - /* - * Get client user name. Note that we just have to - * trust the client; this is one reason why rhosts - * authentication is insecure. (Another is - * IP-spoofing on a local network.) - */ - client_user = packet_get_string(&ulen); - packet_check_eom(); - - /* Try to authenticate using /etc/hosts.equiv and .rhosts. */ - authenticated = auth_rhosts(pw, client_user); - - snprintf(info, sizeof info, " ruser %.100s", client_user); - break; - - case SSH_CMSG_AUTH_RHOSTS_RSA: - if (!options.rhosts_rsa_authentication) { - verbose("Rhosts with RSA authentication disabled."); - break; - } - /* - * Get client user name. Note that we just have to - * trust the client; root on the client machine can - * claim to be any user. - */ - client_user = packet_get_string(&ulen); - - /* Get the client host key. */ - client_host_key = key_new(KEY_RSA1); - bits = packet_get_int(); - packet_get_bignum(client_host_key->rsa->e); - packet_get_bignum(client_host_key->rsa->n); - - if (bits != BN_num_bits(client_host_key->rsa->n)) - verbose("Warning: keysize mismatch for client_host_key: " - "actual %d, announced %d", - BN_num_bits(client_host_key->rsa->n), bits); - packet_check_eom(); - - authenticated = auth_rhosts_rsa(pw, client_user, - client_host_key); - key_free(client_host_key); - - snprintf(info, sizeof info, " ruser %.100s", client_user); - break; - - case SSH_CMSG_AUTH_RSA: - if (!options.rsa_authentication) { - verbose("RSA authentication disabled."); - break; - } - /* RSA authentication requested. */ - if ((n = BN_new()) == NULL) - fatal("do_authloop: BN_new failed"); - packet_get_bignum(n); - packet_check_eom(); - authenticated = auth_rsa(pw, n); - BN_clear_free(n); - break; - - case SSH_CMSG_AUTH_PASSWORD: - if (!options.password_authentication) { - verbose("Password authentication disabled."); - break; - } - /* - * Read user password. It is in plain text, but was - * transmitted over the encrypted channel so it is - * not visible to an outside observer. - */ - password = packet_get_string(&dlen); - packet_check_eom(); - - /* Try authentication with the password. */ - authenticated = PRIVSEP(auth_password(authctxt, password)); - - memset(password, 0, strlen(password)); - xfree(password); - break; - - case SSH_CMSG_AUTH_TIS: - debug("rcvd SSH_CMSG_AUTH_TIS"); - if (options.challenge_response_authentication == 1) { - char *challenge = get_challenge(authctxt); - if (challenge != NULL) { - debug("sending challenge '%s'", challenge); - packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); - packet_put_cstring(challenge); - xfree(challenge); - packet_send(); - packet_write_wait(); - continue; - } - } - break; - case SSH_CMSG_AUTH_TIS_RESPONSE: - debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE"); - if (options.challenge_response_authentication == 1) { - char *response = packet_get_string(&dlen); - debug("got response '%s'", response); - packet_check_eom(); - authenticated = verify_response(authctxt, response); - memset(response, 'r', dlen); - xfree(response); - } - break; - - default: - /* - * Any unknown messages will be ignored (and failure - * returned) during authentication. - */ - log("Unknown message during authentication: type %d", type); - break; + /* + * If we started challenge-response authentication but the + * next packet is not a response to our challenge, release + * the resources allocated by get_challenge() (which would + * normally have been released by verify_response() had we + * received such a response) + */ + if (prev == SSH_CMSG_AUTH_TIS && + type != SSH_CMSG_AUTH_TIS_RESPONSE) + abandon_challenge_response(authctxt); + + if (authctxt->failures >= options.max_authtries) + goto skip; + if ((meth = lookup_authmethod1(type)) == NULL) { + logit("Unknown message during authentication: " + "type %d", type); + goto skip; + } + + if (!*(meth->enabled)) { + verbose("%s authentication disabled.", meth->name); + goto skip; } + + authenticated = meth->method(authctxt, info, sizeof(info)); + if (authenticated == -1) + continue; /* "postponed" */ + #ifdef BSD_AUTH if (authctxt->as) { auth_close(authctxt->as); @@ -292,25 +311,46 @@ do_authloop(Authctxt *authctxt) fatal("INTERNAL ERROR: authenticated invalid user %s", authctxt->user); -#ifdef HAVE_CYGWIN - if (authenticated && - !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, pw)) { - packet_disconnect("Authentication rejected for uid %d.", - pw == NULL ? -1 : pw->pw_uid); +#ifdef _UNICOS + if (authenticated && cray_access_denied(authctxt->user)) { authenticated = 0; + fatal("Access denied for user %s.",authctxt->user); } -#else +#endif /* _UNICOS */ + +#ifndef HAVE_CYGWIN /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && - !auth_root_allowed(get_authname(type))) - authenticated = 0; + !auth_root_allowed(meth->name)) { + authenticated = 0; +# ifdef SSH_AUDIT_EVENTS + PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); +# endif + } #endif + #ifdef USE_PAM - if (!use_privsep && authenticated && - !do_pam_account(pw->pw_name, client_user)) - authenticated = 0; + if (options.use_pam && authenticated && + !PRIVSEP(do_pam_account())) { + char *msg; + size_t len; + + error("Access denied for user %s by PAM account " + "configuration", authctxt->user); + len = buffer_len(&loginmsg); + buffer_append(&loginmsg, "\0", 1); + msg = buffer_ptr(&loginmsg); + /* strip trailing newlines */ + if (len > 0) + while (len > 0 && msg[--len] == '\n') + msg[len] = '\0'; + else + msg = "Access denied."; + packet_disconnect("%s", msg); + } #endif + skip: /* Log before sending the reply */ auth_log(authctxt, authenticated, get_authname(type), info); @@ -322,12 +362,10 @@ do_authloop(Authctxt *authctxt) if (authenticated) return; - if (authctxt->failures++ > AUTH_FAIL_MAX) { -#ifdef WITH_AIXAUTHENTICATE - loginfailed(authctxt->user, - get_canonical_hostname(options.verify_reverse_mapping), - "ssh"); -#endif /* WITH_AIXAUTHENTICATE */ + if (++authctxt->failures >= options.max_authtries) { +#ifdef SSH_AUDIT_EVENTS + PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); +#endif packet_disconnect(AUTH_FAIL_MSG, authctxt->user); } @@ -341,10 +379,9 @@ do_authloop(Authctxt *authctxt) * Performs authentication of an incoming connection. Session key has already * been exchanged and encryption is enabled. */ -Authctxt * -do_authentication(void) +void +do_authentication(Authctxt *authctxt) { - Authctxt *authctxt; u_int ulen; char *user, *style = NULL; @@ -358,36 +395,28 @@ do_authentication(void) if ((style = strchr(user, ':')) != NULL) *style++ = '\0'; -#ifdef KRB5 - /* XXX - SSH.com Kerberos v5 braindeath. */ - if ((datafellows & SSH_BUG_K5USER) && - options.kerberos_authentication) { - char *p; - if ((p = strchr(user, '@')) != NULL) - *p = '\0'; - } -#endif - - authctxt = authctxt_new(); authctxt->user = user; authctxt->style = style; /* Verify that the user is a valid user. */ if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) authctxt->valid = 1; - else - debug("do_authentication: illegal user %s", user); + else { + debug("do_authentication: invalid user %s", user); + authctxt->pw = fakepw(); + } - setproctitle("%s%s", authctxt->pw ? user : "unknown", + setproctitle("%s%s", authctxt->valid ? user : "unknown", use_privsep ? " [net]" : ""); #ifdef USE_PAM - PRIVSEP(start_pam(authctxt->pw == NULL ? "NOUSER" : user)); + if (options.use_pam) + PRIVSEP(start_pam(authctxt)); #endif /* * If we are not running as root, the user must have the same uid as - * the server. (Unless you are running Windows) + * the server. */ #ifndef HAVE_CYGWIN if (!use_privsep && getuid() != 0 && authctxt->pw && @@ -405,6 +434,4 @@ do_authentication(void) packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait(); - - return (authctxt); }