allow empty username, and determine using pname_to_uid
authorLuke Howard <lukeh@padl.com>
Sun, 15 May 2011 12:01:53 +0000 (14:01 +0200)
committerLuke Howard <lukeh@padl.com>
Sun, 15 May 2011 13:53:37 +0000 (15:53 +0200)
fix regression in empty-user patch application

auth.c
auth2-gss.c
auth2.c
gss-serv.c
monitor.c
monitor.h
monitor_wrap.c
monitor_wrap.h
ssh-gss.h

diff --git a/auth.c b/auth.c
index 33680b9..ba27ec0 100644 (file)
--- 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 ",
            authmsg,
            method,
            authctxt->valid ? "" : "invalid user ",
-           authctxt->user,
+           (authctxt->user && authctxt->user[0]) ?
+               authctxt->user : "unknown",
            get_remote_ipaddr(),
            get_remote_port(),
            info);
            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",
 #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");
 #ifdef CUSTOM_FAILED_LOGIN
                record_failed_login(user,
                    get_canonical_hostname(options.use_dns), "ssh");
index a192d28..2c77718 100644 (file)
@@ -102,7 +102,10 @@ userauth_gssapi(Authctxt *authctxt)
        u_int len;
        u_char *doid = NULL;
 
        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();
                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);
 }
 
        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,
 /*
  * 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);
 
        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));
        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 (file)
--- 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 ((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->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 {
                        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
                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]" : "");
                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);
                packet_disconnect("Change of username or service not allowed: "
                    "(%s,%s) -> (%s,%s)",
                    authctxt->user, authctxt->service, user, service);
index 3440a89..bb7743d 100644 (file)
@@ -353,4 +353,25 @@ ssh_gssapi_userok(char *user, struct passwd *pw)
        return (userok);
 }
 
        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 */
index f8a79fb..a05a4bc 100644 (file)
--- 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_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
 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},
 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_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},
     {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_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
     {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__);
 
 
        debug3("%s", __func__);
 
-       if (authctxt->attempt++ != 0)
-               fatal("%s: multiple attempts for getpwnam", __func__);
-
        username = buffer_get_string(m, NULL);
 
        pwent = getpwnamallow(username);
 
        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);
        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);
 }
 
        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)
 {
 int 
 mm_answer_gss_sign(int socket, Buffer *m)
 {
index aa38b16..8a34c38 100644 (file)
--- 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_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,
        MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
        MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
        MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS,
index ff1b05e..30de708 100644 (file)
@@ -1272,6 +1272,31 @@ mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
        return(major);
 }
 
        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
 #endif /* GSSAPI */
 
 #ifdef JPAKE
index 7811d65..3c4be70 100644 (file)
@@ -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_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
 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
index ea12a38..7b9d52d 100644 (file)
--- 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 *);
     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);
 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);