static bool ChangePlaintextPasswordUsingLibPam(const char *puser, const char *password) { int status; pam_handle_t *handle; struct pam_conv conv; conv.conv = PasswordSupplier; conv.appdata_ptr = (void*)password; status = pam_start("passwd", puser, &conv, &handle); if (status != PAM_SUCCESS) { Log(LOG_LEVEL_ERR, "Could not initialize pam session. (pam_start: '%s')", pam_strerror(NULL, status)); return false; } Log(LOG_LEVEL_VERBOSE, "Changing password for user '%s'.", puser); status = pam_chauthtok(handle, PAM_SILENT); pam_end(handle, status); if (status == PAM_SUCCESS) { return true; } else { Log(LOG_LEVEL_ERR, "Could not change password for user '%s'. (pam_chauthtok: '%s')", puser, pam_strerror(handle, status)); return false; } }
static enum pamtest_err run_test_case(pam_handle_t *ph, struct pam_testcase *tc) { switch (tc->pam_operation) { case PAMTEST_AUTHENTICATE: tc->op_rv = pam_authenticate(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_SETCRED: tc->op_rv = pam_setcred(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_ACCOUNT: tc->op_rv = pam_acct_mgmt(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_OPEN_SESSION: tc->op_rv = pam_open_session(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_CLOSE_SESSION: tc->op_rv = pam_close_session(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_CHAUTHTOK: tc->op_rv = pam_chauthtok(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_GETENVLIST: tc->case_out.envlist = pam_getenvlist(ph); return PAMTEST_ERR_OK; case PAMTEST_KEEPHANDLE: tc->case_out.ph = ph; return PAMTEST_ERR_KEEPHANDLE; default: return PAMTEST_ERR_OP; } return PAMTEST_ERR_OP; }
bool PamHandle::chAuthTok(int flags) { m_result = pam_chauthtok(m_handle, flags | m_silent); if (m_result != PAM_SUCCESS) { qWarning() << "[PAM] chAuthTok:" << pam_strerror(m_handle, m_result); } return m_result == PAM_SUCCESS; }
static void loginpam_acct(struct login_context *cxt) { int rc; pam_handle_t *pamh = cxt->pamh; rc = pam_acct_mgmt(pamh, 0); if (rc == PAM_NEW_AUTHTOK_REQD) rc = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); if (is_pam_failure(rc)) loginpam_err(pamh, rc); /* * Grab the user information out of the password file for future use. * First get the username that we are actually using, though. */ rc = loginpam_get_username(pamh, &cxt->username); if (is_pam_failure(rc)) loginpam_err(pamh, rc); if (!cxt->username || !*cxt->username) { warnx(_("\nSession setup problem, abort.")); syslog(LOG_ERR, _("NULL user name in %s:%d. Abort."), __FUNCTION__, __LINE__); pam_end(pamh, PAM_SYSTEM_ERR); sleepexit(EXIT_FAILURE); } }
void do_pam_passwd(const char *user, int silent, int change_expired) { pam_handle_t *pamh = NULL; int flags = 0, ret; if (silent) flags |= PAM_SILENT; if (change_expired) flags |= PAM_CHANGE_EXPIRED_AUTHTOK; ret = pam_start("passwd", user, &conv, &pamh); if (ret != PAM_SUCCESS) { fprintf(stderr, _("passwd: pam_start() failed, error %d\n"), ret); exit(10); /* XXX */ } ret = pam_chauthtok(pamh, flags); if (ret != PAM_SUCCESS) { fprintf(stderr, _("passwd: %s\n"), PAM_STRERROR(pamh, ret)); pam_end(pamh, ret); exit(10); /* XXX */ } pam_end(pamh, PAM_SUCCESS); }
int sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth) { const char *s; int *pam_status = (int *) auth->data; debug_decl(sudo_pam_verify, SUDO_DEBUG_AUTH) def_prompt = prompt; /* for converse */ /* PAM_SILENT prevents the authentication service from generating output. */ *pam_status = pam_authenticate(pamh, PAM_SILENT); switch (*pam_status) { case PAM_SUCCESS: *pam_status = pam_acct_mgmt(pamh, PAM_SILENT); switch (*pam_status) { case PAM_SUCCESS: debug_return_int(AUTH_SUCCESS); case PAM_AUTH_ERR: log_warning(NO_MAIL, N_("account validation failure, " "is your account locked?")); debug_return_int(AUTH_FATAL); case PAM_NEW_AUTHTOK_REQD: log_warning(NO_MAIL, N_("Account or password is " "expired, reset your password and try again")); *pam_status = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); if (*pam_status == PAM_SUCCESS) debug_return_int(AUTH_SUCCESS); if ((s = pam_strerror(pamh, *pam_status)) != NULL) { log_warning(NO_MAIL, N_("unable to change expired password: %s"), s); } debug_return_int(AUTH_FAILURE); case PAM_AUTHTOK_EXPIRED: log_warning(NO_MAIL, N_("Password expired, contact your system administrator")); debug_return_int(AUTH_FATAL); case PAM_ACCT_EXPIRED: log_warning(NO_MAIL, N_("Account expired or PAM config lacks an \"account\" " "section for sudo, contact your system administrator")); debug_return_int(AUTH_FATAL); } /* FALLTHROUGH */ case PAM_AUTH_ERR: case PAM_AUTHINFO_UNAVAIL: if (getpass_error) { /* error or ^C from tgetpass() */ debug_return_int(AUTH_INTR); } /* FALLTHROUGH */ case PAM_MAXTRIES: case PAM_PERM_DENIED: debug_return_int(AUTH_FAILURE); default: if ((s = pam_strerror(pamh, *pam_status)) != NULL) log_warning(NO_MAIL, N_("PAM authentication error: %s"), s); debug_return_int(AUTH_FATAL); } }
bool PAMAuthenticator::authenticate(void) { pam_conv c; c.conv = PAMAuthenticator::conv; c.appdata_ptr = this; int res = pam_start("repwatchproxy", 0, &c, &this->m_ph); if (res == PAM_SUCCESS) { res = pam_set_item(this->m_ph, PAM_RUSER, this->m_user.constData()); if (res != PAM_SUCCESS) { goto getout; } res = pam_set_item(this->m_ph, PAM_RHOST, this->m_host.constData()); if (res != PAM_SUCCESS) { goto getout; } res = pam_authenticate(this->m_ph, 0); if (res != PAM_SUCCESS) { goto getout; } res = pam_acct_mgmt(this->m_ph, 0); if (PAM_NEW_AUTHTOK_REQD == res) { res = pam_chauthtok(this->m_ph, PAM_CHANGE_EXPIRED_AUTHTOK); } if (res != PAM_SUCCESS) { goto getout; } res = pam_setcred(this->m_ph, PAM_ESTABLISH_CRED); if (res != PAM_SUCCESS) { goto getout; } res = pam_open_session(this->m_ph, 0); if (res != PAM_SUCCESS) { goto getout; } return true; getout: qWarning("%s: %s", Q_FUNC_INFO, pam_strerror(this->m_ph, res)); pam_end(this->m_ph, res); } else { qCritical("PAM initialization failed"); } this->m_ph = 0; return false; }
int pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth) { const char *s; int *pam_status = (int *) auth->data; def_prompt = prompt; /* for converse */ /* PAM_SILENT prevents the authentication service from generating output. */ *pam_status = pam_authenticate(pamh, PAM_SILENT); switch (*pam_status) { case PAM_SUCCESS: *pam_status = pam_acct_mgmt(pamh, PAM_SILENT); switch (*pam_status) { case PAM_SUCCESS: return AUTH_SUCCESS; case PAM_AUTH_ERR: log_error(NO_EXIT|NO_MAIL, _("account validation failure, " "is your account locked?")); return AUTH_FATAL; case PAM_NEW_AUTHTOK_REQD: log_error(NO_EXIT|NO_MAIL, _("Account or password is " "expired, reset your password and try again")); *pam_status = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); if (*pam_status == PAM_SUCCESS) return AUTH_SUCCESS; if ((s = pam_strerror(pamh, *pam_status))) log_error(NO_EXIT|NO_MAIL, _("pam_chauthtok: %s"), s); return AUTH_FAILURE; case PAM_AUTHTOK_EXPIRED: log_error(NO_EXIT|NO_MAIL, _("Password expired, contact your system administrator")); return AUTH_FATAL; case PAM_ACCT_EXPIRED: log_error(NO_EXIT|NO_MAIL, _("Account expired or PAM config lacks an \"account\" " "section for sudo, contact your system administrator")); return AUTH_FATAL; } /* FALLTHROUGH */ case PAM_AUTH_ERR: if (gotintr) { /* error or ^C from tgetpass() */ return AUTH_INTR; } case PAM_MAXTRIES: case PAM_PERM_DENIED: return AUTH_FAILURE; default: if ((s = pam_strerror(pamh, *pam_status))) log_error(NO_EXIT|NO_MAIL, _("pam_authenticate: %s"), s); return AUTH_FATAL; } }
int main(int argc, char *argv[]) { pam_handle_t *pamh=NULL; int retval; const char *user="******"; if(argc == 2) { user = argv[1]; } if(argc > 2) { fprintf(stderr, "Usage: check_user [username]\n"); exit(1); } retval = pam_start("sqlite3", user, &conv, &pamh); if(retval == PAM_SUCCESS) printf("PAM started.\n"); if (retval == PAM_SUCCESS) retval = pam_authenticate(pamh, 0); /* is user really user? */ if(retval == PAM_SUCCESS) printf("Authentication succeeded, checking access.\n"); else printf("Authentication failed: %s\n", pam_strerror(pamh, retval)); if (retval == PAM_SUCCESS) retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ if(retval == PAM_SUCCESS) printf("Access permitted.\n"); else printf("Access denied: %s\n", pam_strerror(pamh, retval)); /* lets try print password */ printf("Changing authentication token...\n"); retval = pam_chauthtok(pamh, 0); if(retval != PAM_SUCCESS) { printf("Failed: %s\n", pam_strerror(pamh, retval)); } else { printf("Token changed.\n"); } /* This is where we have been authorized or not. */ if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ pamh = NULL; fprintf(stderr, "check_user: failed to release authenticator\n"); exit(1); } return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ }
static int sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags) { int result; if (sshpam_authctxt == NULL) fatal("PAM: sshpam_authctxt not initialized"); if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1) fatal("%s: setreuid failed: %s", __func__, strerror(errno)); result = pam_chauthtok(pamh, flags); if (setreuid(0, -1) == -1) fatal("%s: setreuid failed: %s", __func__, strerror(errno)); return result; }
static void pm_do_auth(adt_session_data_t *ah) { pam_handle_t *pm_pamh; int err; int pam_flag = 0; int chpasswd_tries; struct pam_conv pam_conv = {pam_tty_conv, NULL}; if (user[0] == '\0') return; if ((err = pam_start("sys-suspend", user, &pam_conv, &pm_pamh)) != PAM_SUCCESS) return; pam_flag = PAM_DISALLOW_NULL_AUTHTOK; do { err = pam_authenticate(pm_pamh, pam_flag); if (err == PAM_SUCCESS) { err = pam_acct_mgmt(pm_pamh, pam_flag); if (err == PAM_NEW_AUTHTOK_REQD) { chpasswd_tries = 0; do { err = pam_chauthtok(pm_pamh, PAM_CHANGE_EXPIRED_AUTHTOK); chpasswd_tries++; } while ((err == PAM_AUTHTOK_ERR || err == PAM_TRY_AGAIN) && chpasswd_tries < DEF_ATTEMPTS); pm_audit_event(ah, ADT_passwd, err); } err = pam_setcred(pm_pamh, PAM_REFRESH_CRED); } if (err != PAM_SUCCESS) { (void) fprintf(stdout, "%s\n", pam_strerror(pm_pamh, err)); pm_audit_event(ah, ADT_screenunlock, err); } } while (err != PAM_SUCCESS); pm_audit_event(ah, ADT_passwd, 0); (void) pam_end(pm_pamh, err); }
int main(int argc, char **argv) { pam_handle_t *pamh=NULL; static struct pam_conv pamc = { misc_conv, NULL }; if( PAM_SUCCESS != pam_start("test", "testa", &pamc, &pamh) ) { fprintf(stderr, "ERR: pam_start failed!\n"); return 1; } /* if( PAM_SUCCESS != pam_set_item(pamh, PAM_USER, "tester") ) { fprintf(stderr, "ERR: pam_set_item user failed!\n"); return 1; } if( PAM_SUCCESS != pam_chauthtok(pamh, 0) ) { fprintf(stderr, "ERR: pam_chauthtok failed!\n"); return 1; } if( PAM_SUCCESS != pam_set_item(pamh, PAM_AUTHTOK, "mypassword") ) { fprintf(stderr, "ERR: pam_set_item password failed!\n"); return 1; } */ if( PAM_SUCCESS != pam_chauthtok(pamh, 0) ) { fprintf(stderr, "ERR: pam_chauthtok failed!\n"); return 1; } if( PAM_SUCCESS != pam_end(pamh, PAM_SUCCESS) ) { fprintf(stderr, "ERR: pam_end failed!\n"); return 1; } return 0; }
/* * XXX this should be done in the authentication phase, but ssh1 doesn't * support that */ void do_pam_chauthtok(void) { if (use_privsep) fatal("Password expired (unable to change with privsep)"); sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, (const void *)&tty_conv); if (sshpam_err != PAM_SUCCESS) fatal("PAM: failed to set PAM_CONV: %s", pam_strerror(sshpam_handle, sshpam_err)); debug("PAM: changing password"); sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); if (sshpam_err != PAM_SUCCESS) fatal("PAM: pam_chauthtok(): %s", pam_strerror(sshpam_handle, sshpam_err)); }
int main(int argc, char *argv[]) { pam_handle_t *pamh = NULL; int retval; struct pam_conv conv = { gradm_pam_conv, NULL }; struct gr_arg_wrapper wrapper; struct gr_arg arg; int fd; if (argc != 2) exit(EXIT_FAILURE); wrapper.version = GRADM_VERSION; wrapper.size = sizeof(struct gr_arg); wrapper.arg = &arg; arg.mode = GRADM_STATUS; if ((fd = open(GRDEV_PATH, O_WRONLY)) < 0) { fprintf(stderr, "Could not open %s.\n", GRDEV_PATH); failure("open"); } retval = write(fd, &wrapper, sizeof(struct gr_arg_wrapper)); close(fd); if (retval != 1) exit(EXIT_FAILURE); retval = pam_start(PAM_SERVICENAME, argv[1], &conv, &pamh); if (retval == PAM_SUCCESS) retval = pam_authenticate(pamh, 0); if (retval == PAM_SUCCESS) retval = pam_acct_mgmt(pamh, 0); if (retval == PAM_AUTHTOK_EXPIRED) retval = pam_chauthtok(pamh, 0); if (pamh) pam_end(pamh, retval); if (retval != PAM_SUCCESS) exit(EXIT_FAILURE); return EXIT_SUCCESS; }
static int do_account_password_management(pam_handle_t *pamh) { int rc; /* Whether the authenticated user is allowed to log in? */ rc = pam_acct_mgmt(pamh, 0); /* Do we need to prompt the user for a new password? */ if (rc == PAM_NEW_AUTHTOK_REQD) rc = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); /* Extend the lifetime of the existing credentials. */ if (rc == PAM_SUCCESS) rc = pam_setcred(pamh, PAM_REFRESH_CRED); return rc; }
static void co_auth_user(void* data) { struct pam_ctx_st * pctx = data; int pret; pctx->state = PAM_S_INIT; pret = pam_authenticate(pctx->ph, 0); if (pret != PAM_SUCCESS) { syslog(LOG_INFO, "PAM authenticate error: %s", pam_strerror(pctx->ph, pret)); pctx->cr_ret = pret; goto wait; } pret = pam_acct_mgmt(pctx->ph, 0); if (pret == PAM_NEW_AUTHTOK_REQD) { /* change password */ syslog(LOG_INFO, "Password for user '%s' is expired. Attempting to update...", pctx->username); pctx->changing = 1; pret = pam_chauthtok(pctx->ph, PAM_CHANGE_EXPIRED_AUTHTOK); } if (pret != PAM_SUCCESS) { syslog(LOG_INFO, "PAM acct-mgmt error: %s", pam_strerror(pctx->ph, pret)); pctx->cr_ret = pret; goto wait; } pctx->state = PAM_S_COMPLETE; pctx->cr_ret = PAM_SUCCESS; wait: while(1) { co_resume(); } }
/* * Attempt to authenticate the user using PAM. Returns 0 if the user is * authenticated, or 1 if not authenticated. If some sort of PAM system * error occurs (e.g., the "/etc/pam.conf" file is missing) then this * function returns -1. This can be used as an indication that we should * fall back to a different authentication mechanism. */ static int auth_pam(void) { const char *tmpl_user; const void *item; int rval; pam_err = pam_authenticate(pamh, pam_silent); switch (pam_err) { case PAM_SUCCESS: /* * With PAM we support the concept of a "template" * user. The user enters a login name which is * authenticated by PAM, usually via a remote service * such as RADIUS or TACACS+. If authentication * succeeds, a different but related "template" name * is used for setting the credentials, shell, and * home directory. The name the user enters need only * exist on the remote authentication server, but the * template name must be present in the local password * database. * * This is supported by two various mechanisms in the * individual modules. However, from the application's * point of view, the template user is always passed * back as a changed value of the PAM_USER item. */ pam_err = pam_get_item(pamh, PAM_USER, &item); if (pam_err == PAM_SUCCESS) { tmpl_user = (const char *)item; if (strcmp(username, tmpl_user) != 0) pwd = getpwnam(tmpl_user); } else { pam_syslog("pam_get_item(PAM_USER)"); } rval = 0; break; case PAM_AUTH_ERR: case PAM_USER_UNKNOWN: case PAM_MAXTRIES: rval = 1; break; default: pam_syslog("pam_authenticate()"); rval = -1; break; } if (rval == 0) { pam_err = pam_acct_mgmt(pamh, pam_silent); switch (pam_err) { case PAM_SUCCESS: break; case PAM_NEW_AUTHTOK_REQD: pam_err = pam_chauthtok(pamh, pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK); if (pam_err != PAM_SUCCESS) { pam_syslog("pam_chauthtok()"); rval = 1; } break; default: pam_syslog("pam_acct_mgmt()"); rval = 1; break; } } if (rval != 0) { pam_end(pamh, pam_err); pamh = NULL; } return (rval); }
static void authenticate (const struct passwd* pw) { const struct passwd* lpw = NULL; const char* cp, *srvname = NULL; int retval; switch (su_mode) { case SU_MODE: srvname = simulate_login ? PAM_SRVNAME_SU_L : PAM_SRVNAME_SU; break; case RUNUSER_MODE: srvname = simulate_login ? PAM_SRVNAME_RUNUSER_L : PAM_SRVNAME_RUNUSER; break; default: abort(); break; } retval = pam_start (srvname, pw->pw_name, &conv, &pamh); if (is_pam_failure(retval)) { goto done; } if (isatty (0) && (cp = ttyname (0)) != NULL) { const char* tty; if (strncmp (cp, "/dev/", 5) == 0) { tty = cp + 5; } else { tty = cp; } retval = pam_set_item (pamh, PAM_TTY, tty); if (is_pam_failure(retval)) { goto done; } } lpw = current_getpwuid (); if (lpw && lpw->pw_name) { retval = pam_set_item (pamh, PAM_RUSER, (const void*) lpw->pw_name); if (is_pam_failure(retval)) { goto done; } } if (su_mode == RUNUSER_MODE) { /* * This is the only difference between runuser(1) and su(1). The command * runuser(1) does not required authentication, because user is root. */ if (restricted) { errx(EXIT_FAILURE, _("may not be used by non-root users")); } return; } retval = pam_authenticate (pamh, 0); if (is_pam_failure(retval)) { goto done; } retval = pam_acct_mgmt (pamh, 0); if (retval == PAM_NEW_AUTHTOK_REQD) { /* Password has expired. Offer option to change it. */ retval = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } done: log_syslog(pw, !is_pam_failure(retval)); if (is_pam_failure(retval)) { const char* msg; log_btmp(pw); msg = pam_strerror(pamh, retval); pam_end(pamh, retval); sleep (getlogindefs_num ("FAIL_DELAY", 1)); errx (EXIT_FAILURE, "%s", msg ? msg : _("incorrect password")); } }
int main(int argc, char **argv) { struct sockaddr_storage peer_sa; struct sockaddr *peer = (struct sockaddr *)&peer_sa; int peerlen = sizeof(peer_sa); char user[1024]; char luser[1024]; char term[1024]; int port; struct passwd *pw; int err; char opt; char host[NI_MAXHOST]; char buf[4096]; int len; struct pollfd pfd[3]; struct winsize winsize; uint16_t winbuf[4]; int i; int master, slave; char *tty; pam_handle_t *handle; struct pam_conv conv = {conv_h, NULL}; const void *item; char *pamuser; int pid; argv0 = argv[0]; /* Process options */ while((opt = getopt(argc, argv, "+")) != -1) { switch(opt) { default: syslog(LOG_ERR, "Unknown option!"); usage(); return 1; } } if(optind != argc) { syslog(LOG_ERR, "Too many arguments!"); usage(); return 1; } /* Check source of connection */ if(getpeername(0, peer, &peerlen)) { syslog(LOG_ERR, "Can't get address of peer: %m"); return 1; } /* Unmap V4MAPPED addresses */ if(peer->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)peer)->sin6_addr)) { ((struct sockaddr_in *)peer)->sin_addr.s_addr = ((struct sockaddr_in6 *)peer)->sin6_addr.s6_addr32[3]; peer->sa_family = AF_INET; } /* Lookup hostname */ if((err = getnameinfo(peer, peerlen, host, sizeof(host), NULL, 0, 0))) { syslog(LOG_ERR, "Error resolving address: %s", gai_strerror(err)); return 1; } /* Check if connection comes from a privileged port */ switch(peer->sa_family) { case AF_INET: port = ntohs(((struct sockaddr_in *)peer)->sin_port); break; case AF_INET6: port = ntohs(((struct sockaddr_in6 *)peer)->sin6_port); break; default: port = -1; break; } if(port != -1 && (port < 512 || port >= 1024)) { syslog(LOG_ERR, "Connection from %s on illegal port %d.", host, port); return 1; } /* Wait for NULL byte */ if(read(0, buf, 1) != 1 || *buf) { syslog(LOG_ERR, "Didn't receive NULL byte from %s: %m\n", host); return 1; } /* Read usernames and terminal info */ if(readtonull(0, user, sizeof(user)) <= 0 || readtonull(0, luser, sizeof(luser)) <= 0) { syslog(LOG_ERR, "Error while receiving usernames from %s: %m", host); return 1; } if(readtonull(0, term, sizeof(term)) <= 0) { syslog(LOG_ERR, "Error while receiving terminal from %s: %m", host); return 1; } syslog(LOG_NOTICE, "Connection from %s@%s for %s", user, host, luser); /* We need to have a pty before we can use PAM */ if(openpty(&master, &slave, 0, 0, &winsize) != 0) { syslog(LOG_ERR, "Could not open pty: %m"); return 1; } tty = ttyname(slave); /* Start PAM */ if((err = pam_start("rlogin", luser, &conv, &handle)) != PAM_SUCCESS) { safewrite(1, "Authentication failure\n", 23); syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } pam_set_item(handle, PAM_USER, luser); pam_set_item(handle, PAM_RUSER, user); pam_set_item(handle, PAM_RHOST, host); pam_set_item(handle, PAM_TTY, tty); /* Write NULL byte to client so we can give a login prompt if necessary */ if(safewrite(1, "", 1) == -1) { syslog(LOG_ERR, "Unable to write NULL byte: %m"); return 1; } /* Try to authenticate */ err = pam_authenticate(handle, 0); /* PAM might ask for a new password */ if(err == PAM_NEW_AUTHTOK_REQD) { err = pam_chauthtok(handle, PAM_CHANGE_EXPIRED_AUTHTOK); if(err == PAM_SUCCESS) err = pam_authenticate(handle, 0); } if(err != PAM_SUCCESS) { safewrite(1, "Authentication failure\n", 23); syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } /* Check account */ err = pam_acct_mgmt(handle, 0); if(err != PAM_SUCCESS) { safewrite(1, "Authentication failure\n", 23); syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } /* PAM can map the user to a different user */ err = pam_get_item(handle, PAM_USER, &item); if(err != PAM_SUCCESS) { syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } pamuser = strdup((char *)item); if(!pamuser || !*pamuser) { syslog(LOG_ERR, "PAM didn't return a username?!"); return 1; } pw = getpwnam(pamuser); if (!pw) { syslog(LOG_ERR, "PAM_USER does not exist?!"); return 1; } if (setgid(pw->pw_gid)) { syslog(LOG_ERR, "setgid() failed: %m"); return 1; } if (initgroups(pamuser, pw->pw_gid)) { syslog(LOG_ERR, "initgroups() failed: %m"); return 1; } err = pam_setcred(handle, PAM_ESTABLISH_CRED); if(err != PAM_SUCCESS) { syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } /* Authentication succeeded */ pam_end(handle, PAM_SUCCESS); /* spawn login shell */ if((pid = fork()) < 0) { syslog(LOG_ERR, "fork() failed: %m"); return 1; } if(send(1, "\x80", 1, MSG_OOB) <= 0) { syslog(LOG_ERR, "Unable to write OOB \x80: %m"); return 1; } if(pid) { /* Parent process, still the rlogin server */ close(slave); /* Process input/output */ pfd[0].fd = 0; pfd[0].events = POLLIN | POLLERR | POLLHUP; pfd[1].fd = master; pfd[1].events = POLLIN | POLLERR | POLLHUP; for(;;) { errno = 0; if(poll(pfd, 2, -1) == -1) { if(errno == EINTR) continue; break; } if(pfd[0].revents) { len = read(0, buf, sizeof(buf)); if(len <= 0) break; /* Scan for control messages. Yes this is evil and should be done differently. */ for(i = 0; i < len - 11;) { if(buf[i++] == (char)0xFF) if(buf[i++] == (char)0xFF) if(buf[i++] == 's') if(buf[i++] == 's') { memcpy(winbuf, buf + i, 8); winsize.ws_row = ntohs(winbuf[0]); winsize.ws_col = ntohs(winbuf[1]); winsize.ws_xpixel = ntohs(winbuf[2]); winsize.ws_ypixel = ntohs(winbuf[3]); if(ioctl(master, TIOCSWINSZ, &winsize) == -1) break; memcpy(buf + i - 4, buf + i + 8, len - i - 8); i -= 4; len -= 12; } } if(safewrite(master, buf, len) == -1) break; pfd[0].revents = 0; } if(pfd[1].revents) { len = read(master, buf, sizeof(buf)); if(len <= 0) { errno = 0; break; } if(safewrite(1, buf, len) == -1) break; pfd[1].revents = 0; } } /* The end */ if(errno) { syslog(LOG_NOTICE, "Closing connection with %s@%s: %m", user, host); return 1; } else { syslog(LOG_NOTICE, "Closing connection with %s@%s", user, host); return 0; } close(master); } else { /* Child process, will become the shell */ char *speed; struct termios tios; char *envp[2]; /* Prepare tty for login */ close(master); if(login_tty(slave)) { syslog(LOG_ERR, "login_tty() failed: %m"); return 1; } /* Fix terminal type and speed */ tcgetattr(0, &tios); if((speed = strchr(term, '/'))) { *speed++ = '\0'; cfsetispeed(&tios, atoi(speed)); cfsetospeed(&tios, atoi(speed)); } tcsetattr(0, TCSADRAIN, &tios); /* Create environment */ asprintf(&envp[0], "TERM=%s", term); envp[1] = NULL; /* Spawn login process */ execle("/bin/login", "login", "-p", "-h", host, "-f", pamuser, NULL, envp); syslog(LOG_ERR, "Failed to spawn login process: %m"); return 1; } }
int main (int argc, char **argv) { #ifdef USE_PAM pam_handle_t *pamh = NULL; struct passwd *pampw; int retval; #endif /* * Get my name so that I can use it to report errors. */ Prog = Basename (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); #ifdef USE_PAM retval = PAM_SUCCESS; pampw = getpwuid (getuid ()); if (pampw == NULL) { retval = PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS) { retval = pam_start ("shadow", pampw->pw_name, &conv, &pamh); } if (retval == PAM_SUCCESS) { retval = pam_authenticate (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval == PAM_SUCCESS) { retval = pam_acct_mgmt (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval != PAM_SUCCESS) { fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); exit (1); } #endif /* USE_PAM */ OPENLOG (Prog); #ifdef SHADOWGRP is_shadow_grp = sgr_file_present (); #endif /* * The open routines for the DBM files don't use read-write as the * mode, so we have to clue them in. */ #ifdef NDBM gr_dbm_mode = O_RDWR; #ifdef SHADOWGRP sg_dbm_mode = O_RDWR; #endif /* SHADOWGRP */ #endif /* NDBM */ process_flags (argc, argv); /* * Start with a quick check to see if the group exists. */ if (getgrnam (group_name)) { if (fflg) { exit (E_SUCCESS); } fprintf (stderr, _("%s: group %s exists\n"), Prog, group_name); exit (E_NAME_IN_USE); } /* * Do the hard stuff - open the files, create the group entries, * then close and update the files. */ open_files (); if (!gflg || !oflg) find_new_gid (); grp_update (); close_files (); #ifdef USE_PAM if (retval == PAM_SUCCESS) { retval = pam_chauthtok (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval != PAM_SUCCESS) { fprintf (stderr, _("%s: PAM chauthtok failed\n"), Prog); exit (1); } if (retval == PAM_SUCCESS) pam_end (pamh, PAM_SUCCESS); #endif /* USE_PAM */ exit (E_SUCCESS); /*NOTREACHED*/ }
int main(int argc, char **argv) { hardened_shadow_openlog("su"); if (!hardened_shadow_get_current_username(¤t_username)) errx(EXIT_FAILURE, "Cannot determine your user name."); parse_args(argc, argv); uid_t my_uid = getuid(); bool is_root = (my_uid == 0); if (!is_root && (!isatty(STDIN_FILENO) || !ttyname(STDIN_FILENO))) errx(EXIT_FAILURE, "must be run from a terminal"); const struct pam_conv pam_conversation = { misc_conv, NULL }; pam_handle_t *pam_handle = NULL; int pam_rv = pam_start("su", target_username, &pam_conversation, &pam_handle); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_start: error %d", pam_rv); su_fatal(); } pam_rv = pam_set_item(pam_handle, PAM_TTY, ttyname(STDIN_FILENO)); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_set_item: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_set_item(pam_handle, PAM_RUSER, current_username); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_set_item: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_fail_delay(pam_handle, 1000000); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_fail_delay: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_authenticate(pam_handle, 0); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_acct_mgmt(pam_handle, 0); if (pam_rv != PAM_SUCCESS) { if (is_root) { warnx("%s (ignored)", pam_strerror(pam_handle, pam_rv)); } else if (pam_rv == PAM_NEW_AUTHTOK_REQD) { pam_rv = pam_chauthtok(pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_chauthtok: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } } else { hardened_shadow_syslog(LOG_ERR, "pam_acct_mgmt: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } } if (setgid(target_gid) != 0) { hardened_shadow_syslog(LOG_ERR, "bad group ID `%d' for user `%s': %s", target_gid, target_username, strerror(errno)); pam_rv = PAM_ABORT; goto pam_cleanup; } if (initgroups(target_username, target_gid) != 0) { hardened_shadow_syslog(LOG_ERR, "initgroups failed for user `%s': %s", target_username, strerror(errno)); pam_rv = PAM_ABORT; goto pam_cleanup; } pam_rv = pam_setcred(pam_handle, PAM_ESTABLISH_CRED); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_open_session(pam_handle, 0); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cred_cleanup; } char **pam_env = pam_getenvlist(pam_handle); if (!pam_env) errx(EXIT_FAILURE, "pam_getenvlist returned NULL"); struct environment_options environment_options = { .pam_environment = pam_env, .preserve_environment = preserve_environment, .login_shell = login_shell, .target_username = target_username, .target_homedir = target_homedir, .target_shell = shell, }; if (!hardened_shadow_prepare_environment(&environment_options)) { pam_rv = PAM_ABORT; goto pam_session_cleanup; } if (setuid(target_uid) != 0) { hardened_shadow_syslog(LOG_ERR, "bad user ID `%d' for user `%s': %s", target_uid, target_username, strerror(errno)); goto pam_session_cleanup; } int shell_argc = command ? 4 : 2; char **shell_argv = calloc(shell_argc, sizeof(*shell_argv)); if (!shell_argv) { hardened_shadow_syslog(LOG_ERR, "memory allocation failure"); goto pam_session_cleanup; } /* When argv[0] starts with a dash ("-"), bash will recognize * it as a login shell. This is what shadow-utils does. */ shell_argv[0] = login_shell ? "-su" : shell; if (command) { shell_argv[1] = "-c"; shell_argv[2] = command; } shell_argv[shell_argc - 1] = NULL; int status; if (!run_shell(shell, shell_argv, &status)) { pam_rv = PAM_ABORT; goto pam_session_cleanup; } free(shell_argv); pam_rv = pam_setcred(pam_handle, PAM_DELETE_CRED); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pam_handle, pam_rv)); pam_close_session(pam_handle, 0); pam_end(pam_handle, pam_rv); errx(EXIT_FAILURE, "pam_setcred"); } pam_rv = pam_close_session(pam_handle, 0); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pam_handle, pam_rv)); pam_end(pam_handle, pam_rv); errx(EXIT_FAILURE, "pam_close_session"); } pam_end(pam_handle, pam_rv); free(shell); free(current_username); free(target_username); free(target_homedir); hardened_shadow_closelog(); if (WIFEXITED(status)) return WEXITSTATUS(status); return WTERMSIG(status) + 128; pam_session_cleanup: pam_close_session(pam_handle, 0); pam_cred_cleanup: pam_setcred(pam_handle, PAM_DELETE_CRED); pam_cleanup: pam_end(pam_handle, pam_rv); su_fatal(); }
gchar * mdm_verify_user (MdmDisplay *d, const char *username, gboolean allow_retry) { gint pamerr = 0; struct passwd *pwent = NULL; char *login, *passreq; char *pam_stack = NULL; MDM_PAM_QUAL void *p; int null_tok = 0; gboolean credentials_set = FALSE; gboolean error_msg_given = FALSE; gboolean started_timer = FALSE; verify_user_again: pamerr = 0; login = NULL; error_msg_given = FALSE; credentials_set = FALSE; started_timer = FALSE; null_tok = 0; /* Don't start a timed login if we've already entered a username */ if (username != NULL) { login = g_strdup (username); mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login); } else { /* start the timer for timed logins */ if ( ! ve_string_empty (mdm_daemon_config_get_value_string (MDM_KEY_TIMED_LOGIN)) && d->timed_login_ok && (d->attached)) { mdm_slave_greeter_ctl_no_ret (MDM_STARTTIMER, ""); started_timer = TRUE; } } cur_mdm_disp = d; authenticate_again: if (prev_user && !login) { login = g_strdup (prev_user); } else if (login && !prev_user) { prev_user = g_strdup (login); auth_retries = 0; } else if (login && prev_user && strcmp (login, prev_user)) { g_free (prev_user); prev_user = g_strdup (login); auth_retries = 0; } /* * Initialize a PAM session for the user... * Get value per-display so different displays can use different * PAM Stacks, in case one display should use a different * authentication mechanism than another display. */ pam_stack = mdm_daemon_config_get_value_string_per_display (MDM_KEY_PAM_STACK, (char *)d->name); if ( ! create_pamh (d, pam_stack, login, &pamc, d->name, &pamerr)) { if (started_timer) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); g_free (pam_stack); goto pamerr; } g_free (pam_stack); /* * have to unset login otherwise there is no chance to ever enter * a different user */ g_free (login); login = NULL; pam_set_item (pamh, PAM_USER_PROMPT, _("Username:"******"PASSREQ="); if (mdm_daemon_config_get_value_bool (MDM_KEY_PASSWORD_REQUIRED) || ((passreq != NULL) && g_ascii_strcasecmp (passreq, "YES") == 0)) null_tok |= PAM_DISALLOW_NULL_AUTHTOK; mdm_verify_select_user (NULL); /* Start authentication session */ did_we_ask_for_password = FALSE; if ((pamerr = pam_authenticate (pamh, null_tok)) != PAM_SUCCESS) { if ( ! ve_string_empty (selected_user)) { pam_handle_t *tmp_pamh; /* Face browser was used to select a user, just completely rewhack everything since it seems various PAM implementations are having goats with just setting PAM_USER and trying to pam_authenticate again */ g_free (login); login = selected_user; selected_user = NULL; mdm_sigterm_block_push (); mdm_sigchld_block_push (); tmp_pamh = pamh; pamh = NULL; mdm_sigchld_block_pop (); mdm_sigterm_block_pop (); /* FIXME: what about errors */ /* really this has been a sucess, not a failure */ pam_end (tmp_pamh, pamerr); g_free (prev_user); prev_user = NULL; auth_retries = 0; mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login); goto authenticate_again; } if (started_timer) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); if (mdm_slave_action_pending ()) { /* FIXME: see note above about PAM_FAIL_DELAY */ /* #ifndef PAM_FAIL_DELAY */ mdm_sleep_no_signal (mdm_daemon_config_get_value_int (MDM_KEY_RETRY_DELAY)); /* wait up to 100ms randomly */ usleep (g_random_int_range (0, 100000)); /* #endif */ /* PAM_FAIL_DELAY */ mdm_error ("Couldn't authenticate user"); if (prev_user) { unsigned max_auth_retries = 3; char *val = mdm_read_default ("LOGIN_RETRIES="); if (val) { max_auth_retries = atoi (val); g_free (val); } if (allow_retry == FALSE || pamerr == PAM_MAXTRIES || ++auth_retries >= max_auth_retries) { g_free (prev_user); prev_user = NULL; auth_retries = 0; } } } else { /* cancel, configurator etc pressed */ g_free (prev_user); prev_user = NULL; auth_retries = 0; } goto pamerr; } /* stop the timer for timed logins */ if (started_timer) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); g_free (login); login = NULL; g_free (prev_user); prev_user = NULL; if ((pamerr = pam_get_item (pamh, PAM_USER, &p)) != PAM_SUCCESS) { login = NULL; /* is not really an auth problem, but it will pretty much look as such, it shouldn't really happen */ if (mdm_slave_action_pending ()) mdm_error ("Couldn't authenticate user"); goto pamerr; } login = g_strdup ((const char *)p); /* kind of anal, the greeter likely already knows, but it could have been changed */ mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login); if ( ! mdm_slave_check_user_wants_to_log_in (login)) { /* cleanup stuff */ mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, ""); g_free (login); login = NULL; mdm_slave_greeter_ctl_no_ret (MDM_RESETOK, ""); mdm_verify_cleanup (d); goto verify_user_again; } /* Check if user is root and is allowed to log in */ pwent = getpwnam (login); if (( ! mdm_daemon_config_get_value_bool (MDM_KEY_ALLOW_ROOT) || ( ! d->attached )) && (pwent != NULL && pwent->pw_uid == 0)) { mdm_error ("Root login disallowed on display '%s'", d->name); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator " "is not allowed to login " "from this screen")); /*mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG, _("Root login disallowed"));*/ error_msg_given = TRUE; goto pamerr; } if (mdm_daemon_config_get_value_bool (MDM_KEY_DISPLAY_LAST_LOGIN)) { char *info = mdm_get_last_info (login); mdm_slave_greeter_ctl_no_ret (MDM_MSG, info); g_free (info); } /* Check if the user's account is healthy. */ pamerr = pam_acct_mgmt (pamh, null_tok); switch (pamerr) { case PAM_SUCCESS : break; case PAM_NEW_AUTHTOK_REQD : if ((pamerr = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) { mdm_error ("Authentication token change failed for user %s", login); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe change of the authentication token failed. " "Please try again later or contact the system administrator.")); error_msg_given = TRUE; goto pamerr; } break; case PAM_ACCT_EXPIRED : mdm_error ("User %s no longer permitted to access the system", login); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator has disabled your account.")); error_msg_given = TRUE; goto pamerr; case PAM_PERM_DENIED : mdm_error ("User %s not permitted to gain access at this time", login); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator has disabled access to the system temporarily.")); error_msg_given = TRUE; goto pamerr; default : if (mdm_slave_action_pending ()) mdm_error ("Couldn't set acct. mgmt for %s", login); goto pamerr; } pwent = getpwnam (login); if (/* paranoia */ pwent == NULL || ! mdm_setup_gids (login, pwent->pw_gid)) { mdm_error ("Cannot set user group for %s", login); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nCannot set your user group; " "you will not be able to log in. " "Please contact your system administrator.")); goto pamerr; } did_setcred = TRUE; /* Set credentials */ pamerr = pam_setcred (pamh, PAM_ESTABLISH_CRED); if (pamerr != PAM_SUCCESS) { did_setcred = FALSE; if (mdm_slave_action_pending ()) mdm_error ("Couldn't set credentials for %s", login); goto pamerr; } credentials_set = TRUE; opened_session = TRUE; /* Register the session */ pamerr = pam_open_session (pamh, 0); if (pamerr != PAM_SUCCESS) { opened_session = FALSE; /* we handle this above */ did_setcred = FALSE; if (mdm_slave_action_pending ()) mdm_error ("Couldn't open session for %s", login); goto pamerr; } /* Workaround to avoid mdm messages being logged as PAM_pwdb */ mdm_log_shutdown (); mdm_log_init (); cur_mdm_disp = NULL; /* * Login succeeded. * This function is a no-op if libaudit is not present. */ log_to_audit_system(login, d->hostname, d->name, AU_SUCCESS); return login; pamerr: /* * Take care of situation where we get here before setting pwent. * Since login can be passed in as NULL, get the actual value if * possible. */ if ((pam_get_item (pamh, PAM_USER, &p)) == PAM_SUCCESS) { g_free (login); login = g_strdup ((const char *)p); } if (pwent == NULL && login != NULL) { pwent = getpwnam (login); } /* * Log the failed login attempt. * This function is a no-op if libaudit is not present. */ log_to_audit_system(login, d->hostname, d->name, AU_FAILED); /* The verbose authentication is turned on, output the error * message from the PAM subsystem */ if ( ! error_msg_given && mdm_slave_action_pending ()) { mdm_slave_write_utmp_wtmp_record (d, MDM_SESSION_RECORD_TYPE_FAILED_ATTEMPT, login, getpid ()); /* * I'm not sure yet if I should display this message for any * other issues - heeten * Adding AUTHINFO_UNAVAIL to the list - its what an unknown * user is. */ if (pamerr == PAM_AUTH_ERR || pamerr == PAM_USER_UNKNOWN || pamerr == PAM_AUTHINFO_UNAVAIL) { gboolean is_capslock = FALSE; const char *basemsg; char *msg; char *ret; ret = mdm_slave_greeter_ctl (MDM_QUERY_CAPSLOCK, ""); if ( ! ve_string_empty (ret)) is_capslock = TRUE; g_free (ret); /* Only give this message if we actually asked for password, otherwise it would be silly to say that the password may have been wrong */ if (did_we_ask_for_password) { basemsg = _("\nIncorrect username or password. " "Letters must be typed in the correct " "case."); } else { basemsg = _("\nAuthentication failed. " "Letters must be typed in the correct " "case."); } if (is_capslock) { msg = g_strconcat (basemsg, " ", _("Caps Lock is on."), NULL); } else { msg = g_strdup (basemsg); } mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, msg); g_free (msg); } else { mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG, _("Authentication failed")); } } did_setcred = FALSE; opened_session = FALSE; if (pamh != NULL) { pam_handle_t *tmp_pamh; mdm_sigterm_block_push (); mdm_sigchld_block_push (); tmp_pamh = pamh; pamh = NULL; mdm_sigchld_block_pop (); mdm_sigterm_block_pop (); /* Throw away the credentials */ if (credentials_set) pam_setcred (tmp_pamh, PAM_DELETE_CRED); pam_end (tmp_pamh, pamerr); } pamh = NULL; /* Workaround to avoid mdm messages being logged as PAM_pwdb */ mdm_log_shutdown (); mdm_log_init (); g_free (login); cur_mdm_disp = NULL; return NULL; }
int main(int argc, char *argv[]) { char hostname[MAXHOSTNAMELEN]; const char *user, *tty; const void *item; char **args, **pam_envlist, **pam_env; struct passwd *pwd; int o, pam_err, status; pid_t pid; while ((o = getopt(argc, argv, "")) != -1) switch (o) { default: usage(); } argc -= optind; argv += optind; if (argc > 0) { user = *argv; --argc; ++argv; } else { user = "******"; } /* initialize PAM */ pamc.conv = &openpam_ttyconv; pam_start("su", user, &pamc, &pamh); /* set some items */ gethostname(hostname, sizeof(hostname)); if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS) goto pamerr; user = getlogin(); if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS) goto pamerr; tty = ttyname(STDERR_FILENO); if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) goto pamerr; /* authenticate the applicant */ if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS) goto pamerr; if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD) pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); if (pam_err != PAM_SUCCESS) goto pamerr; /* establish the requested credentials */ if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) goto pamerr; /* authentication succeeded; open a session */ if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) goto pamerr; /* get mapped user name; PAM may have changed it */ pam_err = pam_get_item(pamh, PAM_USER, &item); if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user = item)) == NULL) goto pamerr; /* export PAM environment */ if ((pam_envlist = pam_getenvlist(pamh)) != NULL) { for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) { putenv(*pam_env); free(*pam_env); } free(pam_envlist); } /* build argument list */ if ((args = calloc(argc + 2, sizeof *args)) == NULL) { warn("calloc()"); goto err; } *args = pwd->pw_shell; memcpy(args + 1, argv, argc * sizeof *args); /* fork and exec */ switch ((pid = fork())) { case -1: warn("fork()"); goto err; case 0: /* child: give up privs and start a shell */ /* set uid and groups */ if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { warn("initgroups()"); _exit(1); } if (setgid(pwd->pw_gid) == -1) { warn("setgid()"); _exit(1); } if (setuid(pwd->pw_uid) == -1) { warn("setuid()"); _exit(1); } execve(*args, args, environ); warn("execve()"); _exit(1); default: /* parent: wait for child to exit */ waitpid(pid, &status, 0); /* close the session and release PAM resources */ pam_err = pam_close_session(pamh, 0); pam_end(pamh, pam_err); exit(WEXITSTATUS(status)); } pamerr: fprintf(stderr, "Sorry\n"); err: pam_end(pamh, pam_err); exit(1); }
int main(int argc, char **argv) { char hostname[MAXHOSTNAMELEN]; struct passwd *pwd = NULL; int o, pam_err; uid_t uid; while ((o = getopt(argc, argv, "d:h:loy")) != -1) switch (o) { case 'd': yp_domain = optarg; break; case 'h': yp_host = optarg; break; case 'l': case 'o': case 'y': /* compatibility */ break; default: usage(); } argc -= optind; argv += optind; uid = getuid(); switch (argc) { case 0: if ((pwd = getpwuid(uid)) == NULL) errx(1, "who are you?"); break; case 1: if ((pwd = getpwnam(*argv)) == NULL) errx(1, "%s: no such user", *argv); break; default: usage(); } if (uid != 0 && uid != pwd->pw_uid) errx(1, "permission denied"); /* check where the user's from */ switch (pwd->pw_fields & _PWF_SOURCE) { case _PWF_FILES: fprintf(stderr, "Changing local password for %s\n", pwd->pw_name); break; case _PWF_NIS: fprintf(stderr, "Changing NIS password for %s\n", pwd->pw_name); break; default: fprintf(stderr, "Changing password for %s\n", pwd->pw_name); } #define pam_check(func) do { \ if (pam_err != PAM_SUCCESS) { \ if (pam_err == PAM_AUTH_ERR || pam_err == PAM_PERM_DENIED || \ pam_err == PAM_AUTHTOK_RECOVERY_ERR) \ warnx("sorry"); \ else \ warnx("%s(): %s", func, pam_strerror(pamh, pam_err)); \ goto end; \ } \ } while (0) /* initialize PAM */ pam_err = pam_start("passwd", pwd->pw_name, &pamc, &pamh); pam_check("pam_start"); pam_err = pam_set_item(pamh, PAM_TTY, ttyname(STDERR_FILENO)); pam_check("pam_set_item"); gethostname(hostname, sizeof hostname); pam_err = pam_set_item(pamh, PAM_RHOST, hostname); pam_check("pam_set_item"); pam_err = pam_set_item(pamh, PAM_RUSER, getlogin()); pam_check("pam_set_item"); /* set YP domain and host */ pam_err = pam_set_data(pamh, "yp_domain", yp_domain, NULL); pam_check("pam_set_data"); pam_err = pam_set_data(pamh, "yp_server", yp_host, NULL); pam_check("pam_set_data"); /* set new password */ pam_err = pam_chauthtok(pamh, 0); pam_check("pam_chauthtok"); end: pam_end(pamh, pam_err); exit(pam_err == PAM_SUCCESS ? 0 : 1); }
/* * Authentication thread. */ static void * sshpam_thread(void *ctxtp) { struct pam_ctxt *ctxt = ctxtp; Buffer buffer; struct pam_conv sshpam_conv; int flags = (options.permit_empty_passwd == 0 ? PAM_DISALLOW_NULL_AUTHTOK : 0); #ifndef UNSUPPORTED_POSIX_THREADS_HACK extern char **environ; char **env_from_pam; u_int i; const char *pam_user; const char **ptr_pam_user = &pam_user; char *tz = getenv("TZ"); sshpam_err = pam_get_item(sshpam_handle, PAM_USER, (sshpam_const void **)ptr_pam_user); if (sshpam_err != PAM_SUCCESS) goto auth_fail; environ[0] = NULL; if (tz != NULL) if (setenv("TZ", tz, 1) == -1) error("PAM: could not set TZ environment: %s", strerror(errno)); if (sshpam_authctxt != NULL) { setproctitle("%s [pam]", sshpam_authctxt->valid ? pam_user : "******"); } #endif sshpam_conv.conv = sshpam_thread_conv; sshpam_conv.appdata_ptr = ctxt; if (sshpam_authctxt == NULL) fatal("%s: PAM authctxt not initialized", __func__); buffer_init(&buffer); sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, (const void *)&sshpam_conv); if (sshpam_err != PAM_SUCCESS) goto auth_fail; sshpam_err = pam_authenticate(sshpam_handle, flags); if (sshpam_err != PAM_SUCCESS) goto auth_fail; if (compat20) { if (!do_pam_account()) { sshpam_err = PAM_ACCT_EXPIRED; goto auth_fail; } if (sshpam_authctxt->force_pwchange) { sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); if (sshpam_err != PAM_SUCCESS) goto auth_fail; sshpam_password_change_required(0); } } buffer_put_cstring(&buffer, "OK"); #ifndef UNSUPPORTED_POSIX_THREADS_HACK /* Export variables set by do_pam_account */ buffer_put_int(&buffer, sshpam_account_status); buffer_put_int(&buffer, sshpam_authctxt->force_pwchange); /* Export any environment strings set in child */ for(i = 0; environ[i] != NULL; i++) ; /* Count */ buffer_put_int(&buffer, i); for(i = 0; environ[i] != NULL; i++) buffer_put_cstring(&buffer, environ[i]); /* Export any environment strings set by PAM in child */ env_from_pam = pam_getenvlist(sshpam_handle); for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) ; /* Count */ buffer_put_int(&buffer, i); for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) buffer_put_cstring(&buffer, env_from_pam[i]); #endif /* UNSUPPORTED_POSIX_THREADS_HACK */ /* XXX - can't do much about an error here */ ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer); buffer_free(&buffer); pthread_exit(NULL); auth_fail: buffer_put_cstring(&buffer, pam_strerror(sshpam_handle, sshpam_err)); /* XXX - can't do much about an error here */ if (sshpam_err == PAM_ACCT_EXPIRED) ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer); else ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); buffer_free(&buffer); pthread_exit(NULL); return (NULL); /* Avoid warning for non-pthread case */ }
int main(int argc, char **argv) { pam_handle_t *pamh=NULL; char *username=NULL; int retcode; /* did the user call with a username as an argument ? */ if (argc > 2) { fprintf(stderr,"usage: %s [username]\n",argv[0]); } else if (argc == 2) { username = argv[1]; } /* initialize the Linux-PAM library */ retcode = pam_start("blank", username, &conv, &pamh); bail_out(pamh,1,retcode,"pam_start"); /* test the environment stuff */ { #define MAXENV 15 const char *greek[MAXENV] = { "a=alpha", "b=beta", "c=gamma", "d=delta", "e=epsilon", "f=phi", "g=psi", "h=eta", "i=iota", "j=mu", "k=nu", "l=zeta", "h=", "d", "k=xi" }; char **env; int i; for (i=0; i<MAXENV; ++i) { retcode = pam_putenv(pamh,greek[i]); bail_out(pamh,0,retcode,"pam_putenv"); } env = pam_getenvlist(pamh); if (env) env = pam_misc_drop_env(env); else fprintf(stderr,"???\n"); fprintf(stderr,"a test: c=[%s], j=[%s]\n" , pam_getenv(pamh, "c"), pam_getenv(pamh, "j")); } /* to avoid using goto we abuse a loop here */ for (;;) { /* authenticate the user --- `0' here, could have been PAM_SILENT * | PAM_DISALLOW_NULL_AUTHTOK */ retcode = pam_authenticate(pamh, 0); bail_out(pamh,0,retcode,"pam_authenticate"); /* has the user proved themself valid? */ if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: invalid request\n",argv[0]); break; } /* the user is valid, but should they have access at this time? */ retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */ bail_out(pamh,0,retcode,"pam_acct_mgmt"); if (retcode == PAM_NEW_AUTHTOK_REQD) { fprintf(stderr,"Application must request new password...\n"); retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK); bail_out(pamh,0,retcode,"pam_chauthtok"); } if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: invalid request\n",argv[0]); break; } /* `0' could be as above */ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); bail_out(pamh,0,retcode,"pam_setcred1"); if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: problem setting user credentials\n" ,argv[0]); break; } /* open a session for the user --- `0' could be PAM_SILENT */ retcode = pam_open_session(pamh,0); bail_out(pamh,0,retcode,"pam_open_session"); if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: problem opening a session\n",argv[0]); break; } fprintf(stderr,"The user has been authenticated and `logged in'\n"); /* close a session for the user --- `0' could be PAM_SILENT * it is possible that this pam_close_call is in another program.. */ retcode = pam_close_session(pamh,0); bail_out(pamh,0,retcode,"pam_close_session"); if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: problem closing a session\n",argv[0]); break; } retcode = pam_setcred(pamh, PAM_DELETE_CRED); bail_out(pamh,0,retcode,"pam_setcred2"); break; /* don't go on for ever! */ } /* close the Linux-PAM library */ retcode = pam_end(pamh, PAM_SUCCESS); pamh = NULL; bail_out(pamh,1,retcode,"pam_end"); exit(0); }
void pwpam_process(const char *username, int argc, char **argv) { int ch, pam_err; char hostname[MAXHOSTNAMELEN + 1]; /* details about the invoking user for logging */ const uid_t i_uid = getuid(); const struct passwd *const i_pwd = getpwuid(i_uid); const char *const i_username = (i_pwd && i_pwd->pw_name) ? i_pwd->pw_name : "(null)"; while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; switch (argc) { case 0: /* username already provided */ break; case 1: username = argv[0]; break; default: usage(); /* NOTREACHED */ } (void)printf("Changing password for %s.\n", username); /* initialize PAM -- always use the program name "passwd" */ pam_err = pam_start("passwd", username, &pamc, &pamh); if (pam_err != PAM_SUCCESS) errx(1, "unable to start PAM session: %s", pam_strerror(NULL, pam_err)); pam_err = pam_set_item(pamh, PAM_TTY, ttyname(STDERR_FILENO)); pam_check("unable to set TTY"); (void)gethostname(hostname, sizeof hostname); pam_err = pam_set_item(pamh, PAM_RHOST, hostname); pam_check("unable to set RHOST"); pam_err = pam_set_item(pamh, PAM_RUSER, getlogin()); pam_check("unable to set RUSER"); /* set new password */ pam_err = pam_chauthtok(pamh, 0); if (pam_err != PAM_SUCCESS) { if (pam_err == PAM_PERM_DENIED) { syslog(LOG_AUTH | LOG_NOTICE, "user %s (UID %lu) failed to change the " "PAM authentication token of user %s: %s", i_username, (unsigned long)i_uid, username, pam_strerror(pamh, pam_err)); } printf("Unable to change auth token: %s\n", pam_strerror(pamh, pam_err)); } else { syslog(LOG_AUTH | LOG_INFO, "user %s (UID %lu) successfully changed the " "PAM authentication token of user %s", i_username, (unsigned long)i_uid, username); } end: pam_end(pamh, pam_err); if (pam_err == PAM_SUCCESS) return; exit(1); }
gboolean mdm_verify_setup_user (MdmDisplay *d, const gchar *login, char **new_login) { gint pamerr = 0; struct passwd *pwent = NULL; MDM_PAM_QUAL void *p; char *passreq; char *pam_stack = NULL; char *pam_service_name = NULL; int null_tok = 0; gboolean credentials_set; const char *after_login; credentials_set = FALSE; *new_login = NULL; if (login == NULL) return FALSE; cur_mdm_disp = d; g_free (extra_standalone_message); extra_standalone_message = g_strdup_printf ("%s (%s)", _("Automatic login"), login); /* * Initialize a PAM session for the user... * Get value per-display so different displays can use different * PAM Stacks, in case one display should use a different * authentication mechanism than another display. */ pam_stack = mdm_daemon_config_get_value_string_per_display (MDM_KEY_PAM_STACK, (char *)d->name); pam_service_name = g_strdup_printf ("%s-autologin", pam_stack); if ( ! create_pamh (d, pam_service_name, login, &standalone_pamc, d->name, &pamerr)) { g_free (pam_stack); g_free (pam_service_name); goto setup_pamerr; } g_free (pam_stack); g_free (pam_service_name); passreq = mdm_read_default ("PASSREQ="); if (mdm_daemon_config_get_value_bool (MDM_KEY_PASSWORD_REQUIRED) || ((passreq != NULL) && g_ascii_strcasecmp (passreq, "YES") == 0)) null_tok |= PAM_DISALLOW_NULL_AUTHTOK; /* Start authentication session */ did_we_ask_for_password = FALSE; if ((pamerr = pam_authenticate (pamh, null_tok)) != PAM_SUCCESS) { if (mdm_slave_action_pending ()) { mdm_error ("Couldn't authenticate user"); mdm_errorgui_error_box (cur_mdm_disp, GTK_MESSAGE_ERROR, _("Authentication failed")); } goto setup_pamerr; } if ((pamerr = pam_get_item (pamh, PAM_USER, &p)) != PAM_SUCCESS) { /* is not really an auth problem, but it will pretty much look as such, it shouldn't really happen */ mdm_error ("Couldn't authenticate user"); mdm_errorgui_error_box (cur_mdm_disp, GTK_MESSAGE_ERROR, _("Authentication failed")); goto setup_pamerr; } after_login = p; if (after_login != NULL /* should never be */ && strcmp (after_login, login) != 0) { *new_login = g_strdup (after_login); } /* Check if the user's account is healthy. */ pamerr = pam_acct_mgmt (pamh, null_tok); switch (pamerr) { case PAM_SUCCESS : break; case PAM_NEW_AUTHTOK_REQD : /* XXX: this is for automatic and timed logins, * we shouldn't be asking for new pw since we never * authenticated the user. I suppose just ignoring * this would be OK */ #if 0 /* don't change password */ if ((pamerr = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) { mdm_error ("Authentication token change failed for user %s", login); mdm_errorgui_error_box (cur_mdm_disp, GTK_MESSAGE_ERROR, _("\nThe change of the authentication token failed. " "Please try again later or contact the system administrator.")); goto setup_pamerr; } #endif /* 0 */ break; case PAM_ACCT_EXPIRED : mdm_error ("User %s no longer permitted to access the system", login); mdm_errorgui_error_box (cur_mdm_disp, GTK_MESSAGE_ERROR, _("The system administrator has disabled your account.")); goto setup_pamerr; case PAM_PERM_DENIED : mdm_error ("User %s not permitted to gain access at this time", login); mdm_errorgui_error_box (cur_mdm_disp, GTK_MESSAGE_ERROR, _("The system administrator has disabled your access to the system temporarily.")); goto setup_pamerr; default : if (mdm_slave_action_pending ()) mdm_error ("Couldn't set acct. mgmt for %s", login); goto setup_pamerr; } pwent = getpwnam (login); if (/* paranoia */ pwent == NULL || ! mdm_setup_gids (login, pwent->pw_gid)) { mdm_error ("Cannot set user group for %s", login); mdm_errorgui_error_box (cur_mdm_disp, GTK_MESSAGE_ERROR, _("Cannot set your user group; " "you will not be able to log in. " "Please contact your system administrator.")); goto setup_pamerr; } did_setcred = TRUE; /* Set credentials */ pamerr = pam_setcred (pamh, PAM_ESTABLISH_CRED); if (pamerr != PAM_SUCCESS) { did_setcred = FALSE; if (mdm_slave_action_pending ()) mdm_error ("Couldn't set credentials for %s", login); goto setup_pamerr; } credentials_set = TRUE; opened_session = TRUE; /* Register the session */ pamerr = pam_open_session (pamh, 0); if (pamerr != PAM_SUCCESS) { did_setcred = FALSE; opened_session = FALSE; /* Throw away the credentials */ pam_setcred (pamh, PAM_DELETE_CRED); if (mdm_slave_action_pending ()) mdm_error ("Couldn't open session for %s", login); goto setup_pamerr; } /* Workaround to avoid mdm messages being logged as PAM_pwdb */ mdm_log_shutdown (); mdm_log_init (); cur_mdm_disp = NULL; g_free (extra_standalone_message); extra_standalone_message = NULL; /* * Login succeeded. * This function is a no-op if libaudit is not present */ log_to_audit_system(login, d->hostname, d->name, AU_SUCCESS); return TRUE; setup_pamerr: /* * Take care of situation where we get here before setting pwent. * Note login is never NULL when this function is called. */ if (pwent == NULL) { pwent = getpwnam (login); } /* * Log the failed login attempt. * This function is a no-op if libaudit is not present */ log_to_audit_system(login, d->hostname, d->name, AU_FAILED); did_setcred = FALSE; opened_session = FALSE; if (pamh != NULL) { pam_handle_t *tmp_pamh; mdm_sigterm_block_push (); mdm_sigchld_block_push (); tmp_pamh = pamh; pamh = NULL; mdm_sigchld_block_pop (); mdm_sigterm_block_pop (); /* Throw away the credentials */ if (credentials_set) pam_setcred (tmp_pamh, PAM_DELETE_CRED); pam_end (tmp_pamh, pamerr); } pamh = NULL; /* Workaround to avoid mdm messages being logged as PAM_pwdb */ mdm_log_shutdown (); mdm_log_init (); cur_mdm_disp = NULL; g_free (extra_standalone_message); extra_standalone_message = NULL; return FALSE; }
int main (int argc, char *argv[]) { int retcode; int ret; pam_handle_t *pamh; char *username; char *hostname; char *tty_name; char *ttyn; struct pam_conv conv = { misc_conv, NULL }; int failcount; ret = 1; username = NULL; hostname = NULL; tty_name = NULL; retcode = pam_start ("login", username, &conv, &pamh); if (retcode != PAM_SUCCESS) { fprintf (stderr, "login: PAM Failure, aborting: %s\n", pam_strerror (pamh, retcode)); exit (99); } ttyn = ttyname (0); if (strncmp (ttyn, _PATH_DEV, 5) == 0) { tty_name = ttyn + 5; } else { tty_name = ttyn; } retcode = pam_set_item (pamh, PAM_RHOST, hostname); PAM_FAIL_CHECK; retcode = pam_set_item (pamh, PAM_TTY, tty_name); PAM_FAIL_CHECK; pam_set_item (pamh, PAM_USER, NULL); retcode = pam_set_item (pamh, PAM_USER_PROMPT, "Username: "******"Login incorrect\n\n"); pam_set_item (pamh, PAM_USER, NULL); retcode = pam_authenticate (pamh, 0); } if (retcode != PAM_SUCCESS) { fprintf (stderr, "\nLogin incorrect\n"); pam_end (pamh, retcode); exit (0); } retcode = pam_acct_mgmt (pamh, 0); if (retcode == PAM_NEW_AUTHTOK_REQD) { retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } PAM_FAIL_CHECK; pam_putenv (pamh, "CKCON_TTY=/dev/tty55"); pam_putenv (pamh, "CKCON_X11_DISPLAY=:50"); retcode = pam_open_session (pamh, 0); PAM_FAIL_CHECK; retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED); PAM_FAIL_CHECK; pam_get_item (pamh, PAM_USER, (const void **) &username); printf ("Session opened for %s\n", username); printf ("sleeping for 20 seconds..."); sleep (20); PAM_END; printf ("\nSession closed\n"); return ret; }
/* * login - create a new login session for a user * * login is typically called by getty as the second step of a * new user session. getty is responsible for setting the line * characteristics to a reasonable set of values and getting * the name of the user to be logged in. login may also be * called to create a new user session on a pty for a variety * of reasons, such as X servers or network logins. * * the flags which login supports are * * -p - preserve the environment * -r - perform autologin protocol for rlogin * -f - do not perform authentication, user is preauthenticated * -h - the name of the remote host */ int main (int argc, char **argv) { const char *tmptty; char tty[BUFSIZ]; #ifdef RLOGIN char term[128] = ""; #endif /* RLOGIN */ #if defined(HAVE_STRFTIME) && !defined(USE_PAM) char ptime[80]; #endif unsigned int delay; unsigned int retries; bool failed; bool subroot = false; #ifndef USE_PAM bool is_console; #endif int err; const char *cp; char *tmp; char fromhost[512]; struct passwd *pwd = NULL; char **envp = environ; const char *failent_user; /*@null@*/struct utmp *utent; #ifdef USE_PAM int retcode; pid_t child; char *pam_user = NULL; #else struct spwd *spwd = NULL; #endif /* * Some quick initialization. */ sanitize_env (); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); initenv (); amroot = (getuid () == 0); Prog = Basename (argv[0]); if (geteuid() != 0) { fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog); exit (1); } process_flags (argc, argv); if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) { exit (1); /* must be a terminal */ } utent = get_current_utmp (); /* * Be picky if run by normal users (possible if installed setuid * root), but not if run by root. This way it still allows logins * even if your getty is broken, or if something corrupts utmp, * but users must "exec login" which will use the existing utmp * entry (will not overwrite remote hostname). --marekm */ if (!amroot && (NULL == utent)) { (void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\"")); exit (1); } /* NOTE: utent might be NULL afterwards */ tmptty = ttyname (0); if (NULL == tmptty) { tmptty = "UNKNOWN"; } STRFCPY (tty, tmptty); #ifndef USE_PAM is_console = console (tty); #endif if (rflg || hflg) { /* * Add remote hostname to the environment. I think * (not sure) I saw it once on Irix. --marekm */ addenv ("REMOTEHOST", hostname); } if (fflg) { preauth_flag = true; } if (hflg) { reason = PW_RLOGIN; } #ifdef RLOGIN if (rflg) { assert (NULL == username); username = xmalloc (USER_NAME_MAX_LENGTH + 1); username[USER_NAME_MAX_LENGTH] = '\0'; if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) { preauth_flag = true; } else { free (username); username = NULL; } } #endif /* RLOGIN */ OPENLOG ("login"); setup_tty (); #ifndef USE_PAM (void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); { /* * Use the ULIMIT in the login.defs file, and if * there isn't one, use the default value. The * user may have one for themselves, but otherwise, * just take what you get. */ long limit = getdef_long ("ULIMIT", -1L); if (limit != -1) { set_filesize_limit (limit); } } #endif /* * The entire environment will be preserved if the -p flag * is used. */ if (pflg) { while (NULL != *envp) { /* add inherited environment, */ addenv (*envp, NULL); /* some variables change later */ envp++; } } #ifdef RLOGIN if (term[0] != '\0') { addenv ("TERM", term); } else #endif /* RLOGIN */ { /* preserve TERM from getty */ if (!pflg) { tmp = getenv ("TERM"); if (NULL != tmp) { addenv ("TERM", tmp); } } } init_env (); if (optind < argc) { /* now set command line variables */ set_env (argc - optind, &argv[optind]); } if (rflg || hflg) { cp = hostname; #ifdef HAVE_STRUCT_UTMP_UT_HOST } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) { cp = utent->ut_host; #endif /* HAVE_STRUCT_UTMP_UT_HOST */ } else { cp = ""; } if ('\0' != *cp) { snprintf (fromhost, sizeof fromhost, " on '%.100s' from '%.200s'", tty, cp); } else { snprintf (fromhost, sizeof fromhost, " on '%.100s'", tty); } top: /* only allow ALARM sec. for login */ (void) signal (SIGALRM, alarm_handler); timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM); if (timeout > 0) { (void) alarm (timeout); } environ = newenvp; /* make new environment active */ delay = getdef_unum ("FAIL_DELAY", 1); retries = getdef_unum ("LOGIN_RETRIES", RETRIES); #ifdef USE_PAM retcode = pam_start ("login", username, &conv, &pamh); if (retcode != PAM_SUCCESS) { fprintf (stderr, _("login: PAM Failure, aborting: %s\n"), pam_strerror (pamh, retcode)); SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s", pam_strerror (pamh, retcode))); exit (99); } /* * hostname & tty are either set to NULL or their correct values, * depending on how much we know. We also set PAM's fail delay to * ours. * * PAM_RHOST and PAM_TTY are used for authentication, only use * information coming from login or from the caller (e.g. no utmp) */ retcode = pam_set_item (pamh, PAM_RHOST, hostname); PAM_FAIL_CHECK; retcode = pam_set_item (pamh, PAM_TTY, tty); PAM_FAIL_CHECK; #ifdef HAS_PAM_FAIL_DELAY retcode = pam_fail_delay (pamh, 1000000 * delay); PAM_FAIL_CHECK; #endif /* if fflg, then the user has already been authenticated */ if (!fflg) { unsigned int failcount = 0; char hostn[256]; char loginprompt[256]; /* That's one hell of a prompt :) */ /* Make the login prompt look like we want it */ if (gethostname (hostn, sizeof (hostn)) == 0) { snprintf (loginprompt, sizeof (loginprompt), _("%s login: "******"login: "******"TOO MANY LOGIN TRIES (%u)%s FOR '%s'", failcount, fromhost, failent_user)); fprintf(stderr, _("Maximum number of tries exceeded (%u)\n"), failcount); PAM_END; exit(0); } else if (retcode == PAM_ABORT) { /* Serious problems, quit now */ (void) fputs (_("login: abort requested by PAM\n"), stderr); SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()")); PAM_END; exit(99); } else if (retcode != PAM_SUCCESS) { SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%u)%s FOR '%s', %s", failcount, fromhost, failent_user, pam_strerror (pamh, retcode))); failed = true; } if (!failed) { break; } #ifdef WITH_AUDIT audit_fd = audit_open (); audit_log_acct_message (audit_fd, AUDIT_USER_LOGIN, NULL, /* Prog. name */ "login", failent_user, AUDIT_NO_ID, hostname, NULL, /* addr */ tty, 0); /* result */ close (audit_fd); #endif /* WITH_AUDIT */ (void) puts (""); (void) puts (_("Login incorrect")); if (failcount >= retries) { SYSLOG ((LOG_NOTICE, "TOO MANY LOGIN TRIES (%u)%s FOR '%s'", failcount, fromhost, failent_user)); fprintf(stderr, _("Maximum number of tries exceeded (%u)\n"), failcount); PAM_END; exit(0); } /* * Let's give it another go around. * Even if a username was given on the command * line, prompt again for the username. */ retcode = pam_set_item (pamh, PAM_USER, NULL); PAM_FAIL_CHECK; } /* We don't get here unless they were authenticated above */ (void) alarm (0); } /* Check the account validity */ retcode = pam_acct_mgmt (pamh, 0); if (retcode == PAM_NEW_AUTHTOK_REQD) { retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } PAM_FAIL_CHECK; /* Open the PAM session */ get_pam_user (&pam_user); retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0); PAM_FAIL_CHECK; /* Grab the user information out of the password file for future usage * First get the username that we are actually using, though. * * From now on, we will discard changes of the user (PAM_USER) by * PAM APIs. */ get_pam_user (&pam_user); if (NULL != username) { free (username); } username = pam_user; failent_user = get_failent_user (username); pwd = xgetpwnam (username); if (NULL == pwd) { SYSLOG ((LOG_ERR, "cannot find user %s", failent_user)); exit (1); } /* This set up the process credential (group) and initialize the * supplementary group access list. * This has to be done before pam_setcred */ if (setup_groups (pwd) != 0) { exit (1); } retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED); PAM_FAIL_CHECK; /* NOTE: If pam_setcred changes PAM_USER, this will not be taken * into account. */ #else /* ! USE_PAM */ while (true) { /* repeatedly get login/password pairs */ /* user_passwd is always a pointer to this constant string * or a passwd or shadow password that will be memzero by * pw_free / spw_free. * Do not free() user_passwd. */ const char *user_passwd = "!"; /* Do some cleanup to avoid keeping entries we do not need * anymore. */ if (NULL != pwd) { pw_free (pwd); pwd = NULL; } if (NULL != spwd) { spw_free (spwd); spwd = NULL; } failed = false; /* haven't failed authentication yet */ if (NULL == username) { /* need to get a login id */ if (subroot) { closelog (); exit (1); } preauth_flag = false; username = xmalloc (USER_NAME_MAX_LENGTH + 1); username[USER_NAME_MAX_LENGTH] = '\0'; login_prompt (_("\n%s login: "******"!", * the account is locked and the user cannot * login, even if they have been * "pre-authenticated." */ if ( ('!' == user_passwd[0]) || ('*' == user_passwd[0])) { failed = true; } } if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) { spwd = xgetspnam (username); if (NULL != spwd) { user_passwd = spwd->sp_pwdp; } else { /* The user exists in passwd, but not in * shadow. SHADOW_PASSWD_STRING indicates * that the password shall be in shadow. */ SYSLOG ((LOG_WARN, "no shadow password for '%s'%s", username, fromhost)); } } /* * The -r and -f flags provide a name which has already * been authenticated by some server. */ if (preauth_flag) { goto auth_ok; } if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) { goto auth_ok; } SYSLOG ((LOG_WARN, "invalid password for '%s' %s", failent_user, fromhost)); failed = true; auth_ok: /* * This is the point where all authenticated users wind up. * If you reach this far, your password has been * authenticated and so on. */ if ( !failed && (NULL != pwd) && (0 == pwd->pw_uid) && !is_console) { SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost)); failed = true; } if ( !failed && !login_access (username, ('\0' != *hostname) ? hostname : tty)) { SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s", username, fromhost)); failed = true; } if ( (NULL != pwd) && getdef_bool ("FAILLOG_ENAB") && !failcheck (pwd->pw_uid, &faillog, failed)) { SYSLOG ((LOG_CRIT, "exceeded failure limit for '%s' %s", username, fromhost)); failed = true; } if (!failed) { break; } /* don't log non-existent users */ if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) { failure (pwd->pw_uid, tty, &faillog); } if (getdef_str ("FTMP_FILE") != NULL) { #ifdef USE_UTMPX struct utmpx *failent = prepare_utmpx (failent_user, tty, /* FIXME: or fromhost? */hostname, utent); #else /* !USE_UTMPX */ struct utmp *failent = prepare_utmp (failent_user, tty, hostname, utent); #endif /* !USE_UTMPX */ failtmp (failent_user, failent); free (failent); } retries--; if (retries <= 0) { SYSLOG ((LOG_CRIT, "REPEATED login failures%s", fromhost)); } /* * If this was a passwordless account and we get here, login * was denied (securetty, faillog, etc.). There was no * password prompt, so do it now (will always fail - the bad * guys won't see that the passwordless account exists at * all). --marekm */ if (user_passwd[0] == '\0') { pw_auth ("!", username, reason, (char *) 0); } /* * Authentication of this user failed. * The username must be confirmed in the next try. */ free (username); username = NULL; /* * Wait a while (a la SVR4 /usr/bin/login) before attempting * to login the user again. If the earlier alarm occurs * before the sleep() below completes, login will exit. */ if (delay > 0) { (void) sleep (delay); } (void) puts (_("Login incorrect")); /* allow only one attempt with -r or -f */ if (rflg || fflg || (retries <= 0)) { closelog (); exit (1); } } /* while (true) */ #endif /* ! USE_PAM */ assert (NULL != username); assert (NULL != pwd); (void) alarm (0); /* turn off alarm clock */ #ifndef USE_PAM /* PAM does this */ /* * porttime checks moved here, after the user has been * authenticated. now prints a message, as suggested * by Ivan Nejgebauer <*****@*****.**>. --marekm */ if ( getdef_bool ("PORTTIME_CHECKS_ENAB") && !isttytime (username, tty, time ((time_t *) 0))) { SYSLOG ((LOG_WARN, "invalid login time for '%s'%s", username, fromhost)); closelog (); bad_time_notify (); exit (1); } check_nologin (pwd->pw_uid == 0); #endif if (getenv ("IFS")) { /* don't export user IFS ... */ addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */ } if (pwd->pw_shell[0] == '*') { /* subsystem root */ pwd->pw_shell++; /* skip the '*' */ subsystem (pwd); /* figure out what to execute */ subroot = true; /* say I was here again */ endpwent (); /* close all of the file which were */ endgrent (); /* open in the original rooted file */ endspent (); /* system. they will be re-opened */ #ifdef SHADOWGRP endsgent (); /* in the new rooted file system */ #endif goto top; /* go do all this all over again */ } #ifdef WITH_AUDIT audit_fd = audit_open (); audit_log_acct_message (audit_fd, AUDIT_USER_LOGIN, NULL, /* Prog. name */ "login", username, AUDIT_NO_ID, hostname, NULL, /* addr */ tty, 1); /* result */ close (audit_fd); #endif /* WITH_AUDIT */ #ifndef USE_PAM /* pam_lastlog handles this */ if (getdef_bool ("LASTLOG_ENAB")) { /* give last login and log this one */ dolastlog (&ll, pwd, tty, hostname); } #endif #ifndef USE_PAM /* PAM handles this as well */ /* * Have to do this while we still have root privileges, otherwise we * don't have access to /etc/shadow. */ if (NULL != spwd) { /* check for age of password */ if (expire (pwd, spwd)) { /* The user updated her password, get the new * entries. * Use the x variants because we need to keep the * entry for a long time, and there might be other * getxxyy in between. */ pw_free (pwd); pwd = xgetpwnam (username); if (NULL == pwd) { SYSLOG ((LOG_ERR, "cannot find user %s after update of expired password", username)); exit (1); } spw_free (spwd); spwd = xgetspnam (username); } } setup_limits (pwd); /* nice, ulimit etc. */ #endif /* ! USE_PAM */ chown_tty (pwd); #ifdef USE_PAM /* * We must fork before setuid() because we need to call * pam_close_session() as root. */ (void) signal (SIGINT, SIG_IGN); child = fork (); if (child < 0) { /* error in fork() */ fprintf (stderr, _("%s: failure forking: %s"), Prog, strerror (errno)); PAM_END; exit (0); } else if (child != 0) { /* * parent - wait for child to finish, then cleanup * session */ wait (NULL); PAM_END; exit (0); } /* child */ #endif /* If we were init, we need to start a new session */ if (getppid() == 1) { setsid(); if (ioctl(0, TIOCSCTTY, 1) != 0) { fprintf (stderr, _("TIOCSCTTY failed on %s"), tty); } } /* * The utmp entry needs to be updated to indicate the new status * of the session, the new PID and SID. */ update_utmp (username, tty, hostname, utent); /* The pwd and spwd entries for the user have been copied. * * Close all the files so that unauthorized access won't occur. */ endpwent (); /* stop access to password file */ endgrent (); /* stop access to group file */ endspent (); /* stop access to shadow passwd file */ #ifdef SHADOWGRP endsgent (); /* stop access to shadow group file */ #endif /* Drop root privileges */ #ifndef USE_PAM if (setup_uid_gid (pwd, is_console)) #else /* The group privileges were already dropped. * See setup_groups() above. */ if (change_uid (pwd)) #endif { exit (1); } setup_env (pwd); /* set env vars, cd to the home dir */ #ifdef USE_PAM { const char *const *env; env = (const char *const *) pam_getenvlist (pamh); while ((NULL != env) && (NULL != *env)) { addenv (*env, NULL); env++; } } #endif (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); if (!hushed (username)) { addenv ("HUSHLOGIN=FALSE", NULL); /* * pam_unix, pam_mail and pam_lastlog should take care of * this */ #ifndef USE_PAM motd (); /* print the message of the day */ if ( getdef_bool ("FAILLOG_ENAB") && (0 != faillog.fail_cnt)) { failprint (&faillog); /* Reset the lockout times if logged in */ if ( (0 != faillog.fail_max) && (faillog.fail_cnt >= faillog.fail_max)) { (void) puts (_("Warning: login re-enabled after temporary lockout.")); SYSLOG ((LOG_WARN, "login '%s' re-enabled after temporary lockout (%d failures)", username, (int) faillog.fail_cnt)); } } if ( getdef_bool ("LASTLOG_ENAB") && (ll.ll_time != 0)) { time_t ll_time = ll.ll_time; #ifdef HAVE_STRFTIME (void) strftime (ptime, sizeof (ptime), "%a %b %e %H:%M:%S %z %Y", localtime (&ll_time)); printf (_("Last login: %s on %s"), ptime, ll.ll_line); #else printf (_("Last login: %.19s on %s"), ctime (&ll_time), ll.ll_line); #endif #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */ if ('\0' != ll.ll_host[0]) { printf (_(" from %.*s"), (int) sizeof ll.ll_host, ll.ll_host); } #endif printf (".\n"); } agecheck (spwd); mailcheck (); /* report on the status of mail */ #endif /* !USE_PAM */ } else { addenv ("HUSHLOGIN=TRUE", NULL); } ttytype (tty); (void) signal (SIGQUIT, SIG_DFL); /* default quit signal */ (void) signal (SIGTERM, SIG_DFL); /* default terminate signal */ (void) signal (SIGALRM, SIG_DFL); /* default alarm signal */ (void) signal (SIGHUP, SIG_DFL); /* added this. --marekm */ (void) signal (SIGINT, SIG_DFL); /* default interrupt signal */ if (0 == pwd->pw_uid) { SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost)); } else if (getdef_bool ("LOG_OK_LOGINS")) { SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost)); } closelog (); tmp = getdef_str ("FAKE_SHELL"); if (NULL != tmp) { err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */ } else { /* exec the shell finally */ err = shell (pwd->pw_shell, (char *) 0, newenvp); } return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); }