X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/44a053a3174c2aaef640d35350c460003288be99..HEAD:/openssh/auth2.c diff --git a/openssh/auth2.c b/openssh/auth2.c index e40a8da..f4ab7f4 100644 --- a/openssh/auth2.c +++ b/openssh/auth2.c @@ -1,3 +1,4 @@ +/* $OpenBSD: auth2.c,v 1.121 2009/06/22 05:39:28 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -23,56 +24,72 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth2.c,v 1.93 2002/05/31 11:35:15 markus Exp $"); -#include "ssh2.h" -#include "ssh1.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "atomicio.h" #include "xmalloc.h" +#include "ssh2.h" #include "packet.h" #include "log.h" +#include "buffer.h" #include "servconf.h" #include "compat.h" +#include "key.h" +#include "hostfile.h" #include "auth.h" #include "dispatch.h" #include "pathnames.h" -#include "monitor_wrap.h" -#include "misc.h" +#include "buffer.h" +#include "canohost.h" #ifdef GSSAPI #include "ssh-gss.h" -#ifdef GSI -#include "globus_gss_assist.h" -char* olduser; -int changeuser = 0; -#endif #endif +#include "monitor_wrap.h" /* import */ extern ServerOptions options; extern u_char *session_id2; -extern int session_id2_len; - -Authctxt *x_authctxt = NULL; +extern u_int session_id2_len; +extern Buffer loginmsg; /* methods */ extern Authmethod method_none; -#ifdef GSSAPI -extern Authmethod method_external; -extern Authmethod method_gssapi; -#endif extern Authmethod method_pubkey; extern Authmethod method_passwd; extern Authmethod method_kbdint; extern Authmethod method_hostbased; +#ifdef GSSAPI +extern Authmethod method_gsskeyex; +extern Authmethod method_gssapi; +#endif +#ifdef JPAKE +extern Authmethod method_jpake; +#endif + +static int log_flag = 0; + Authmethod *authmethods[] = { &method_none, + &method_pubkey, #ifdef GSSAPI - &method_external, + &method_gsskeyex, &method_gssapi, #endif - &method_pubkey, +#ifdef JPAKE + &method_jpake, +#endif &method_passwd, &method_kbdint, &method_hostbased, @@ -87,41 +104,90 @@ static void input_userauth_request(int, u_int32_t, void *); /* helper */ static Authmethod *authmethod_lookup(const char *); static char *authmethods_get(void); -int user_key_allowed(struct passwd *, Key *); -int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); -/* - * loop until authctxt->success == TRUE - */ +char * +auth2_read_banner(void) +{ + struct stat st; + char *banner = NULL; + size_t len, n; + int fd; + + if ((fd = open(options.banner, O_RDONLY)) == -1) + return (NULL); + if (fstat(fd, &st) == -1) { + close(fd); + return (NULL); + } + if (st.st_size > 1*1024*1024) { + close(fd); + return (NULL); + } + + len = (size_t)st.st_size; /* truncate */ + banner = xmalloc(len + 1); + n = atomicio(read, fd, banner, len); + close(fd); -Authctxt * -do_authentication2(void) + if (n != len) { + xfree(banner); + return (NULL); + } + banner[n] = '\0'; + + return (banner); +} + +void +userauth_send_banner(const char *msg) { - Authctxt *authctxt = authctxt_new(); + if (datafellows & SSH_BUG_BANNER) + return; - x_authctxt = authctxt; /*XXX*/ + packet_start(SSH2_MSG_USERAUTH_BANNER); + packet_put_cstring(msg); + packet_put_cstring(""); /* language, unused */ + packet_send(); + debug("%s: sent", __func__); +} + +static void +userauth_banner(void) +{ + char *banner = NULL; + + if (options.banner == NULL || + strcasecmp(options.banner, "none") == 0 || + (datafellows & SSH_BUG_BANNER) != 0) + return; + + if ((banner = PRIVSEP(auth2_read_banner())) == NULL) + goto done; + userauth_send_banner(banner); - /* challenge-response is implemented via keyboard interactive */ - if (options.challenge_response_authentication) - options.kbd_interactive_authentication = 1; - if (options.pam_authentication_via_kbd_int) - options.kbd_interactive_authentication = 1; - if (use_privsep) - options.pam_authentication_via_kbd_int = 0; +done: + if (banner) + xfree(banner); +} +/* + * loop until authctxt->success == TRUE + */ +void +do_authentication2(Authctxt *authctxt) +{ dispatch_init(&dispatch_protocol_error); dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); - - return (authctxt); } +/*ARGSUSED*/ static void input_service_request(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; u_int len; - int accept = 0; + int acceptit = 0; char *service = packet_get_string(&len); packet_check_eom(); @@ -130,14 +196,14 @@ input_service_request(int type, u_int32_t seq, void *ctxt) if (strcmp(service, "ssh-userauth") == 0) { if (!authctxt->success) { - accept = 1; + acceptit = 1; /* now we can handle user-auth requests */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); } } /* XXX all other service requests are denied */ - if (accept) { + if (acceptit) { packet_start(SSH2_MSG_SERVICE_ACCEPT); packet_put_cstring(service); packet_send(); @@ -149,6 +215,7 @@ input_service_request(int type, u_int32_t seq, void *ctxt) xfree(service); } +/*ARGSUSED*/ static void input_userauth_request(int type, u_int32_t seq, void *ctxt) { @@ -165,92 +232,111 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) method = packet_get_string(NULL); #ifdef GSSAPI -#ifdef GSI - if(changeuser == 0 && (strcmp(method,"external-keyx") == 0 || strcmp(method,"gssapi") ==0) && strcmp(user,"") == 0) { - char *gridmapped_name = NULL; - struct passwd *pw = NULL; - if(globus_gss_assist_gridmap(gssapi_client_name.value, - &gridmapped_name) == 0) { - user = gridmapped_name; - debug("I gridmapped and got %s", user); - pw = getpwnam(user); - if (pw && allowed_user(pw)) { - olduser = authctxt->user; - authctxt->user = xstrdup(user); - authctxt->pw = pwcopy(pw); - authctxt->valid = 1; - changeuser = 1; - } - - } else { - debug("I gridmapped and got null, reverting to %s", - authctxt->user); + if (user[0] == '\0') { + debug("received empty username for %s", method); + if (strcmp(method, "gssapi-keyex") == 0) { + char *lname = NULL; + PRIVSEP(ssh_gssapi_localname(&lname)); + if (lname && lname[0] != '\0') { xfree(user); - user = xstrdup(authctxt->user); - } - } - else if(changeuser) { - struct passwd *pw = NULL; - pw = getpwnam(user); - if (pw && allowed_user(pw)) { - xfree(authctxt->user); - authctxt->user = olduser; - authctxt->pw = pwcopy(pw); - authctxt->valid = 1; - changeuser = 0; - } - } - -#endif /* GSI */ -#endif /* GSSAPI */ + user = lname; + debug("set username to %s from gssapi context", user); + } else { + debug("failed to set username from gssapi context"); + packet_send_debug("failed to set username from gssapi context"); + } + } + } +#endif - debug("userauth-request for user %s service %s method %s", user, service, method); + debug("userauth-request for user %s service %s method %s", + user[0] ? user : "", service, method); + if (!log_flag) { + logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", + get_remote_ipaddr(), get_remote_port(), + user[0] ? user : ""); + log_flag = 1; + } debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); if ((style = strchr(user, ':')) != NULL) *style++ = 0; - if (authctxt->attempt++ == 0) { - /* setup auth context */ + /* If first time or username changed or empty username, + setup/reset authentication context. */ + if ((authctxt->attempt++ == 0) || + (strcmp(user, authctxt->user) != 0) || + (strcmp(user, "") == 0)) { + if (authctxt->user) { + xfree(authctxt->user); + authctxt->user = NULL; + } + authctxt->valid = 0; + authctxt->user = xstrdup(user); + if (strcmp(service, "ssh-connection") != 0) { + packet_disconnect("Unsupported service %s", service); + } +#ifdef GSSAPI + /* If we're going to set the username based on the + GSSAPI context later, then wait until then to + verify it. Just put in placeholders for now. */ + if ((strcmp(user, "") == 0) && + ((strcmp(method, "gssapi") == 0) || + (strcmp(method, "gssapi-with-mic") == 0))) { + authctxt->pw = fakepw(); + } else { +#endif authctxt->pw = PRIVSEP(getpwnamallow(user)); - if (authctxt->pw && strcmp(service, "ssh-connection")==0) { + if (authctxt->pw) { authctxt->valid = 1; debug2("input_userauth_request: setting up authctxt for %s", user); -#ifdef USE_PAM - PRIVSEP(start_pam(authctxt->pw->pw_name)); -#endif } else { - log("input_userauth_request: illegal user %s", user); -#ifdef USE_PAM - PRIVSEP(start_pam("NOUSER")); + logit("input_userauth_request: invalid user %s", user); + authctxt->pw = fakepw(); +#ifdef SSH_AUDIT_EVENTS + PRIVSEP(audit_event(SSH_INVALID_USER)); #endif } - setproctitle("%s%s", authctxt->pw ? user : "unknown", +#ifdef GSSAPI + } /* endif for setting username based on GSSAPI context */ +#endif +#ifdef USE_PAM + if (options.use_pam) + PRIVSEP(start_pam(authctxt)); +#endif + setproctitle("%s%s", authctxt->valid ? user : "unknown", use_privsep ? " [net]" : ""); - authctxt->user = xstrdup(user); - authctxt->service = xstrdup(service); - authctxt->style = style ? xstrdup(style) : NULL; - if (use_privsep) - mm_inform_authserv(service, style); - } else if (strcmp(user, authctxt->user) != 0 || - strcmp(service, authctxt->service) != 0) { - packet_disconnect("Change of username or service not allowed: " + if (authctxt->attempt == 1) { + authctxt->service = xstrdup(service); + authctxt->style = style ? xstrdup(style) : NULL; + if (use_privsep) + mm_inform_authserv(service, style); + userauth_banner(); + } + } + if (strcmp(service, authctxt->service) != 0) { + packet_disconnect("Change of service not allowed: " "(%s,%s) -> (%s,%s)", authctxt->user, authctxt->service, user, service); } /* reset state */ auth2_challenge_stop(authctxt); +#ifdef JPAKE + auth2_jpake_stop(authctxt); +#endif #ifdef GSSAPI + /* XXX move to auth2_gssapi_stop() */ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); #endif authctxt->postponed = 0; + authctxt->server_caused_failure = 0; /* try to authenticate user */ m = authmethod_lookup(method); - if (m != NULL) { + if (m != NULL && authctxt->failures < options.max_authtries) { debug2("input_userauth_request: try method %s", method); authenticated = m->userauth(authctxt); } @@ -272,19 +358,36 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method) /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && - !auth_root_allowed(method)) + !auth_root_allowed(method)) { authenticated = 0; +#ifdef SSH_AUDIT_EVENTS + PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); +#endif + } #ifdef USE_PAM - if (!use_privsep && authenticated && authctxt->user && - !do_pam_account(authctxt->user, NULL)) + if (options.use_pam && authenticated) { + if (!PRIVSEP(do_pam_account())) { + /* if PAM returned a message, send it to the user */ + if (buffer_len(&loginmsg) > 0) { + buffer_append(&loginmsg, "\0", 1); + userauth_send_banner(buffer_ptr(&loginmsg)); + packet_write_wait(); + } + fatal("Access denied for user %s by PAM account " + "configuration", authctxt->user); + } + } +#endif + +#ifdef _UNICOS + if (authenticated && cray_access_denied(authctxt->user)) { authenticated = 0; -#endif /* USE_PAM */ + fatal("Access denied for user %s.",authctxt->user); + } +#endif /* _UNICOS */ /* Log before sending the reply */ - if (!compat20) - auth_log(authctxt, authenticated, method, " ssh1"); - else auth_log(authctxt, authenticated, method, " ssh2"); if (authctxt->postponed) @@ -294,34 +397,23 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method) if (authenticated == 1) { /* turn off userauth */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); - if (!compat20) - packet_start(SSH_SMSG_SUCCESS); - else packet_start(SSH2_MSG_USERAUTH_SUCCESS); packet_send(); packet_write_wait(); /* now we can break out */ authctxt->success = 1; } else { - if (authctxt->failures++ > AUTH_FAIL_MAX) { -#ifdef WITH_AIXAUTHENTICATE - /* XXX: privsep */ - loginfailed(authctxt->user, - get_canonical_hostname(options.verify_reverse_mapping), - "ssh"); -#endif /* WITH_AIXAUTHENTICATE */ + /* Dont count server configuration issues against the client */ + /* Allow initial try of "none" auth without failure penalty */ + if (!authctxt->server_caused_failure && + (authctxt->attempt > 1 || strcmp(method, "none") != 0)) + authctxt->failures++; + 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); } - if (!compat20) { - /* - * Break out of the dispatch loop now and go back to - * SSH1 code. We need to set the 'success' flag to - * break out of the loop. Set the 'postponed' flag to - * tell the SSH1 code that authentication failed. The - * SSH1 code will handle sending SSH_SMSG_FAILURE. - */ - authctxt->success = authctxt->postponed = 1; - } else { methods = authmethods_get(); packet_start(SSH2_MSG_USERAUTH_FAILURE); packet_put_cstring(methods); @@ -329,20 +421,9 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method) packet_send(); packet_write_wait(); xfree(methods); - } } } -/* get current user */ - -struct passwd* -auth_get_user(void) -{ - return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; -} - -#define DELIM "," - static char * authmethods_get(void) { @@ -383,3 +464,4 @@ authmethod_lookup(const char *name) name ? name : "NULL"); return NULL; } +