PAMH_ARG_DECL(int get_account_info, const char *name, struct passwd **pwd, struct spwd **spwdent) { /* UNIX passwords area */ *pwd = pam_modutil_getpwnam(pamh, name); /* Get password file entry... */ *spwdent = NULL; if (*pwd != NULL) { if (strcmp((*pwd)->pw_passwd, "*NP*") == 0) { /* NIS+ */ #ifdef HELPER_COMPILE uid_t save_euid, save_uid; save_euid = geteuid(); save_uid = getuid(); if (save_uid == (*pwd)->pw_uid) setreuid(save_euid, save_uid); else { setreuid(0, -1); if (setreuid(-1, (*pwd)->pw_uid) == -1) { setreuid(-1, 0); setreuid(0, -1); if(setreuid(-1, (*pwd)->pw_uid) == -1) return PAM_CRED_INSUFFICIENT; } } *spwdent = pam_modutil_getspnam(pamh, name); if (save_uid == (*pwd)->pw_uid) setreuid(save_uid, save_euid); else { setreuid(-1, 0); setreuid(save_uid, -1); setreuid(-1, save_euid); } if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL) return PAM_AUTHINFO_UNAVAIL; #else /* we must run helper for NIS+ passwords */ return PAM_UNIX_RUN_HELPER; #endif } else if (is_pwd_shadowed(*pwd)) { /* * ...and shadow password file entry for this user, * if shadowing is enabled */ #ifndef HELPER_COMPILE if (geteuid() || SELINUX_ENABLED) return PAM_UNIX_RUN_HELPER; #endif *spwdent = pam_modutil_getspnam(pamh, name); if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL) return PAM_AUTHINFO_UNAVAIL; } } else { return PAM_USER_UNKNOWN; } return PAM_SUCCESS; }
/* now the session stuff */ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { pid_t pid; int ctrl, ret; char *user_name; struct passwd *pwd; D(("called.")); ctrl = _pam_parse(pamh, argc, argv); ret = pam_get_item(pamh, PAM_USER, (void *) &user_name); if (user_name == NULL || ret != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "open_session - error recovering" "username"); return PAM_SESSION_ERR; } pwd = pam_modutil_getpwnam(pamh, user_name); if (!pwd) { if (ctrl & PAM_DEBUG_ARG) pam_syslog(pamh, LOG_ERR, "open_session username" " '%s' does not exist", user_name); return PAM_SESSION_ERR; } D(("user name is %s", user_name)); /* Initialize libcg */ ret = cgroup_init(); if (ret) { if (ctrl & PAM_DEBUG_ARG) pam_syslog(pamh, LOG_ERR, "libcgroup initialization" " failed"); return PAM_SESSION_ERR; } D(("Initialized libcgroup successfuly.")); /* Determine the pid of the task */ pid = getpid(); /* Note: We are using default gid here. Is there a way to determine * under what egid service will be provided? */ ret = cgroup_change_cgroup_uid_gid(pwd->pw_uid, pwd->pw_gid, pid); if (ret) { if (ctrl & PAM_DEBUG_ARG) pam_syslog(pamh, LOG_ERR, "Change of cgroup for process" " with username %s failed.\n", user_name); return PAM_SESSION_ERR; } if (ctrl & PAM_DEBUG_ARG) pam_syslog(pamh, LOG_DEBUG, "Changed cgroup for process %d" " with username %s.\n", pid, user_name); return PAM_SUCCESS; }
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { int retval, ctrl; const void *user; const struct passwd *pwd; uid_t uid; time_t lltime = 0; /* * this module gets the uid of the PAM_USER. Uses it to display * last login info and then updates the lastlog for that user. */ ctrl = _pam_parse(pamh, flags, argc, argv); /* which user? */ retval = pam_get_item(pamh, PAM_USER, &user); if (retval != PAM_SUCCESS || user == NULL || *(const char *)user == '\0') { pam_syslog(pamh, LOG_NOTICE, "user unknown"); return PAM_USER_UNKNOWN; } /* what uid? */ pwd = pam_modutil_getpwnam (pamh, user); if (pwd == NULL) { D(("couldn't identify user %s", user)); return PAM_USER_UNKNOWN; } uid = pwd->pw_uid; pwd = NULL; /* tidy up */ /* process the current login attempt (indicate last) */ retval = last_login_date(pamh, ctrl, uid, user, &lltime); if ((ctrl & LASTLOG_BTMP) && retval == PAM_SUCCESS) { retval = last_login_failed(pamh, ctrl, user, lltime); } /* indicate success or failure */ uid = -1; /* forget this */ return retval; }
static int init(pam_handle_t *pamh, struct pld_cfg *cfg, struct pld_ctx **ctx, const char **username, const char **service, const char **ruser, const char **rhost, const char **tty) { int rc; struct passwd *pwent; /* get user name */ rc = pam_get_user(pamh, username, NULL); if (rc != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "failed to get user name: %s", pam_strerror(pamh, rc)); return rc; } if ((*username == NULL) || ((*username)[0] == '\0')) { pam_syslog(pamh, LOG_ERR, "got empty user name"); return PAM_USER_UNKNOWN; } /* check uid */ if (cfg->minimum_uid > 0) { pwent = pam_modutil_getpwnam(args->pamh, *username); if ((pwent != NULL) && (pwent->pw_uid < cfg->minimum_uid)) { if (cfg->debug) pam_syslog(pamh, LOG_DEBUG, "uid below minimum_uid; user=%s uid=%ld", *username, (long)pwent->pw_uid); return cfg->ignore_unknown_user ? PAM_IGNORE : PAM_USER_UNKNOWN; } } /* get our context */ rc = ctx_get(pamh, *username, ctx); if (rc != PAM_SUCCESS) return rc; /* get service name */ rc = pam_get_item(pamh, PAM_SERVICE, (PAM_ITEM_CONST void **)service); if (rc != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "failed to get service name: %s", pam_strerror(pamh, rc)); return rc; } /* get more PAM information (ignore errors) */ pam_get_item(pamh, PAM_RUSER, (PAM_ITEM_CONST void **)ruser); pam_get_item(pamh, PAM_RHOST, (PAM_ITEM_CONST void **)rhost); pam_get_item(pamh, PAM_TTY, (PAM_ITEM_CONST void **)tty); return PAM_SUCCESS; }
/* * Given the PAM arguments and the user we're authenticating, see if we should * ignore that user because they're root or have a low-numbered UID and we * were configured to ignore such users. Returns true if we should ignore * them, false otherwise. */ int pamk5_should_ignore(struct pam_args *args, PAM_CONST char *username) { struct passwd *pwd; if (args->ignore_root && strcmp("root", username) == 0) { pamk5_debug(args, "ignoring root user"); return 1; } if (args->minimum_uid > 0) { pwd = pam_modutil_getpwnam(args->pamh, username); if (pwd != NULL && pwd->pw_uid < (unsigned long) args->minimum_uid) { pamk5_debug(args, "ignoring low-UID user (%lu < %d)", (unsigned long) pwd->pw_uid, args->minimum_uid); return 1; } } return 0; }
PAM_EXTERN int pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc, const char **argv) { const char *luser = NULL; const char *ruser = NULL, *rhost = NULL; const char *opt_superuser = NULL; const void *c_void; int opt_debug = 0; int opt_silent; int as_root; int retval; opt_silent = flags & PAM_SILENT; while (argc-- > 0) { if (strcmp(*argv, "debug") == 0) opt_debug = 1; else if (strcmp (*argv, "silent") == 0 || strcmp(*argv, "suppress") == 0) opt_silent = 1; else if (strncmp(*argv, "superuser="******"superuser="******"superuser="******"unrecognized option '%s'", *argv); ++argv; } retval = pam_get_item (pamh, PAM_RHOST, &c_void); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "could not get the remote host name"); return retval; } rhost = c_void; retval = pam_get_item(pamh, PAM_RUSER, &c_void); ruser = c_void; if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "could not get the remote username"); return retval; } retval = pam_get_user(pamh, &luser, NULL); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "could not determine name of local user"); return retval; } if (rhost == NULL || ruser == NULL || luser == NULL) return PAM_AUTH_ERR; if (opt_superuser && strcmp(opt_superuser, luser) == 0) as_root = 1; else { struct passwd *lpwd; lpwd = pam_modutil_getpwnam(pamh, luser); if (lpwd == NULL) { if (opt_debug) /* don't print by default, could be the user's password */ pam_syslog(pamh, LOG_DEBUG, "user '%s' unknown to this system", luser); return PAM_USER_UNKNOWN; } as_root = (lpwd->pw_uid == 0); } #ifdef HAVE_RUSEROK_AF retval = ruserok_af (rhost, as_root, ruser, luser, PF_UNSPEC); #else retval = ruserok (rhost, as_root, ruser, luser); #endif if (retval != 0) { if (!opt_silent || opt_debug) pam_syslog(pamh, LOG_WARNING, "denied access to %s@%s as %s", ruser, rhost, luser); return PAM_AUTH_ERR; } else { if (!opt_silent || opt_debug) pam_syslog(pamh, LOG_NOTICE, "allowed access to %s@%s as %s", ruser, rhost, luser); return PAM_SUCCESS; } }
/* now the session stuff */ PAM_EXTERN int pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { int retval; int i; int glob_rc; char *user_name; struct passwd *pwd; int ctrl; struct pam_limit_s plstruct; struct pam_limit_s *pl = &plstruct; glob_t globbuf; const char *oldlocale; D(("called.")); memset(pl, 0, sizeof(*pl)); memset(&globbuf, 0, sizeof(globbuf)); ctrl = _pam_parse(pamh, argc, argv, pl); retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); if ( user_name == NULL || retval != PAM_SUCCESS ) { pam_syslog(pamh, LOG_CRIT, "open_session - error recovering username"); return PAM_SESSION_ERR; } pwd = pam_modutil_getpwnam(pamh, user_name); if (!pwd) { if (ctrl & PAM_DEBUG_ARG) pam_syslog(pamh, LOG_WARNING, "open_session username '%s' does not exist", user_name); return PAM_USER_UNKNOWN; } retval = init_limits(pamh, pl, ctrl); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_WARNING, "cannot initialize"); return PAM_ABORT; } retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl); if (retval == PAM_IGNORE) { D(("the configuration file ('%s') has an applicable '<domain> -' entry", CONF_FILE)); return PAM_SUCCESS; } if (retval != PAM_SUCCESS || pl->conf_file != NULL) /* skip reading limits.d if config file explicitely specified */ goto out; /* Read subsequent *.conf files, if they exist. */ /* set the LC_COLLATE so the sorting order doesn't depend on system locale */ oldlocale = setlocale(LC_COLLATE, "C"); glob_rc = glob(LIMITS_CONF_GLOB, GLOB_ERR, NULL, &globbuf); if (oldlocale != NULL) setlocale (LC_COLLATE, oldlocale); if (!glob_rc) { /* Parse the *.conf files. */ for (i = 0; globbuf.gl_pathv[i] != NULL; i++) { pl->conf_file = globbuf.gl_pathv[i]; retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl); if (retval == PAM_IGNORE) { D(("the configuration file ('%s') has an applicable '<domain> -' entry", pl->conf_file)); globfree(&globbuf); return PAM_SUCCESS; } if (retval != PAM_SUCCESS) goto out; } } out: globfree(&globbuf); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_WARNING, "error parsing the configuration file: '%s' ",CONF_FILE); return retval; } retval = setup_limits(pamh, pwd->pw_name, pwd->pw_uid, ctrl, pl); if (retval & LOGIN_ERR) pam_error(pamh, _("Too many logins for '%s'."), pwd->pw_name); if (retval != LIMITED_OK) { return PAM_PERM_DENIED; } return PAM_SUCCESS; }
user_config *get_user_config(pam_handle_t * pamh, const module_config *cfg) { _Bool non_root; char *kerberos_principal, *kerberos_domain; user_config *user_cfg = calloc(1, sizeof(user_config)); if(!user_cfg) { return NULL; } if (pam_get_user(pamh, &user_cfg->username, NULL) != PAM_SUCCESS) { DBG(("Unable to retrieve username!")); free(user_cfg); return NULL; } DBG(("username = %s", user_cfg->username)); non_root = strcmp(user_cfg->username, ROOT_USER); if (!non_root && cfg->domain != NULL) { kerberos_principal = extract_details(pamh, cfg->debug, "gssapi-with-mic"); if (kerberos_principal != NULL) { kerberos_domain = strchr(kerberos_principal, '@'); if (kerberos_domain != NULL && strcmp(kerberos_domain + 1, cfg->domain) == 0) { *kerberos_domain = '\0'; user_cfg->username = kerberos_principal; user_cfg->username_allocated = 1; non_root = strcmp(user_cfg->username, ROOT_USER); } else { pam_syslog(pamh, LOG_ERR, "Kerberos principal does not have expected domain, ignoring : '%s'", kerberos_principal); // cleanup char* returned by extract_details and that we do not use free(kerberos_principal); } } } if (cfg->ldap_enabled && non_root) { #ifdef HAVE_LDAP //GET 2nd FACTORS FROM LDAP int rc = ldap_search_factors(pamh, cfg, user_cfg->username, user_cfg); if (rc < 0) { pam_syslog(pamh, LOG_ERR, "LDAP request failed for user '%s' with error %d", user_cfg->username, rc); free(user_cfg); return NULL; } #else DBG(("LDAP configured, but not compiled (should never happen!)")); #endif } else { //NO LDAP QUERY struct passwd *user_entry = NULL; struct pam_2fa_privs p; user_entry = pam_modutil_getpwnam(pamh, user_cfg->username); if(!user_entry) { pam_syslog(pamh, LOG_ERR, "Can't get passwd entry for '%s'", user_cfg->username); free(user_cfg); return NULL; } #ifdef HAVE_CURL if(cfg->gauth_enabled && non_root) { strncpy(user_cfg->gauth_login, user_cfg->username, GAUTH_LOGIN_LEN + 1); user_cfg->gauth_login[GAUTH_LOGIN_LEN] = 0; } #endif pam_2fa_drop_priv(pamh, &p, user_entry); #ifdef HAVE_YKCLIENT yk_load_user_file(pamh, cfg, user_entry, &user_cfg->yk_publicids); #endif sms_load_user_file(pamh, cfg, user_entry, user_cfg); pam_2fa_regain_priv(pamh, &p, user_entry); } return user_cfg; }
PAM_EXTERN int pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { const void *prompt; const char *user; struct passwd *pwd; int ret, i, count, use_uid, debug; const char *left, *right, *qual; int quiet_fail, quiet_succ, audit; /* Get the user prompt. */ ret = pam_get_item(pamh, PAM_USER_PROMPT, &prompt); if ((ret != PAM_SUCCESS) || (prompt == NULL) || (strlen(prompt) == 0)) { prompt = "login: "******"debug") == 0) { debug++; } if (strcmp(argv[i], "use_uid") == 0) { use_uid++; } if (strcmp(argv[i], "quiet") == 0) { quiet_fail++; quiet_succ++; } if (strcmp(argv[i], "quiet_fail") == 0) { quiet_fail++; } if (strcmp(argv[i], "quiet_success") == 0) { quiet_succ++; } if (strcmp(argv[i], "audit") == 0) { audit++; } } if (use_uid) { /* Get information about the user. */ pwd = pam_modutil_getpwuid(pamh, getuid()); if (pwd == NULL) { pam_syslog(pamh, LOG_CRIT, "error retrieving information about user %lu", (unsigned long)getuid()); return PAM_USER_UNKNOWN; } user = pwd->pw_name; } else { /* Get the user's name. */ ret = pam_get_user(pamh, &user, prompt); if ((ret != PAM_SUCCESS) || (user == NULL)) { pam_syslog(pamh, LOG_CRIT, "error retrieving user name: %s", pam_strerror(pamh, ret)); return ret; } /* Get information about the user. */ pwd = pam_modutil_getpwnam(pamh, user); if (pwd == NULL) { if(audit) pam_syslog(pamh, LOG_NOTICE, "error retrieving information about user %s", user); return PAM_USER_UNKNOWN; } } /* Walk the argument list. */ count = 0; left = qual = right = NULL; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) { continue; } if (strcmp(argv[i], "use_uid") == 0) { continue; } if (strcmp(argv[i], "quiet") == 0) { continue; } if (strcmp(argv[i], "quiet_fail") == 0) { continue; } if (strcmp(argv[i], "quiet_success") == 0) { continue; } if (strcmp(argv[i], "audit") == 0) { continue; } if (left == NULL) { left = argv[i]; continue; } if (qual == NULL) { qual = argv[i]; continue; } if (right == NULL) { right = argv[i]; if (right == NULL) continue; count++; ret = evaluate(pamh, debug, left, qual, right, pwd, user); if (ret != PAM_SUCCESS) { if(!quiet_fail) pam_syslog(pamh, LOG_INFO, "requirement \"%s %s %s\" " "not met by user \"%s\"", left, qual, right, user); left = qual = right = NULL; break; } else if(!quiet_succ) pam_syslog(pamh, LOG_INFO, "requirement \"%s %s %s\" " "was met by user \"%s\"", left, qual, right, user); left = qual = right = NULL; continue; } } if (left || qual || right) { ret = PAM_SERVICE_ERR; pam_syslog(pamh, LOG_CRIT, "incomplete condition detected"); } else if (count == 0) { pam_syslog(pamh, LOG_INFO, "no condition detected; module succeeded"); } return ret; }
/* * open a PAM session by making sure there's a session keyring */ int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { struct passwd *pw; const char *username; int ret, old_uid, uid, old_gid, gid, loop, force = 0; for (loop = 0; loop < argc; loop++) { if (strcmp(argv[loop], "force") == 0) force = 1; else if (strcmp(argv[loop], "debug") == 0) xdebug = 1; else if (strcmp(argv[loop], "revoke") == 0) do_revoke = 1; } /* don't do anything if already created a keyring (will be called * multiple times if mentioned more than once in a pam script) */ session_counter++; debug(pamh, "OPEN %d", session_counter); if (my_session_keyring > 0) return PAM_SUCCESS; /* look up the target UID */ ret = pam_get_user(pamh, &username, "key user"); if (ret != PAM_SUCCESS) return ret; pw = pam_modutil_getpwnam(pamh, username); if (!pw) { error(pamh, "Unable to look up user \"%s\"\n", username); return PAM_USER_UNKNOWN; } revoke_as_uid = uid = pw->pw_uid; old_uid = getuid(); revoke_as_gid = gid = pw->pw_gid; old_gid = getgid(); debug(pamh, "UID:%d [%d] GID:%d [%d]", uid, old_uid, gid, old_gid); /* switch to the real UID and GID so that the keyring ends up owned by * the right user */ if (gid != old_gid && setregid(gid, -1) < 0) { error(pamh, "Unable to change GID to %d temporarily\n", gid); return PAM_SESSION_ERR; } if (uid != old_uid && setreuid(uid, -1) < 0) { error(pamh, "Unable to change UID to %d temporarily\n", uid); if (setregid(old_gid, -1) < 0) error(pamh, "Unable to change GID back to %d\n", old_gid); return PAM_SESSION_ERR; } ret = init_keyrings(pamh, force); /* return to the orignal UID and GID (probably root) */ if (uid != old_uid && setreuid(old_uid, -1) < 0) ret = error(pamh, "Unable to change UID back to %d\n", old_uid); if (gid != old_gid && setregid(old_gid, -1) < 0) ret = error(pamh, "Unable to change GID back to %d\n", old_gid); return ret; }
int save_old_password(pam_handle_t *pamh, const char *forwho, const char *oldpass, int howmany) #endif { static char buf[16384]; static char nbuf[16384]; char *s_luser, *s_uid, *s_npas, *s_pas, *pass; int npas; FILE *pwfile, *opwfile; int err = 0; int oldmask; int found = 0; struct passwd *pwd = NULL; struct stat st; #ifdef WITH_SELINUX security_context_t prev_context=NULL; #endif if (howmany < 0) { return PAM_SUCCESS; } if (oldpass == NULL) { return PAM_SUCCESS; } oldmask = umask(077); #ifdef WITH_SELINUX if (SELINUX_ENABLED) { security_context_t passwd_context=NULL; if (getfilecon("/etc/passwd",&passwd_context)<0) { return PAM_AUTHTOK_ERR; }; if (getfscreatecon(&prev_context)<0) { freecon(passwd_context); return PAM_AUTHTOK_ERR; } if (setfscreatecon(passwd_context)) { freecon(passwd_context); freecon(prev_context); return PAM_AUTHTOK_ERR; } freecon(passwd_context); } #endif pwfile = fopen(OPW_TMPFILE, "w"); umask(oldmask); if (pwfile == NULL) { err = 1; goto done; } opwfile = fopen(OLD_PASSWORDS_FILE, "r"); if (opwfile == NULL) { fclose(pwfile); err = 1; goto done; } if (fstat(fileno(opwfile), &st) == -1) { fclose(opwfile); fclose(pwfile); err = 1; goto done; } if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { fclose(opwfile); fclose(pwfile); err = 1; goto done; } if (fchmod(fileno(pwfile), st.st_mode) == -1) { fclose(opwfile); fclose(pwfile); err = 1; goto done; } while (fgets(buf, 16380, opwfile)) { if (!strncmp(buf, forwho, strlen(forwho))) { char *sptr = NULL; found = 1; if (howmany == 0) continue; buf[strlen(buf) - 1] = '\0'; s_luser = strtok_r(buf, ":", &sptr); s_uid = strtok_r(NULL, ":", &sptr); s_npas = strtok_r(NULL, ":", &sptr); s_pas = strtok_r(NULL, ":", &sptr); npas = strtol(s_npas, NULL, 10) + 1; while (npas > howmany) { s_pas = strpbrk(s_pas, ","); if (s_pas != NULL) s_pas++; npas--; } pass = crypt_md5_wrapper(oldpass); if (s_pas == NULL) snprintf(nbuf, sizeof(nbuf), "%s:%s:%d:%s\n", s_luser, s_uid, npas, pass); else snprintf(nbuf, sizeof(nbuf),"%s:%s:%d:%s,%s\n", s_luser, s_uid, npas, s_pas, pass); _pam_delete(pass); if (fputs(nbuf, pwfile) < 0) { err = 1; break; } } else if (fputs(buf, pwfile) < 0) { err = 1; break; } } fclose(opwfile); if (!found) { pwd = pam_modutil_getpwnam(pamh, forwho); if (pwd == NULL) { err = 1; } else { pass = crypt_md5_wrapper(oldpass); snprintf(nbuf, sizeof(nbuf), "%s:%lu:1:%s\n", forwho, (unsigned long)pwd->pw_uid, pass); _pam_delete(pass); if (fputs(nbuf, pwfile) < 0) { err = 1; } } } if (fflush(pwfile) || fsync(fileno(pwfile))) { D(("fflush or fsync error writing entries to old passwords file: %m")); err = 1; } if (fclose(pwfile)) { D(("fclose error writing entries to old passwords file: %m")); err = 1; } done: if (!err) { if (rename(OPW_TMPFILE, OLD_PASSWORDS_FILE)) err = 1; } #ifdef WITH_SELINUX if (SELINUX_ENABLED) { if (setfscreatecon(prev_context)) { err = 1; } if (prev_context) freecon(prev_context); prev_context=NULL; } #endif if (!err) { return PAM_SUCCESS; } else { unlink(OPW_TMPFILE); return PAM_AUTHTOK_ERR; } }
int pam_sm_chauthtok (pam_handle_t *pamh, int flags, int argc, const char **argv) { struct passwd *pwd; const char *newpass; const char *user; int retval, tries; options_t options; memset (&options, 0, sizeof (options)); /* Set some default values, which could be overwritten later. */ options.remember = 10; options.tries = 1; /* Parse parameters for module */ for ( ; argc-- > 0; argv++) parse_option (pamh, *argv, &options); if (options.debug) pam_syslog (pamh, LOG_DEBUG, "pam_sm_chauthtok entered"); if (options.remember == 0) return PAM_IGNORE; retval = pam_get_user (pamh, &user, NULL); if (retval != PAM_SUCCESS) return retval; if (user == NULL || strlen (user) == 0) { if (options.debug) pam_syslog (pamh, LOG_DEBUG, "User is not known to system"); return PAM_USER_UNKNOWN; } if (flags & PAM_PRELIM_CHECK) { if (options.debug) pam_syslog (pamh, LOG_DEBUG, "pam_sm_chauthtok(PAM_PRELIM_CHECK)"); return PAM_SUCCESS; } pwd = pam_modutil_getpwnam (pamh, user); if (pwd == NULL) return PAM_USER_UNKNOWN; if ((strcmp(pwd->pw_passwd, "x") == 0) || ((pwd->pw_passwd[0] == '#') && (pwd->pw_passwd[1] == '#') && (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0))) { struct spwd *spw = pam_modutil_getspnam (pamh, user); if (spw == NULL) return PAM_USER_UNKNOWN; retval = save_old_pass (pamh, user, pwd->pw_uid, spw->sp_pwdp, options.remember, options.debug); if (retval != PAM_SUCCESS) return retval; } else { retval = save_old_pass (pamh, user, pwd->pw_uid, pwd->pw_passwd, options.remember, options.debug); if (retval != PAM_SUCCESS) return retval; } newpass = NULL; tries = 0; while ((newpass == NULL) && (tries < options.tries)) { retval = pam_get_authtok (pamh, PAM_AUTHTOK, &newpass, NULL); if (retval != PAM_SUCCESS && retval != PAM_TRY_AGAIN) { if (retval == PAM_CONV_AGAIN) retval = PAM_INCOMPLETE; return retval; } tries++; if (options.debug) { if (newpass) pam_syslog (pamh, LOG_DEBUG, "got new auth token"); else pam_syslog (pamh, LOG_DEBUG, "got no auth token"); } if (newpass == NULL || retval == PAM_TRY_AGAIN) continue; if (options.debug) pam_syslog (pamh, LOG_DEBUG, "check against old password file"); if (check_old_pass (pamh, user, newpass, options.debug) != PAM_SUCCESS) { if (getuid() || options.enforce_for_root || (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) { pam_error (pamh, _("Password has been already used. Choose another.")); newpass = NULL; /* Remove password item, else following module will use it */ pam_set_item (pamh, PAM_AUTHTOK, (void *) NULL); } else pam_info (pamh, _("Password has been already used.")); } } if (newpass == NULL && tries >= options.tries) { if (options.debug) pam_syslog (pamh, LOG_DEBUG, "Aborted, too many tries"); return PAM_MAXTRIES; } return PAM_SUCCESS; }
PAM_EXTERN int pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { int retval, i, citem=0, extitem=0, onerr=PAM_SERVICE_ERR, sense=2, quiet=0; const void *void_citemp; const char *citemp; char *ifname=NULL; char aline[256]; char mybuf[256],myval[256]; struct stat fileinfo; FILE *inf; char apply_val[256]; int apply_type; /* Stuff for "extended" items */ struct passwd *userinfo; apply_type=APPLY_TYPE_NULL; memset(apply_val,0,sizeof(apply_val)); for(i=0; i < argc; i++) { { const char *junk; /* option quiet has no value */ if(!strcmp(argv[i],"quiet")) { quiet = 1; continue; } memset(mybuf,'\0',sizeof(mybuf)); memset(myval,'\0',sizeof(myval)); junk = strchr(argv[i], '='); if((junk == NULL) || (junk - argv[i]) >= (int) sizeof(mybuf)) { pam_syslog(pamh,LOG_ERR, "Bad option: \"%s\"", argv[i]); continue; } strncpy(mybuf, argv[i], LESSER(junk - argv[i], (int)sizeof(mybuf) - 1)); strncpy(myval, junk + 1, sizeof(myval) - 1); } if(!strcmp(mybuf,"onerr")) if(!strcmp(myval,"succeed")) onerr = PAM_SUCCESS; else if(!strcmp(myval,"fail")) onerr = PAM_SERVICE_ERR; else { if (ifname) free (ifname); return PAM_SERVICE_ERR; } else if(!strcmp(mybuf,"sense")) if(!strcmp(myval,"allow")) sense=0; else if(!strcmp(myval,"deny")) sense=1; else { if (ifname) free (ifname); return onerr; } else if(!strcmp(mybuf,"file")) { if (ifname) free (ifname); ifname = (char *)malloc(strlen(myval)+1); if (!ifname) return PAM_BUF_ERR; strcpy(ifname,myval); } else if(!strcmp(mybuf,"item")) if(!strcmp(myval,"user")) citem = PAM_USER; else if(!strcmp(myval,"tty")) citem = PAM_TTY; else if(!strcmp(myval,"rhost")) citem = PAM_RHOST; else if(!strcmp(myval,"ruser")) citem = PAM_RUSER; else { /* These items are related to the user, but are not directly gettable with pam_get_item */ citem = PAM_USER; if(!strcmp(myval,"group")) extitem = EI_GROUP; else if(!strcmp(myval,"shell")) extitem = EI_SHELL; else citem = 0; } else if(!strcmp(mybuf,"apply")) { apply_type=APPLY_TYPE_NONE; memset(apply_val,'\0',sizeof(apply_val)); if (myval[0]=='@') { apply_type=APPLY_TYPE_GROUP; strncpy(apply_val,myval+1,sizeof(apply_val)-1); } else { apply_type=APPLY_TYPE_USER; strncpy(apply_val,myval,sizeof(apply_val)-1); } } else { free(ifname); pam_syslog(pamh,LOG_ERR, "Unknown option: %s",mybuf); return onerr; } } if(!citem) { pam_syslog(pamh,LOG_ERR, "Unknown item or item not specified"); free(ifname); return onerr; } else if(!ifname) { pam_syslog(pamh,LOG_ERR, "List filename not specified"); return onerr; } else if(sense == 2) { pam_syslog(pamh,LOG_ERR, "Unknown sense or sense not specified"); free(ifname); return onerr; } else if( (apply_type==APPLY_TYPE_NONE) || ((apply_type!=APPLY_TYPE_NULL) && (*apply_val=='\0')) ) { pam_syslog(pamh,LOG_ERR, "Invalid usage for apply= parameter"); free (ifname); return onerr; } /* Check if it makes sense to use the apply= parameter */ if (apply_type != APPLY_TYPE_NULL) { if((citem==PAM_USER) || (citem==PAM_RUSER)) { pam_syslog(pamh,LOG_WARNING, "Non-sense use for apply= parameter"); apply_type=APPLY_TYPE_NULL; } if(extitem && (extitem==EI_GROUP)) { pam_syslog(pamh,LOG_WARNING, "Non-sense use for apply= parameter"); apply_type=APPLY_TYPE_NULL; } } /* Short-circuit - test if this session apply for this user */ { const char *user_name; int rval; rval=pam_get_user(pamh,&user_name,NULL); if((rval==PAM_SUCCESS) && user_name && user_name[0]) { /* Got it ? Valid ? */ if(apply_type==APPLY_TYPE_USER) { if(strcmp(user_name, apply_val)) { /* Does not apply to this user */ #ifdef PAM_DEBUG pam_syslog(pamh,LOG_DEBUG, "don't apply: apply=%s, user=%s", apply_val,user_name); #endif /* PAM_DEBUG */ free(ifname); return PAM_IGNORE; } } else if(apply_type==APPLY_TYPE_GROUP) { if(!pam_modutil_user_in_group_nam_nam(pamh,user_name,apply_val)) { /* Not a member of apply= group */ #ifdef PAM_DEBUG pam_syslog(pamh,LOG_DEBUG, "don't apply: %s not a member of group %s", user_name,apply_val); #endif /* PAM_DEBUG */ free(ifname); return PAM_IGNORE; } } } } retval = pam_get_item(pamh,citem,&void_citemp); citemp = void_citemp; if(retval != PAM_SUCCESS) { free(ifname); return onerr; } if((citem == PAM_USER) && !citemp) { retval = pam_get_user(pamh,&citemp,NULL); if (retval != PAM_SUCCESS || !citemp) { free(ifname); return PAM_SERVICE_ERR; } } if((citem == PAM_TTY) && citemp) { /* Normalize the TTY name. */ if(strncmp(citemp, "/dev/", 5) == 0) { citemp += 5; } } if(!citemp || (strlen(citemp) == 0)) { free(ifname); /* The item was NULL - we are sure not to match */ return sense?PAM_SUCCESS:PAM_AUTH_ERR; } if(extitem) { switch(extitem) { case EI_GROUP: /* Just ignore, call pam_modutil_in_group... later */ break; case EI_SHELL: /* Assume that we have already gotten PAM_USER in pam_get_item() - a valid assumption since citem gets set to PAM_USER in the extitem switch */ userinfo = pam_modutil_getpwnam(pamh, citemp); if (userinfo == NULL) { pam_syslog(pamh,LOG_ERR, "getpwnam(%s) failed", citemp); free(ifname); return onerr; } citemp = userinfo->pw_shell; break; default: pam_syslog(pamh,LOG_ERR, "Internal weirdness, unknown extended item %d", extitem); free(ifname); return onerr; } } #ifdef PAM_DEBUG pam_syslog(pamh,LOG_INFO, "Got file = %s, item = %d, value = %s, sense = %d", ifname, citem, citemp, sense); #endif if(lstat(ifname,&fileinfo)) { if(!quiet) pam_syslog(pamh,LOG_ERR, "Couldn't open %s",ifname); free(ifname); return onerr; } if((fileinfo.st_mode & S_IWOTH) || !S_ISREG(fileinfo.st_mode)) { /* If the file is world writable or is not a normal file, return error */ pam_syslog(pamh,LOG_ERR, "%s is either world writable or not a normal file", ifname); free(ifname); return PAM_AUTH_ERR; } inf = fopen(ifname,"r"); if(inf == NULL) { /* Check that we opened it successfully */ if (onerr == PAM_SERVICE_ERR) { /* Only report if it's an error... */ pam_syslog(pamh,LOG_ERR, "Error opening %s", ifname); } free(ifname); return onerr; } /* There should be no more errors from here on */ retval=PAM_AUTH_ERR; /* This loop assumes that PAM_SUCCESS == 0 and PAM_AUTH_ERR != 0 */ #ifdef PAM_DEBUG assert(PAM_SUCCESS == 0); assert(PAM_AUTH_ERR != 0); #endif while((fgets(aline,sizeof(aline),inf) != NULL) && retval) { char *a = aline; if(strlen(aline) == 0) continue; if(aline[strlen(aline) - 1] == '\n') aline[strlen(aline) - 1] = '\0'; if(strlen(aline) == 0) continue; if(aline[strlen(aline) - 1] == '\r') aline[strlen(aline) - 1] = '\0'; if(citem == PAM_TTY) { if(strncmp(a, "/dev/", 5) == 0) a += 5; } if (extitem == EI_GROUP) { retval = !pam_modutil_user_in_group_nam_nam(pamh, citemp, aline); } else { retval = strcmp(a, citemp); } } fclose(inf); free(ifname); if ((sense && retval) || (!sense && !retval)) { #ifdef PAM_DEBUG pam_syslog(pamh,LOG_INFO, "Returning PAM_SUCCESS, retval = %d", retval); #endif return PAM_SUCCESS; } else { const void *service; const char *user_name; #ifdef PAM_DEBUG pam_syslog(pamh,LOG_INFO, "Returning PAM_AUTH_ERR, retval = %d", retval); #endif (void) pam_get_item(pamh, PAM_SERVICE, &service); (void) pam_get_user(pamh, &user_name, NULL); if (!quiet) pam_syslog (pamh, LOG_ALERT, "Refused user %s for service %s", user_name, (const char *)service); return PAM_AUTH_ERR; } }
/* --- authentication (locking out inactive users) functions --- */ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int retval, ctrl; const char *user = NULL; const struct passwd *pwd; uid_t uid; time_t lltime = 0; time_t inactive_days = 0; int last_fd; /* * Lock out the user if he did not login recently enough. */ ctrl = _pam_auth_parse(pamh, flags, argc, argv, &inactive_days); /* which user? */ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL || *user == '\0') { pam_syslog(pamh, LOG_ERR, "cannot determine the user's name"); return PAM_USER_UNKNOWN; } /* what uid? */ pwd = pam_modutil_getpwnam (pamh, user); if (pwd == NULL) { pam_syslog(pamh, LOG_ERR, "user unknown"); return PAM_USER_UNKNOWN; } uid = pwd->pw_uid; pwd = NULL; /* tidy up */ if (uid == 0) return PAM_SUCCESS; /* obtain the last login date and all the relevant info */ last_fd = last_login_open(pamh, ctrl, uid); if (last_fd < 0) { return PAM_IGNORE; } retval = last_login_read(pamh, ctrl|LASTLOG_QUIET, last_fd, uid, &lltime); close(last_fd); if (retval != PAM_SUCCESS) { D(("error while reading lastlog file")); return PAM_IGNORE; } if (lltime == 0) { /* user never logged in before */ if (ctrl & LASTLOG_DEBUG) pam_syslog(pamh, LOG_DEBUG, "user never logged in - pass"); return PAM_SUCCESS; } lltime = (time(NULL) - lltime) / (24*60*60); if (lltime > inactive_days) { pam_syslog(pamh, LOG_INFO, "user %s inactive for %ld days - denied", user, (long) lltime); return PAM_AUTH_ERR; } return PAM_SUCCESS; }
/* * Verify the user authorization. Call krb5_kuserok if this is a local * account, or do the krb5_aname_to_localname verification if ignore_k5login * was requested. For non-local accounts, the principal must match the * authentication identity. */ int pamk5_authorized(struct pam_args *args) { struct context *ctx; krb5_context c; struct passwd *pwd; char kuser[65]; /* MAX_USERNAME == 65 (MIT Kerberos 1.4.1). */ if (args == NULL || args->ctx == NULL || args->ctx->context == NULL) return PAM_SERVICE_ERR; ctx = args->ctx; if (ctx->name == NULL) return PAM_SERVICE_ERR; c = ctx->context; /* * If alt_auth_map was set, authorize the user if the authenticated * principal matches the mapped principal. alt_auth_map essentially * serves as a supplemental .k5login. */ if (args->alt_auth_map != NULL) { char *mapped; char *authed; int retval; krb5_principal princ; if (pamk5_map_principal(args, ctx->name, &mapped) != PAM_SUCCESS) return PAM_SERVICE_ERR; retval = krb5_parse_name(c, mapped, &princ); if (retval != 0) { free(mapped); return PAM_SERVICE_ERR; } free(mapped); retval = krb5_unparse_name(c, princ, &mapped); if (retval != 0) return PAM_SERVICE_ERR; retval = krb5_unparse_name(c, ctx->princ, &authed); if (retval != 0) { free(mapped); return PAM_SERVICE_ERR; } if (strcmp(authed, mapped) == 0) { free(authed); free(mapped); return PAM_SUCCESS; } free(authed); free(mapped); } /* * If the name to which we're authenticating contains @ (is fully * qualified), it must match the principal exactly. */ if (strchr(ctx->name, '@') != NULL) { char *principal; int retval; retval = krb5_unparse_name(c, ctx->princ, &principal); if (retval != 0) return PAM_SERVICE_ERR; if (strcmp(principal, ctx->name) != 0) { free(principal); return PAM_AUTH_ERR; } return PAM_SUCCESS; } /* * Otherwise, apply either krb5_aname_to_localname or krb5_kuserok * depending on the situation. */ pwd = pam_modutil_getpwnam(args->pamh, ctx->name); if (args->ignore_k5login || pwd == NULL) { if (krb5_aname_to_localname(c, ctx->princ, sizeof(kuser), kuser) != 0) return PAM_AUTH_ERR; if (strcmp(kuser, ctx->name) != 0) return PAM_AUTH_ERR; } else { if (!krb5_kuserok(c, ctx->princ, ctx->name)) return PAM_AUTH_ERR; } return PAM_SUCCESS; }
static int get_folder(pam_handle_t *pamh, int ctrl, const char *path_mail, char **folder_p, size_t hashcount) { int retval; const char *user, *path; char *folder = NULL; const struct passwd *pwd = NULL; retval = pam_get_user(pamh, &user, NULL); if (retval != PAM_SUCCESS || user == NULL) { pam_syslog(pamh, LOG_ERR, "cannot determine username"); retval = PAM_USER_UNKNOWN; goto get_folder_cleanup; } if (ctrl & PAM_NEW_MAIL_DIR) { path = path_mail; if (*path == '~') { /* support for $HOME delivery */ pwd = pam_modutil_getpwnam(pamh, user); if (pwd == NULL) { pam_syslog(pamh, LOG_ERR, "user unknown"); retval = PAM_USER_UNKNOWN; goto get_folder_cleanup; } /* * "~/xxx" and "~xxx" are treated as same */ if (!*++path || (*path == '/' && !*++path)) { pam_syslog(pamh, LOG_ERR, "badly formed mail path [%s]", path_mail); retval = PAM_SERVICE_ERR; goto get_folder_cleanup; } ctrl |= PAM_HOME_MAIL; if (hashcount != 0) { pam_syslog(pamh, LOG_ERR, "cannot do hash= and home directory mail"); } } } else { path = DEFAULT_MAIL_DIRECTORY; } /* put folder together */ hashcount = hashcount < strlen(user) ? hashcount : strlen(user); retval = PAM_BUF_ERR; if (ctrl & PAM_HOME_MAIL) { if (asprintf(&folder, MAIL_FILE_FORMAT, pwd->pw_dir, "", path) < 0) goto get_folder_cleanup; } else { int rc; size_t i; char *hash; if ((hash = malloc(2 * hashcount + 1)) == NULL) goto get_folder_cleanup; for (i = 0; i < hashcount; i++) { hash[2 * i] = '/'; hash[2 * i + 1] = user[i]; } hash[2 * i] = '\0'; rc = asprintf(&folder, MAIL_FILE_FORMAT, path, hash, user); _pam_overwrite(hash); _pam_drop(hash); if (rc < 0) goto get_folder_cleanup; } D(("folder=[%s]", folder)); retval = PAM_SUCCESS; /* tidy up */ get_folder_cleanup: user = NULL; path = NULL; *folder_p = folder; folder = NULL; if (retval == PAM_BUF_ERR) pam_syslog(pamh, LOG_CRIT, "out of memory for mail folder"); return retval; }