From: Luke Howard Date: Sun, 15 May 2011 12:01:53 +0000 (+0200) Subject: allow empty username, and determine using pname_to_uid X-Git-Url: http://www.project-moonshot.org/gitweb/?p=openssh.git;a=commitdiff_plain;h=991c385d7c6b1c8592b4057bf2e0708ddf9854e9 allow empty username, and determine using pname_to_uid fix regression in empty-user patch application --- diff --git a/auth.c b/auth.c index 33680b9..ba27ec0 100644 --- a/auth.c +++ b/auth.c @@ -275,7 +275,8 @@ auth_log(Authctxt *authctxt, int authenticated, char *method, char *info) authmsg, method, authctxt->valid ? "" : "invalid user ", - authctxt->user, + (authctxt->user && authctxt->user[0]) ? + authctxt->user : "unknown", get_remote_ipaddr(), get_remote_port(), info); @@ -587,7 +588,8 @@ getpwnamallow(const char *user) #endif if (pw == NULL) { logit("Invalid user %.100s from %.100s", - user, get_remote_ipaddr()); + (user && user[0]) ? user : "unknown", + get_remote_ipaddr()); #ifdef CUSTOM_FAILED_LOGIN record_failed_login(user, get_canonical_hostname(options.use_dns), "ssh"); diff --git a/auth2-gss.c b/auth2-gss.c index a192d28..2c77718 100644 --- a/auth2-gss.c +++ b/auth2-gss.c @@ -102,7 +102,10 @@ userauth_gssapi(Authctxt *authctxt) u_int len; u_char *doid = NULL; - if (!authctxt->valid || authctxt->user == NULL) + /* authctxt->valid may be 0 if we haven't yet determined + username from gssapi context. */ + + if (authctxt->user == NULL) return (0); mechs = packet_get_int(); @@ -253,6 +256,32 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) gss_release_buffer(&maj_status, &send_tok); } +static void +gssapi_set_username(Authctxt *authctxt) +{ + char *lname = NULL; + + if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) { + PRIVSEP(ssh_gssapi_localname(&lname)); + if (lname && lname[0] != '\0') { + if (authctxt->user) xfree(authctxt->user); + authctxt->user = lname; + debug("set username to %s from gssapi context", lname); + authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user)); + if (authctxt->pw) { + authctxt->valid = 1; +#ifdef USE_PAM + if (options.use_pam) + PRIVSEP(start_pam(authctxt)); +#endif + } + } else { + debug("failed to set username from gssapi context"); + packet_send_debug("failed to set username from gssapi context"); + } + } +} + /* * This is called when the client thinks we've completed authentication. * It should only be enabled in the dispatch handler by the function above, @@ -313,6 +342,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) gssbuf.value = buffer_ptr(&b); gssbuf.length = buffer_len(&b); + gssapi_set_username(authctxt); + if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); diff --git a/auth2.c b/auth2.c index 3c38cdd..d3fe0b4 100644 --- a/auth2.c +++ b/auth2.c @@ -232,11 +232,32 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) 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-with-mic") == 0 || + strcmp(method, "gssapi-keyex") == 0)) { + authctxt->pw = fakepw(); + } else { +#endif authctxt->pw = PRIVSEP(getpwnamallow(user)); - authctxt->user = xstrdup(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); } else { @@ -250,15 +271,20 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) if (options.use_pam) PRIVSEP(start_pam(authctxt)); #endif +#ifdef GSSAPI + } /* endif for setting username based on GSSAPI context */ +#endif setproctitle("%s%s", authctxt->valid ? user : "unknown", use_privsep ? " [net]" : ""); - authctxt->service = xstrdup(service); - authctxt->style = style ? xstrdup(style) : NULL; - if (use_privsep) - mm_inform_authserv(service, style); - userauth_banner(); - } else if (strcmp(user, authctxt->user) != 0 || - strcmp(service, authctxt->service) != 0) { + 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 username or service not allowed: " "(%s,%s) -> (%s,%s)", authctxt->user, authctxt->service, user, service); diff --git a/gss-serv.c b/gss-serv.c index 3440a89..bb7743d 100644 --- a/gss-serv.c +++ b/gss-serv.c @@ -353,4 +353,25 @@ ssh_gssapi_userok(char *user, struct passwd *pw) return (userok); } -#endif +/* Priviledged */ +OM_uint32 +ssh_gssapi_localname(char **user) +{ + OM_uint32 major_status, lmin; + uid_t uid; + struct passwd *pw; + + major_status = gss_pname_to_uid(&lmin, gssapi_client.name, + GSS_C_NO_OID, &uid); + if (GSS_ERROR(major_status)) + return (major_status); + + pw = getpwuid(uid); + if (pw == NULL) + return (GSS_S_BAD_NAME); + + *user = xstrdup(pw->pw_name); + + return (GSS_S_COMPLETE); +} +#endif /* GSSAPI */ diff --git a/monitor.c b/monitor.c index f8a79fb..a05a4bc 100644 --- a/monitor.c +++ b/monitor.c @@ -171,6 +171,7 @@ int mm_answer_pam_free_ctx(int, Buffer *); int mm_answer_gss_setup_ctx(int, Buffer *); int mm_answer_gss_accept_ctx(int, Buffer *); int mm_answer_gss_userok(int, Buffer *); +int mm_answer_gss_localname(int, Buffer *); int mm_answer_gss_checkmic(int, Buffer *); int mm_answer_gss_sign(int, Buffer *); #endif @@ -212,12 +213,12 @@ struct mon_table { struct mon_table mon_dispatch_proto20[] = { {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, - {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow}, {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, #ifdef USE_PAM - {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, + {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start}, {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, @@ -241,6 +242,7 @@ struct mon_table mon_dispatch_proto20[] = { {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, + {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname}, {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, #endif @@ -650,13 +652,11 @@ mm_answer_pwnamallow(int sock, Buffer *m) debug3("%s", __func__); - if (authctxt->attempt++ != 0) - fatal("%s: multiple attempts for getpwnam", __func__); - username = buffer_get_string(m, NULL); pwent = getpwnamallow(username); + if (authctxt->user) xfree(authctxt->user); authctxt->user = xstrdup(username); setproctitle("%s [priv]", pwent ? username : "unknown"); xfree(username); @@ -2029,6 +2029,27 @@ mm_answer_gss_userok(int sock, Buffer *m) return (authenticated); } +int +mm_answer_gss_localname(int socket, Buffer *m) { + char *name; + + ssh_gssapi_localname(&name); + + buffer_clear(m); + if (name) { + buffer_put_cstring(m, name); + debug3("%s: sending result %s", __func__, name); + xfree(name); + } else { + buffer_put_cstring(m, ""); + debug3("%s: sending result \"\"", __func__); + } + + mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m); + + return(0); +} + int mm_answer_gss_sign(int socket, Buffer *m) { diff --git a/monitor.h b/monitor.h index aa38b16..8a34c38 100644 --- a/monitor.h +++ b/monitor.h @@ -52,6 +52,7 @@ enum monitor_reqtype { MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP, MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, + MONITOR_REQ_GSSLOCALNAME, MONITOR_ANS_GSSLOCALNAME, MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN, MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS, diff --git a/monitor_wrap.c b/monitor_wrap.c index ff1b05e..30de708 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1272,6 +1272,31 @@ mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) return(major); } +OM_uint32 +mm_ssh_gssapi_localname(char **lname) +{ + Buffer m; + OM_uint32 major; + + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m); + + debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME, &m); + + major = buffer_get_int(&m); + *lname = buffer_get_string(&m, NULL); + + if (GSS_ERROR(major)) { + debug3("%s: gssapi identity mapping failed", __func__); + } else { + debug3("%s: gssapi identity mapped to %s", __func__, *lname); + } + + buffer_free(&m); + + return(major); +} #endif /* GSSAPI */ #ifdef JPAKE diff --git a/monitor_wrap.h b/monitor_wrap.h index 7811d65..3c4be70 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h @@ -58,6 +58,7 @@ OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); int mm_ssh_gssapi_userok(char *user, struct passwd *); +OM_uint32 mm_ssh_gssapi_localname(char **user); OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); #endif diff --git a/ssh-gss.h b/ssh-gss.h index ea12a38..7b9d52d 100644 --- a/ssh-gss.h +++ b/ssh-gss.h @@ -124,6 +124,7 @@ int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, const char *); OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); int ssh_gssapi_userok(char *name, struct passwd *); +OM_uint32 ssh_gssapi_localname(char **name); OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); void ssh_gssapi_do_child(char ***, u_int *); void ssh_gssapi_cleanup_creds(void);