authmsg,
method,
authctxt->valid ? "" : "invalid user ",
- authctxt->user,
+ (authctxt->user && authctxt->user[0]) ?
+ authctxt->user : "unknown",
get_remote_ipaddr(),
get_remote_port(),
info);
#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");
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();
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,
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 ((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 {
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);
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 */
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
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},
{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
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);
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)
{
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,
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
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
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);