/*ARGSUSED*/ static int input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) { struct authctxt *authctxt = ssh->authctxt; struct authmethod *m = NULL; char *user = NULL, *service = NULL, *method = NULL, *style = NULL; int r, authenticated = 0; if (authctxt == NULL) fatal("input_userauth_request: no authctxt"); if ((r = sshpkt_get_cstring(ssh, &user, NULL)) != 0 || (r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 || (r = sshpkt_get_cstring(ssh, &method, NULL)) != 0) goto out; debug("userauth-request for user %s service %s method %s", user, service, method); debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); if ((style = strchr(user, ':')) != NULL) *style++ = 0; if (authctxt->attempt++ == 0) { /* setup auth context */ authctxt->pw = PRIVSEP(getpwnamallow(user)); if (authctxt->pw && strcmp(service, "ssh-connection")==0) { authctxt->valid = 1; debug2("input_userauth_request: setting up authctxt for %s", user); } else { logit("input_userauth_request: invalid user %s", user); authctxt->pw = fakepw(); } setproctitle("%s%s", authctxt->valid ? user : "******", 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); userauth_banner(ssh); if (auth2_setup_methods_lists(authctxt) != 0) ssh_packet_disconnect(ssh, "no authentication methods enabled"); } else if (strcmp(user, authctxt->user) != 0 || strcmp(service, authctxt->service) != 0) { ssh_packet_disconnect(ssh, "Change of username or service not allowed: " "(%s,%s) -> (%s,%s)", authctxt->user, authctxt->service, user, service); } /* reset state */ auth2_challenge_stop(ssh); #ifdef GSSAPI /* XXX move to auth2_gssapi_stop() */ ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); #endif authctxt->postponed = 0; authctxt->server_caused_failure = 0; /* try to authenticate user */ m = authmethod_lookup(authctxt, method); if (m != NULL && authctxt->failures < options.max_authtries) { debug2("input_userauth_request: try method %s", method); authenticated = m->userauth(ssh); } userauth_finish(ssh, authenticated, method, NULL); r = 0; out: free(service); free(user); free(method); return r; }
/*ARGSUSED*/ static void input_userauth_request(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; Authmethod *m = NULL; char *user, *service, *method, *style = NULL; int authenticated = 0; if (authctxt == NULL) fatal("input_userauth_request: no authctxt"); user = packet_get_cstring(NULL); service = packet_get_cstring(NULL); method = packet_get_cstring(NULL); debug("userauth-request for user %s service %s method %s", user, service, method); if (!log_flag) { logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", get_remote_ipaddr(), get_remote_port(), 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 */ authctxt->pw = PRIVSEP(getpwnamallow(user)); authctxt->user = xstrdup(user); if (authctxt->pw && strcmp(service, "ssh-connection")==0) { authctxt->valid = 1; debug2("input_userauth_request: setting up authctxt for %s", user); } else { logit("input_userauth_request: invalid user %s", user); authctxt->pw = fakepw(); } #ifdef USE_PAM if (options.use_pam) PRIVSEP(start_pam(authctxt)); #endif setproctitle("%s%s", authctxt->valid ? user : "******", use_privsep ? " [net]" : ""); authctxt->service = xstrdup(service); authctxt->style = style ? xstrdup(style) : NULL; if (use_privsep) mm_inform_authserv(service, style); userauth_banner(); if (auth2_setup_methods_lists(authctxt) != 0) packet_disconnect("no authentication methods enabled"); } else if (strcmp(user, authctxt->user) != 0 || strcmp(service, authctxt->service) != 0) { packet_disconnect("Change of username or 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(authctxt, method); if (m != NULL && authctxt->failures < options.max_authtries) { debug2("input_userauth_request: try method %s", method); authenticated = m->userauth(authctxt); } userauth_finish(authctxt, authenticated, method, NULL); free(service); free(user); free(method); }
int mm_answer_pwnamallow(int socket, Buffer *m) { char *login; struct passwd *pwent; int allowed = 0; debug3("%s", __func__); if (authctxt->attempt++ != 0) fatal("%s: multiple attempts for getpwnam", __func__); login = buffer_get_string(m, NULL); pwent = getpwnamallow(login); authctxt->user = xstrdup(login); setproctitle("%s [priv]", pwent ? login : "******"); xfree(login); buffer_clear(m); if (pwent == NULL) { buffer_put_char(m, 0); goto out; } allowed = 1; authctxt->pw = pwent; authctxt->valid = 1; buffer_put_char(m, 1); buffer_put_string(m, pwent, sizeof(struct passwd)); buffer_put_cstring(m, pwent->pw_name); buffer_put_cstring(m, "*"); buffer_put_cstring(m, pwent->pw_gecos); #ifdef HAVE_PW_CLASS_IN_PASSWD buffer_put_cstring(m, pwent->pw_class); #endif buffer_put_cstring(m, pwent->pw_dir); buffer_put_cstring(m, pwent->pw_shell); out: debug3("%s: sending MONITOR_ANS_PWNAM: %d", __func__, allowed); mm_request_send(socket, MONITOR_ANS_PWNAM, m); /* For SSHv1 allow authentication now */ if (!compat20) monitor_permit_authentications(1); else { /* Allow service/style information on the auth context */ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); } #ifdef USE_PAM monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1); #endif return (0); }
/*ARGSUSED*/ static void input_userauth_request(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; Authmethod *m = NULL; char *user, *service, *method, *style = NULL; int authenticated = 0; #ifdef HAVE_LOGIN_CAP login_cap_t *lc; const char *from_host, *from_ip; from_host = get_canonical_hostname(options.use_dns); from_ip = get_remote_ipaddr(); #endif if (authctxt == NULL) fatal("input_userauth_request: no authctxt"); user = packet_get_cstring(NULL); service = packet_get_cstring(NULL); method = packet_get_cstring(NULL); debug("userauth-request for user %s service %s method %s", user, service, method); debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); if ((style = strchr(user, ':')) != NULL) *style++ = 0; if (authctxt->attempt++ == 0) { /* setup auth context */ authctxt->pw = PRIVSEP(getpwnamallow(user)); authctxt->user = xstrdup(user); if (authctxt->pw && strcmp(service, "ssh-connection")==0) { authctxt->valid = 1; debug2("input_userauth_request: setting up authctxt for %s", user); } else { logit("input_userauth_request: invalid user %s", user); authctxt->pw = fakepw(); #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_INVALID_USER)); #endif } #ifdef USE_PAM if (options.use_pam) PRIVSEP(start_pam(authctxt)); #endif setproctitle("%s%s", authctxt->valid ? user : "******", 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) { packet_disconnect("Change of username or service not allowed: " "(%s,%s) -> (%s,%s)", authctxt->user, authctxt->service, user, service); } #ifdef HAVE_LOGIN_CAP if (authctxt->pw != NULL) { lc = login_getpwclass(authctxt->pw); if (lc == NULL) lc = login_getclassbyname(NULL, authctxt->pw); if (!auth_hostok(lc, from_host, from_ip)) { logit("Denied connection for %.200s from %.200s [%.200s].", authctxt->pw->pw_name, from_host, from_ip); packet_disconnect("Sorry, you are not allowed to connect."); } if (!auth_timeok(lc, time(NULL))) { logit("LOGIN %.200s REFUSED (TIME) FROM %.200s", authctxt->pw->pw_name, from_host); packet_disconnect("Logins not available right now."); } login_close(lc); lc = NULL; } #endif /* HAVE_LOGIN_CAP */ /* 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; /* try to authenticate user */ m = authmethod_lookup(method); if (m != NULL && authctxt->failures < options.max_authtries) { debug2("input_userauth_request: try method %s", method); authenticated = m->userauth(authctxt); } userauth_finish(authctxt, authenticated, method); xfree(service); xfree(user); xfree(method); }
/* * Performs authentication of an incoming connection. Session key has already * been exchanged and encryption is enabled. */ void do_authentication(Authctxt *authctxt) { u_int ulen; char *user, *style = NULL; /* Get the name of the user that we wish to log in as. */ packet_read_expect(SSH_CMSG_USER); /* Get the user name. */ user = packet_get_cstring(&ulen); packet_check_eom(); if ((style = strchr(user, ':')) != NULL) *style++ = '\0'; 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: invalid user %s", user); authctxt->pw = fakepw(); } /* Configuration may have changed as a result of Match */ if (options.num_auth_methods != 0) fatal("AuthenticationMethods is not supported with SSH " "protocol 1"); setproctitle("%s%s", authctxt->valid ? user : "******", use_privsep ? " [net]" : ""); #ifdef USE_PAM 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. */ #ifndef HAVE_CYGWIN if (!use_privsep && getuid() != 0 && authctxt->pw && authctxt->pw->pw_uid != getuid()) packet_disconnect("Cannot change user when server not running as root."); #endif /* * Loop until the user has been authenticated or the connection is * closed, do_authloop() returns only if authentication is successful */ do_authloop(authctxt); /* The user has been authenticated and accepted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait(); }
/* * Performs authentication of an incoming connection. Session key has already * been exchanged and encryption is enabled. */ Authctxt * do_authentication(void) { Authctxt *authctxt; u_int ulen; char *user, *style = NULL; /* Get the name of the user that we wish to log in as. */ packet_read_expect(SSH_CMSG_USER); /* Get the user name. */ user = packet_get_string(&ulen); packet_check_eom(); 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); setproctitle("%s%s", authctxt->pw ? user : "******", use_privsep ? " [net]" : ""); #ifdef USE_PAM PRIVSEP(start_pam(authctxt->pw == NULL ? "NOUSER" : user)); #endif /* * If we are not running as root, the user must have the same uid as * the server. (Unless you are running Windows) */ #ifndef HAVE_CYGWIN if (!use_privsep && getuid() != 0 && authctxt->pw && authctxt->pw->pw_uid != getuid()) packet_disconnect("Cannot change user when server not running as root."); #endif /* * Loop until the user has been authenticated or the connection is * closed, do_authloop() returns only if authentication is successful */ do_authloop(authctxt); /* The user has been authenticated and accepted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait(); return (authctxt); }
int mm_answer_pwnamallow(int sock, struct sshbuf *m) { char *username; struct passwd *pwent; int r, allowed = 0; u_int i; debug3("%s", __func__); if (authctxt->attempt++ != 0) fatal("%s: multiple attempts for getpwnam", __func__); if ((r = sshbuf_get_cstring(m, &username, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); pwent = getpwnamallow(username); authctxt->user = xstrdup(username); setproctitle("%s [priv]", pwent ? username : "******"); free(username); sshbuf_reset(m); if (pwent == NULL) { if ((r = sshbuf_put_u8(m, 0)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); authctxt->pw = fakepw(); goto out; } allowed = 1; authctxt->pw = pwent; authctxt->valid = 1; if ((r = sshbuf_put_u8(m, 1)) != 0 || (r = sshbuf_put_string(m, pwent, sizeof(struct passwd))) != 0 || (r = sshbuf_put_cstring(m, pwent->pw_name)) != 0 || (r = sshbuf_put_cstring(m, "*")) != 0 || (r = sshbuf_put_cstring(m, pwent->pw_gecos)) != 0 || (r = sshbuf_put_cstring(m, pwent->pw_class)) != 0 || (r = sshbuf_put_cstring(m, pwent->pw_dir)) != 0 || (r = sshbuf_put_cstring(m, pwent->pw_shell)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); out: if ((r = sshbuf_put_string(m, &options, sizeof(options))) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); #define M_CP_STROPT(x) do { \ if (options.x != NULL) \ if ((r = sshbuf_put_cstring(m, options.x)) != 0) \ fatal("%s: buffer error: %s", __func__, \ ssh_err(r)); \ } while (0) #define M_CP_STRARRAYOPT(x, nx) do { \ for (i = 0; i < options.nx; i++) \ if ((r = sshbuf_put_cstring(m, options.x[i])) != 0) \ fatal("%s: buffer error: %s", __func__, \ ssh_err(r)); \ } while (0) /* See comment in servconf.h */ COPY_MATCH_STRING_OPTS(); #undef M_CP_STROPT #undef M_CP_STRARRAYOPT /* Create valid auth method lists */ if (compat20 && auth2_setup_methods_lists(authctxt) != 0) { /* * The monitor will continue long enough to let the child * run to it's packet_disconnect(), but it must not allow any * authentication to succeed. */ debug("%s: no valid authentication method lists", __func__); } debug3("%s: sending MONITOR_ANS_PWNAM: %d", __func__, allowed); mm_request_send(sock, MONITOR_ANS_PWNAM, m); /* For SSHv1 allow authentication now */ if (!compat20) monitor_permit_authentications(1); else { /* Allow service/style information on the auth context */ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); } return (0); }
static void input_userauth_request(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; Authmethod *m = NULL; char *user, *service, *method, *style = NULL; int valid_attempt; if (authctxt == NULL) fatal("input_userauth_request: no authctxt"); user = packet_get_string(NULL); service = packet_get_string(NULL); method = packet_get_string(NULL); debug("userauth-request for user %s service %s method %s", user, service, method); debug("attempt %d initial attempt %d failures %d initial failures %d", authctxt->attempt, authctxt->init_attempt, authctxt->failures, authctxt->init_failures); m = authmethod_lookup(method); if ((style = strchr(user, ':')) != NULL) *style++ = 0; authctxt->attempt++; if (m != NULL && m->is_initial) authctxt->init_attempt++; if (options.pre_userauth_hook != NULL && run_auth_hook(options.pre_userauth_hook, user, m->name) != 0) { valid_attempt = 0; } else { valid_attempt = 1; } if (authctxt->attempt == 1) { /* setup auth context */ authctxt->pw = getpwnamallow(user); /* May want to abstract SSHv2 services someday */ if (authctxt->pw && strcmp(service, "ssh-connection")==0) { /* enforced in userauth_finish() below */ if (valid_attempt) { authctxt->valid = 1; } debug2("input_userauth_request: setting up authctxt for %s", user); } else { log("input_userauth_request: illegal user %s", user); } setproctitle("%s", authctxt->pw ? user : "******"); authctxt->user = xstrdup(user); authctxt->service = xstrdup(service); authctxt->style = style ? xstrdup(style) : NULL; userauth_reset_methods(); } else { char *abandoned; /* * Check for abandoned [multi-round-trip] userauths * methods (e.g., kbdint). Userauth method abandonment * should be treated as userauth method failure and * counted against max_auth_tries. */ abandoned = authmethods_check_abandonment(authctxt, m); if (abandoned != NULL && authctxt->failures > options.max_auth_tries) { /* userauth_finish() will now packet_disconnect() */ userauth_finish(authctxt, abandoned); /* NOTREACHED */ } /* Handle user|service changes, possibly packet_disconnect() */ userauth_user_svc_change(authctxt, user, service); } authctxt->method = m; /* run userauth method, try to authenticate user */ if (m != NULL && userauth_method_can_run(m)) { debug2("input_userauth_request: try method %s", method); m->postponed = 0; m->abandoned = 0; m->authenticated = 0; if (!m->is_initial || authctxt->init_failures < options.max_init_auth_tries) m->userauth(authctxt); authmethod_count_attempt(m); if (authctxt->unwind_dispatch_loop) { /* * Method ran nested dispatch loop but was * abandoned. Cleanup and return without doing * anything else; we're just unwinding the stack. */ authctxt->unwind_dispatch_loop = 0; goto done; } if (m->postponed) goto done; /* multi-round trip userauth not finished */ if (m->abandoned) { /* multi-round trip userauth abandoned, log failure */ auth_log(authctxt, 0, method, " ssh2"); goto done; } } userauth_finish(authctxt, method); done: xfree(service); xfree(user); xfree(method); }
int mm_answer_pwnamallow(int sock, Buffer *m) { struct ssh *ssh = active_state; /* XXX */ char *username; struct passwd *pwent; int allowed = 0; u_int i; debug3("%s", __func__); if (authctxt->attempt++ != 0) fatal("%s: multiple attempts for getpwnam", __func__); username = buffer_get_string(m, NULL); pwent = getpwnamallow(username); authctxt->user = xstrdup(username); setproctitle("%s [priv]", pwent ? username : "******"); free(username); buffer_clear(m); if (pwent == NULL) { buffer_put_char(m, 0); authctxt->pw = fakepw(); goto out; } allowed = 1; authctxt->pw = pwent; authctxt->valid = 1; buffer_put_char(m, 1); buffer_put_string(m, pwent, sizeof(struct passwd)); buffer_put_cstring(m, pwent->pw_name); buffer_put_cstring(m, "*"); #ifdef HAVE_STRUCT_PASSWD_PW_GECOS buffer_put_cstring(m, pwent->pw_gecos); #endif #ifdef HAVE_STRUCT_PASSWD_PW_CLASS buffer_put_cstring(m, pwent->pw_class); #endif buffer_put_cstring(m, pwent->pw_dir); buffer_put_cstring(m, pwent->pw_shell); out: ssh_packet_set_log_preamble(ssh, "%suser %s", authctxt->valid ? "authenticating" : "invalid ", authctxt->user); buffer_put_string(m, &options, sizeof(options)); #define M_CP_STROPT(x) do { \ if (options.x != NULL) \ buffer_put_cstring(m, options.x); \ } while (0) #define M_CP_STRARRAYOPT(x, nx) do { \ for (i = 0; i < options.nx; i++) \ buffer_put_cstring(m, options.x[i]); \ } while (0) /* See comment in servconf.h */ COPY_MATCH_STRING_OPTS(); #undef M_CP_STROPT #undef M_CP_STRARRAYOPT /* Create valid auth method lists */ if (auth2_setup_methods_lists(authctxt) != 0) { /* * The monitor will continue long enough to let the child * run to it's packet_disconnect(), but it must not allow any * authentication to succeed. */ debug("%s: no valid authentication method lists", __func__); } debug3("%s: sending MONITOR_ANS_PWNAM: %d", __func__, allowed); mm_request_send(sock, MONITOR_ANS_PWNAM, m); /* Allow service/style information on the auth context */ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); #ifdef USE_PAM if (options.use_pam) monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1); #endif return (0); }
/* * To be called from userauth methods, directly (as in keyboard-interactive) or * indirectly (from auth_pam_password() or from do_pam_non_initial_userauth(). * * The caller is responsible for calling new_start_pam() first. * * PAM state is not cleaned up here on error. This is left to subsequent calls * to new_start_pam() or to the cleanup function upon authentication error. */ int finish_userauth_do_pam(Authctxt *authctxt) { int retval; char *user, *method; /* Various checks; fail gracefully */ if (authctxt == NULL || authctxt->pam == NULL) return PAM_SYSTEM_ERR; /* shouldn't happen */ if (compat20) { if (authctxt->method == NULL || authctxt->method->name == NULL) return PAM_SYSTEM_ERR; /* shouldn't happen */ method = authctxt->method->name; } else if ((method = authctxt->v1_auth_name) == NULL) return PAM_SYSTEM_ERR; /* shouldn't happen */ if (AUTHPAM_DONE(authctxt)) return PAM_SYSTEM_ERR; /* shouldn't happen */ if (!(authctxt->pam->state & PAM_S_DONE_ACCT_MGMT)) { retval = pam_acct_mgmt(authctxt->pam->h, 0); authctxt->pam->last_pam_retval = retval; if (retval == PAM_NEW_AUTHTOK_REQD) { userauth_force_kbdint(); return retval; } if (retval != PAM_SUCCESS) return retval; authctxt->pam->state |= PAM_S_DONE_ACCT_MGMT; } /* * Handle PAM_USER change, if any. * * We do this before pam_open_session() because we need the PAM_USER's * UID for: * * a) PermitRootLogin checking * b) to get at the lastlog entry before pam_open_session() updates it. */ retval = pam_get_item(authctxt->pam->h, PAM_USER, (void **) &user); if (retval != PAM_SUCCESS) { fatal("PAM failure: pam_get_item(PAM_USER) " "returned %d: %.200s", retval, PAM_STRERROR(authctxt->pam->h, retval)); } if (user == NULL || *user == '\0') { debug("PAM set NULL PAM_USER"); return PAM_PERM_DENIED; } if (strcmp(user, authctxt->user) != 0) { log("PAM changed the SSH username"); pwfree(&authctxt->pw); authctxt->pw = PRIVSEP(getpwnamallow(user)); authctxt->valid = (authctxt->pw != NULL); xfree(authctxt->user); authctxt->user = xstrdup(user); } if (!authctxt->valid) { debug2("PAM set PAM_USER to unknown user"); /* * Return success, userauth_finish() will catch * this and send back a failure message. */ return PAM_SUCCESS; } /* Check PermitRootLogin semantics */ if (authctxt->pw->pw_uid == 0 && !auth_root_allowed(method)) return PAM_PERM_DENIED; if (!(authctxt->pam->state & PAM_S_DONE_SETCRED)) { retval = pam_setcred(authctxt->pam->h, PAM_ESTABLISH_CRED); authctxt->pam->last_pam_retval = retval; if (retval != PAM_SUCCESS) return retval; authctxt->pam->state |= PAM_S_DONE_SETCRED; #ifdef GSSAPI /* * Store GSS-API delegated creds after pam_setcred(), which may * have set the current credential store. */ ssh_gssapi_storecreds(NULL, authctxt); #endif /* GSSAPI */ } /* * On Solaris pam_unix_session.so updates the lastlog, but does * not converse a PAM_TEXT_INFO message about it. So we need to * fetch the lastlog entry here and save it for use later. */ authctxt->last_login_time = get_last_login_time(authctxt->pw->pw_uid, authctxt->pw->pw_name, authctxt->last_login_host, sizeof(authctxt->last_login_host)); if (!(authctxt->pam->state & PAM_S_DONE_OPEN_SESSION)) { retval = pam_open_session(authctxt->pam->h, 0); authctxt->pam->last_pam_retval = retval; if (retval != PAM_SUCCESS) return retval; authctxt->pam->state |= PAM_S_DONE_OPEN_SESSION; } /* * All PAM work done successfully. * * PAM handle stays around so we can call pam_close_session() on * it later. */ return PAM_SUCCESS; }