static void set_tkt_string(uid_t uid) { char buf[128]; snprintf(buf, sizeof(buf), "%s%u", TKT_ROOT, (unsigned)uid); krb_set_tkt_string(buf); #if 0 /* pam_set_data+pam_get_data are not guaranteed to work, grr. */ pam_set_data(pamh, "KRBTKFILE", strdup(t), cleanup); if (pam_get_data(pamh, "KRBTKFILE", (const void**)&tkt) == PAM_SUCCESS) { pam_putenv(pamh, var); } #endif /* We don't want to inherit this variable. * If we still do, it must have a sane value. */ if (getenv("KRBTKFILE") != 0) { char *var = malloc(sizeof(buf)); snprintf(var, sizeof(buf), "KRBTKFILE=%s", tkt_string()); putenv(var); /* free(var); XXX */ } }
static int pamGssAcquireCred(pam_handle_t *pamh, int confFlags, gss_name_t userName, gss_buffer_t passwordBuf, gss_OID mech, gss_cred_id_t *cred) { int status; OM_uint32 major, minor; gss_OID_set_desc mechOids; #ifdef __APPLE__ CFDictionaryRef attributes = NULL; status = pam_get_data(pamh, CREDUI_ATTR_DATA, (const void **)&attributes); if (status == PAM_SUCCESS) return pamGssAcquireAaplInitialCred(pamh, userName, mech, attributes, cred); #endif /* __APPLE__ */ mechOids.count = 1; mechOids.elements = mech; major = gss_acquire_cred_with_password(&minor, userName, passwordBuf, GSS_C_INDEFINITE, &mechOids, GSS_C_INITIATE, cred, NULL, NULL); BAIL_ON_GSS_ERROR(major, minor); status = PAM_SUCCESS; cleanup: return status; }
/* try to get the module's context, returns a PAM status code */ static int ctx_get(pam_handle_t *pamh,const char *username,struct pld_ctx **pctx) { struct pld_ctx *ctx=NULL; int rc; /* try to get the context from PAM */ rc=pam_get_data(pamh,PLD_CTX,(const void **)&ctx); if ((rc==PAM_SUCCESS)&&(ctx!=NULL)) { /* if the user is different clear the context */ if ((ctx->user!=NULL)&&(strcmp(ctx->user,username)!=0)) ctx_clear(ctx); } else { /* allocate a new context */ ctx=calloc(1,sizeof(struct pld_ctx)); if (ctx==NULL) { pam_syslog(pamh,LOG_CRIT,"calloc(): failed to allocate memory: %s",strerror(errno)); return PAM_BUF_ERR; } ctx_clear(ctx); /* store the new context with the handler to free it */ rc=pam_set_data(pamh,PLD_CTX,ctx,ctx_free); if (rc!=PAM_SUCCESS) { ctx_free(pamh,ctx,0); pam_syslog(pamh,LOG_ERR,"failed to store context: %s",pam_strerror(pamh,rc)); return rc; } } /* return the context */ *pctx=ctx; return PAM_SUCCESS; }
PAM_EXTERN int pam_sm_open_session (pam_handle_t *ph, int flags, int argc, const char **argv) { const char *user = NULL, *password = NULL; struct passwd *pwd; int ret; uint args; int started_daemon; args = parse_args (ph, argc, argv); if (args & ARG_IGNORE_SERVICE) return PAM_SUCCESS; /* Figure out the user name */ ret = pam_get_user (ph, &user, NULL); if (ret != PAM_SUCCESS) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't get the user name: %s", pam_strerror (ph, ret)); return PAM_SERVICE_ERR; } pwd = getpwnam (user); if (!pwd) { syslog (GKR_LOG_ERR, "gkr-pam: error looking up user information for: %s", user); return PAM_SERVICE_ERR; } /* Get the stored authtok here */ if (pam_get_data (ph, "gkr_system_authtok", (const void**)&password) != PAM_SUCCESS) { /* * No password, no worries, maybe this (PAM using) application * didn't do authentication, or is hopeless and wants to call * different PAM callbacks from different processes. * * No use complaining */ password = NULL; } started_daemon = 0; /* Should we start the daemon? */ if (args & ARG_AUTO_START) { ret = start_daemon_if_necessary (ph, pwd, password, &started_daemon); if (ret != PAM_SUCCESS) return ret; } /* If mate keyring is running, but we didn't start it here, then unlock now */ if (get_any_env (ph, ENV_CONTROL) != NULL) { if (!started_daemon && password != NULL) { if (unlock_keyring (ph, pwd, password) != PAM_SUCCESS) return PAM_SERVICE_ERR; } } return PAM_SUCCESS; }
PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags, int argc, const char **argv) { int retval; pid_t pid; char *targetpath; char *args[4]; // _pam_log(LOG_ERR,"Geteuid : %d",geteuid()); if ((retval = pam_get_data(pamh, "encfs_targetpath", (const void **) &targetpath)) != PAM_SUCCESS) return retval; if (!checkmnt(targetpath)) { _pam_log(LOG_ERR, "Targetpath is not mounted!: %s", targetpath); return PAM_SERVICE_ERR; } args[0] = "fusermount"; args[1] = "-uz"; args[2] = targetpath; args[3] = NULL; switch (pid = fork()) { case -1: _pam_log(LOG_ERR, "Fork failed"); return PAM_SERVICE_ERR; case 0: execvp("fusermount", args); char errstr[128]; snprintf(errstr, 127, "%d - %s", errno, strerror(errno)); _pam_log(LOG_ERR, "Exec failed - %s", errstr); exit(127); } if (waitpid(pid, NULL, 0) == -1) _pam_log(LOG_ERR, "Waitpid failed - %s", strerror(errno)); /*We'll get this error every single time we have more than one session active, todo fix this with some better checks + support fuser -km if no more session connected. if (checkmnt(targetpath)) { _pam_log(LOG_ERR,"Failed to unmount %s",targetpath); return PAM_SERVICE_ERR; } */ return PAM_IGNORE; }
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { const char *user; const void *data; if (pam_get_user(pamh, &user, NULL) == PAM_SUCCESS && pam_get_data(pamh, "pam_auth_ticket", &data) == PAM_SUCCESS) write_ticket(user, (const char*)data); return (PAM_SUCCESS); }
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { int status; OM_uint32 major, minor; gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; gss_OID mech = GSS_C_NO_OID; if (flags && (flags & PAM_ESTABLISH_CRED) == 0) return PAM_SUCCESS; status = pam_get_data(pamh, GSS_CRED_DATA, (const void **)&cred); BAIL_ON_PAM_ERROR(status); status = pam_get_data(pamh, GSS_MECH_DATA, (const void **)&mech); BAIL_ON_PAM_ERROR(status); major = gss_store_cred(&minor, cred, GSS_C_INITIATE, mech, 1, 1, NULL, NULL); BAIL_ON_GSS_ERROR(major, minor); cleanup: return status; }
int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { int retval, *pretval = NULL; retval = PAM_SUCCESS; pam_get_data(pamh, "smb_setcred_return", (const void **) &pretval); if(pretval) { retval = *pretval; SAFE_FREE(pretval); } pam_set_data(pamh, "smb_setcred_return", NULL, NULL); return retval; }
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { pam_syslog(pamh, LOG_INFO, "pam_sm_open_session\n"); if (get_env(pamh, "PAM_KWALLET_LOGIN") != NULL) { pam_syslog(pamh, LOG_INFO, "pam_kwallet: we were already executed"); return PAM_SUCCESS; } parseArguments(argc, argv); int result; result = pam_set_data(pamh, "sm_open_session", "1", NULL); if (result != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Impossible to store sm_open_session: %s" , pam_strerror(pamh, result)); return PAM_IGNORE; } //Fetch the user, needed to get user information const char *username; result = pam_get_user(pamh, &username, NULL); if (result != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get username %s", pam_strerror(pamh, result)); return PAM_IGNORE;//Since we are not an essential module, just make pam ignore us } struct passwd *userInfo; userInfo = getpwnam(username); if (!userInfo) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get user info (passwd) info"); return PAM_IGNORE; } const char *kwalletKey; result = pam_get_data(pamh, "kwallet_key", (const void **)&kwalletKey); if (result != PAM_SUCCESS) { pam_syslog(pamh, LOG_INFO, "pam_kwallet: open_session called without kwallet_key"); return PAM_SUCCESS;//We will wait for pam_sm_authenticate } start_kwallet(pamh, userInfo, kwalletKey); return PAM_SUCCESS; }
int openpam_borrow_cred(pam_handle_t *pamh, const struct passwd *pwd) { struct pam_saved_cred *scred; const void *scredp; int r; ENTERI(pwd->pw_uid); r = pam_get_data(pamh, PAM_SAVED_CRED, &scredp); if (r == PAM_SUCCESS && scredp != NULL) { openpam_log(PAM_LOG_DEBUG, "already operating under borrowed credentials"); RETURNC(PAM_SYSTEM_ERR); } if (geteuid() != 0 && geteuid() != pwd->pw_uid) { openpam_log(PAM_LOG_DEBUG, "called with non-zero euid: %d", (int)geteuid()); RETURNC(PAM_PERM_DENIED); } scred = calloc((size_t)1, sizeof *scred); if (scred == NULL) RETURNC(PAM_BUF_ERR); scred->euid = geteuid(); scred->egid = getegid(); r = getgroups(NGROUPS_MAX, scred->groups); if (r < 0) { FREE(scred); RETURNC(PAM_SYSTEM_ERR); } scred->ngroups = r; r = pam_set_data(pamh, PAM_SAVED_CRED, scred, &openpam_free_data); if (r != PAM_SUCCESS) { FREE(scred); RETURNC(r); } if (geteuid() == pwd->pw_uid) RETURNC(PAM_SUCCESS); if (initgroups(pwd->pw_name, pwd->pw_gid) < 0 || setegid(pwd->pw_gid) < 0 || seteuid(pwd->pw_uid) < 0) { openpam_restore_cred(pamh); RETURNC(PAM_SYSTEM_ERR); } RETURNC(PAM_SUCCESS); /*NOTREACHED*/ }
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { int status; gss_name_t canonUserName = GSS_C_NO_NAME; char *userName = NULL; status = pam_get_data(pamh, GSS_NAME_DATA, (const void **)&canonUserName); if (status != PAM_SUCCESS) return PAM_USER_UNKNOWN; status = pam_get_user(pamh, (void *)&userName, NULL); if (status != PAM_SUCCESS) return PAM_USER_UNKNOWN; return gss_userok(canonUserName, userName) ? PAM_SUCCESS : PAM_PERM_DENIED; }
int openpam_restore_cred(pam_handle_t *pamh) { struct pam_saved_cred *scred; int r; r = pam_get_data(pamh, PAM_SAVED_CRED, (const void **)(void *)&scred); if (r != PAM_SUCCESS) return (r); if (scred == NULL) return (PAM_SYSTEM_ERR); if (seteuid(scred->euid) == -1 || setgroups(scred->ngroups, scred->groups) == -1 || setegid(scred->egid) == -1) return (PAM_SYSTEM_ERR); pam_set_data(pamh, PAM_SAVED_CRED, NULL, NULL); return (PAM_SUCCESS); }
static int _PAMCreateAttributesFromHandle(pam_handle_t *pamh, CFDictionaryRef *pAttributes) { CFMutableDictionaryRef attributes = NULL; const char *user; int rc; rc = pam_get_item(pamh, PAM_USER, (const void **)&user); if (rc != PAM_SUCCESS) return rc; CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, user, kCFStringEncodingUTF8); if (name == NULL) { CFRelease(attributes); return PAM_BUF_ERR; } /* In case module returned PAM_TRY_AGAIN */ rc = pam_get_data(pamh, CREDUI_ATTR_DATA, (const void **)&attributes); if (rc == PAM_SUCCESS && attributes) { CFStringRef assertedName = (CFStringRef)CFDictionaryGetValue(attributes, kCUIAttrName); if (assertedName && CFEqual(assertedName, name)) { *pAttributes = (CFDictionaryRef)CFRetain(attributes); CFRelease(name); return PAM_SUCCESS; } } attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (attributes == NULL) return PAM_BUF_ERR; CFDictionarySetValue(attributes, kCUIAttrNameType, kCUIAttrNameTypePosixName); CFDictionarySetValue(attributes, kCUIAttrName, name); /* we don't get AUTHTOK because it might prompt */ CFRelease(name); *pAttributes = attributes; return PAM_SUCCESS; }
PAM_EXTERN int pam_sm_setcred (pam_handle_t * pamh, int flags, int argc, const char **argv) { int retval; const void *pretval = NULL; DBG (("called.")); retval = PAM_SUCCESS; if (pam_get_data(pamh, "yubikey_setcred_return", &pretval) == PAM_SUCCESS && pretval) { retval = *(const int *)pretval; pam_set_data(pamh, "yubikey_setcred_return", NULL, NULL); } DBG (("done. [%s]", pam_strerror (pamh, retval))); return retval; }
static int stop_daemon (pam_handle_t *ph, struct passwd *pwd) { const char *spid = NULL; char *apid = NULL; pid_t pid; assert (pwd); pam_get_data (ph, "gkr-pam-pid", (const void**)&spid); /* * No pid, no worries, maybe we didn't start mate-keyring-daemon * Or this the calling (PAM using) application is hopeless and * wants to call different PAM callbacks from different processes. * * In any case we live and let live. */ if (!spid) goto done; /* Make sure it parses out nicely */ pid = (pid_t)atoi (spid); if (pid <= 0) { syslog (GKR_LOG_ERR, "gkr-pam: invalid mate-keyring-daemon process id: %s", spid); goto done; } if (kill (pid, SIGTERM) < 0 && errno != ESRCH) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't kill mate-keyring-daemon process %d: %s", (int)pid, strerror (errno)); goto done; } done: free_safe (apid); /* Don't bother user when daemon can't be stopped */ return PAM_SUCCESS; }
int openpam_restore_cred(pam_handle_t *pamh) { const struct pam_saved_cred *scred; const void *scredp; int r; ENTER(); r = pam_get_data(pamh, PAM_SAVED_CRED, &scredp); if (r != PAM_SUCCESS) RETURNC(r); if (scredp == NULL) RETURNC(PAM_SYSTEM_ERR); scred = scredp; if (scred->euid != geteuid()) { if (seteuid(scred->euid) < 0 || setgroups(scred->ngroups, scred->groups) < 0 || setegid(scred->egid) < 0) RETURNC(PAM_SYSTEM_ERR); } pam_set_data(pamh, PAM_SAVED_CRED, NULL, NULL); RETURNC(PAM_SUCCESS); }
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, int argc, const char **argv) { unsigned int ctrl, lctrl; int retval, i; int remember = -1; /* <DO NOT free() THESE> */ const char *user; char *pass_old, *pass_new; /* </DO NOT free() THESE> */ D(("called.")); #ifdef USE_LCKPWDF /* our current locking system requires that we lock the entire password database. This avoids both livelock and deadlock. */ /* These values for the number of attempts and the sleep time are, of course, completely arbitrary. My reading of the PAM docs is that, once pam_chauthtok() has been called with PAM_UPDATE_AUTHTOK, we are obliged to take any reasonable steps to make sure the token is updated; so retrying for 1/10 sec. isn't overdoing it. The other possibility is to call lckpwdf() on the first pam_chauthtok() pass, and hold the lock until released in the second pass--but is this guaranteed to work? -SRL */ i=0; while((retval = lckpwdf()) != 0 && i < 100) { usleep(1000); } if(retval != 0) { return PAM_AUTHTOK_LOCK_BUSY; } #endif ctrl = _set_ctrl(pamh, flags, &remember, argc, argv); /* * First get the name of a user */ retval = pam_get_user(pamh, &user, "Username: "******"bad username [%s]", user); #ifdef USE_LCKPWDF ulckpwdf(); #endif return PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) _log_err(LOG_DEBUG, pamh, "username [%s] obtained", user); } else { if (on(UNIX_DEBUG, ctrl)) _log_err(LOG_DEBUG, pamh, "password - could not identify user"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } D(("Got username of %s", user)); /* * This is not an AUTH module! */ if (on(UNIX__NONULL, ctrl)) set(UNIX__NULLOK, ctrl); if (on(UNIX__PRELIM, ctrl)) { /* * obtain and verify the current password (OLDAUTHTOK) for * the user. */ char *Announce; D(("prelim check")); if (_unix_blankpasswd(ctrl, user)) { #ifdef USE_LCKPWDF ulckpwdf(); #endif return PAM_SUCCESS; } else if (off(UNIX__IAMROOT, ctrl)) { /* instruct user what is happening */ #define greeting "Changing password for " Announce = (char *) malloc(sizeof(greeting) + strlen(user)); if (Announce == NULL) { _log_err(LOG_CRIT, pamh, "password - out of memory"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return PAM_BUF_ERR; } (void) strcpy(Announce, greeting); (void) strcpy(Announce + sizeof(greeting) - 1, user); #undef greeting lctrl = ctrl; set(UNIX__OLD_PASSWD, lctrl); retval = _unix_read_password(pamh, lctrl ,Announce ,"(current) UNIX password: "******"password - (old) token not obtained"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } /* verify that this is the password for this user */ retval = _unix_verify_password(pamh, user, pass_old, ctrl); } else { D(("process run by root so do nothing this time around")); pass_old = NULL; retval = PAM_SUCCESS; /* root doesn't have too */ } if (retval != PAM_SUCCESS) { D(("Authentication failed")); pass_old = NULL; #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); pass_old = NULL; if (retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "failed to set PAM_OLDAUTHTOK"); } retval = _unix_verify_shadow(user, ctrl); if (retval == PAM_AUTHTOK_ERR) { if (off(UNIX__IAMROOT, ctrl)) _make_remark(pamh, ctrl, PAM_ERROR_MSG, "You must wait longer to change your password"); else retval = PAM_SUCCESS; } } else if (on(UNIX__UPDATE, ctrl)) { /* * tpass is used below to store the _pam_md() return; it * should be _pam_delete()'d. */ char *tpass = NULL; int retry = 0; /* * obtain the proposed password */ D(("do update")); /* * get the old token back. NULL was ok only if root [at this * point we assume that this has already been enforced on a * previous call to this function]. */ if (off(UNIX_NOT_SET_PASS, ctrl)) { retval = pam_get_item(pamh, PAM_OLDAUTHTOK ,(const void **) &pass_old); } else { retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK ,(const void **) &pass_old); if (retval == PAM_NO_MODULE_DATA) { retval = PAM_SUCCESS; pass_old = NULL; } } D(("pass_old [%s]", pass_old)); if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "user not authenticated"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } retval = _unix_verify_shadow(user, ctrl); if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } D(("get new password now")); lctrl = ctrl; if (on(UNIX_USE_AUTHTOK, lctrl)) { set(UNIX_USE_FIRST_PASS, lctrl); } retry = 0; retval = PAM_AUTHTOK_ERR; while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) { /* * use_authtok is to force the use of a previously entered * password -- needed for pluggable password strength checking */ retval = _unix_read_password(pamh, lctrl ,NULL ,"Enter new UNIX password: "******"Retype new UNIX password: "******"password - new password not obtained"); } pass_old = NULL; /* tidy up */ #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } D(("returned to _unix_chauthtok")); /* * At this point we know who the user is and what they * propose as their new password. Verify that the new * password is acceptable. */ if (pass_new[0] == '\0') { /* "\0" password = NULL */ pass_new = NULL; } retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); } if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "new password not acceptable"); _pam_overwrite(pass_new); _pam_overwrite(pass_old); pass_new = pass_old = NULL; /* tidy up */ #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } /* * By reaching here we have approved the passwords and must now * rebuild the password database file. */ /* * First we encrypt the new password. */ if (on(UNIX_MD5_PASS, ctrl)) { tpass = crypt_md5_wrapper(pass_new); } else { /* * Salt manipulation is stolen from Rick Faith's passwd * program. Sorry Rick :) -- alex */ time_t tm; char salt[3]; time(&tm); salt[0] = bin_to_ascii(tm & 0x3f); salt[1] = bin_to_ascii((tm >> 6) & 0x3f); salt[2] = '\0'; if (off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8) { /* * to avoid using the _extensions_ of the bigcrypt() * function we truncate the newly entered password */ char *temp = malloc(9); char *e; if (temp == NULL) { _log_err(LOG_CRIT, pamh, "out of memory for password"); _pam_overwrite(pass_new); _pam_overwrite(pass_old); pass_new = pass_old = NULL; /* tidy up */ #ifdef USE_LCKPWDF ulckpwdf(); #endif return PAM_BUF_ERR; } /* copy first 8 bytes of password */ strncpy(temp, pass_new, 8); temp[8] = '\0'; /* no longer need cleartext */ e = bigcrypt(temp, salt); tpass = x_strdup(e); _pam_overwrite(e); _pam_delete(temp); /* tidy up */ } else { char *e; /* no longer need cleartext */ e = bigcrypt(pass_new, salt); tpass = x_strdup(e); _pam_overwrite(e); } } D(("password processed")); /* update the password database(s) -- race conditions..? */ retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, remember); _pam_overwrite(pass_new); _pam_overwrite(pass_old); _pam_delete(tpass); pass_old = pass_new = NULL; } else { /* something has broken with the module */
int pam_sm_chauthtok( pam_handle_t *pamh, int flags, int argc, const char **argv) { char *user; int err, result = PAM_AUTH_ERR; char *newpass = NULL, *vnewpass = NULL; char *oldpass = NULL; int i; int debug = 0; uid_t pw_uid; krb5_module_data_t *kmd = NULL; char *pam_service; int promptforold = 0; int promptfornew = 0; pam_repository_t *rep_data = NULL; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; else syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "PAM-KRB5 (password): illegal option %s"), argv[i]); } if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): start: flags = %x", flags); err = pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data); if (rep_data != NULL) { if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) { if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (auth): wrong" "repository found (%s), returning " "PAM_IGNORE", rep_data->type); return (PAM_IGNORE); } } if (flags & PAM_PRELIM_CHECK) { /* Nothing to do here */ if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): prelim check"); return (PAM_IGNORE); } /* make sure PAM framework is telling us to update passwords */ if (!(flags & PAM_UPDATE_AUTHTOK)) { syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "PAM-KRB5 (password): bad flags: %d"), flags); return (PAM_SYSTEM_ERR); } if ((err = pam_get_data(pamh, KRB5_DATA, (const void **)&kmd)) != PAM_SUCCESS) { if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): get mod data failed %d", err); kmd = NULL; } if (flags & PAM_CHANGE_EXPIRED_AUTHTOK) { /* let's make sure we know the krb5 pw has expired */ if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): kmd age status %d", kmd ? kmd->age_status : -99); if (!kmd || kmd->age_status != PAM_NEW_AUTHTOK_REQD) return (PAM_IGNORE); } err = pam_get_item(pamh, PAM_SERVICE, (void **)&pam_service); if (err != PAM_SUCCESS) { syslog(LOG_ERR, "PAM-KRB5 (password): error getting SERVICE"); return (PAM_SYSTEM_ERR); } err = pam_get_item(pamh, PAM_USER, (void **)&user); if (err != PAM_SUCCESS) { syslog(LOG_ERR, "PAM-KRB5 (password): error getting USER"); return (PAM_SYSTEM_ERR); } if (user == NULL || user == '\0') { syslog(LOG_ERR, "PAM-KRB5 (password): username is empty"); return (PAM_SYSTEM_ERR); } if (!get_pw_uid(user, &pw_uid)) { syslog(LOG_ERR, "PAM-KRB5 (password): can't get uid for %s", user); return (PAM_AUTHTOK_ERR); } /* * if root key exists in the keytab, it's a random key so no * need to prompt for pw and we just return IGNORE */ if ((strcmp(user, ROOT_UNAME) == 0) && key_in_keytab(user, debug)) { if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): " "key for '%s' in keytab, returning IGNORE", user); result = PAM_IGNORE; goto out; } if ((err = pam_get_item(pamh, PAM_AUTHTOK, (void **) &newpass)) < 0) return (err); if ((err = pam_get_item(pamh, PAM_OLDAUTHTOK, (void **) &oldpass)) < 0) return (err); if (!newpass && !oldpass) { promptforold = 1; promptfornew = 1; } else { /* * OLDAUTHTOK not set, we're probably the first password * module but the AUTHTOK is probably set from an auth mod */ if (newpass && !oldpass) { oldpass = newpass; newpass = NULL; promptfornew = 1; } result = krb5_verifypw(pamh, user, oldpass, DONT_DISP_POLICY, debug); if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): verifypw first %d", result); /* * If this fails and is not bad passwd, then it might * be a non-rpcsec_gss KDC so drop thru. * * (note in S9 change pw should work on non-rpcsec_gss KDCs * such as MIT & MS) */ if (result != 0) promptforold = 1; } if (promptforold) { oldpass = get_passwd(pamh, dgettext(TEXT_DOMAIN, "Old Kerberos password: "******"Need the old password" " to proceed \n")); free(oldpass); return (PAM_AUTHTOK_ERR); } result = krb5_verifypw(pamh, user, oldpass, DISP_POLICY, debug); if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): verifypw prforold %d", result); /* * If it's a bad password, we are done. * Else, continue and try the pwch with oldpass. */ if (result == 2) { display_msg(pamh, PAM_ERROR_MSG, dgettext(TEXT_DOMAIN, "Old Kerberos" " password incorrect\n")); (void) memset(oldpass, 0, strlen(oldpass)); free(oldpass); return (PAM_AUTHTOK_ERR); } } if (promptfornew) { newpass = get_passwd(pamh, dgettext(TEXT_DOMAIN, "New Kerberos password: "******"Need a password to proceed \n")); result = PAM_AUTHTOK_ERR; goto out; } vnewpass = get_passwd(pamh, dgettext(TEXT_DOMAIN, "Re-enter new Kerberos password: "******"Need a password to proceed \n")); result = PAM_AUTHTOK_ERR; goto out; } if (strcmp(newpass, vnewpass)) { display_msg(pamh, PAM_ERROR_MSG, dgettext(TEXT_DOMAIN, "Passwords do not match \n")); result = PAM_AUTHTOK_ERR; goto out; } } result = krb5_changepw(pamh, user, oldpass, newpass, debug); if (result == PAM_SUCCESS) { display_msg(pamh, PAM_TEXT_INFO, dgettext(TEXT_DOMAIN, "Kerberos password " "successfully changed\n")); get_set_creds(pamh, kmd, user, newpass, debug); (void) pam_set_item(pamh, PAM_AUTHTOK, newpass); (void) pam_set_item(pamh, PAM_OLDAUTHTOK, oldpass); } out: if (promptforold && oldpass) { (void) memset(oldpass, 0, strlen(oldpass)); free(oldpass); } if (newpass) { (void) memset(newpass, 0, strlen(newpass)); free(newpass); } if (vnewpass) { (void) memset(vnewpass, 0, strlen(vnewpass)); free(vnewpass); } if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): out: returns %d", result); return (result); }
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, int argc, const char **argv) { unsigned int ctrl, lctrl; int retval; int remember = -1; int rounds = -1; int pass_min_len = 0; /* <DO NOT free() THESE> */ const char *user; const void *pass_old, *pass_new; /* </DO NOT free() THESE> */ D(("called.")); ctrl = _set_ctrl(pamh, flags, &remember, &rounds, &pass_min_len, argc, argv); /* * First get the name of a user */ retval = pam_get_user(pamh, &user, NULL); if (retval == PAM_SUCCESS) { /* * Various libraries at various times have had bugs related to * '+' or '-' as the first character of a user name. Don't * allow them. */ if (user == NULL || user[0] == '-' || user[0] == '+') { pam_syslog(pamh, LOG_ERR, "bad username [%s]", user); return PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) pam_syslog(pamh, LOG_DEBUG, "username [%s] obtained", user); } else { if (on(UNIX_DEBUG, ctrl)) pam_syslog(pamh, LOG_DEBUG, "password - could not identify user"); return retval; } D(("Got username of %s", user)); /* * Before we do anything else, check to make sure that the user's * info is in one of the databases we can modify from this module, * which currently is 'files' and 'nis'. We have to do this because * getpwnam() doesn't tell you *where* the information it gives you * came from, nor should it. That's our job. */ if (_unix_comesfromsource(pamh, user, 1, on(UNIX_NIS, ctrl)) == 0) { pam_syslog(pamh, LOG_DEBUG, "user \"%s\" does not exist in /etc/passwd%s", user, on(UNIX_NIS, ctrl) ? " or NIS" : ""); return PAM_USER_UNKNOWN; } else { struct passwd *pwd; _unix_getpwnam(pamh, user, 1, 1, &pwd); if (pwd == NULL) { pam_syslog(pamh, LOG_DEBUG, "user \"%s\" has corrupted passwd entry", user); return PAM_USER_UNKNOWN; } } /* * This is not an AUTH module! */ if (on(UNIX__NONULL, ctrl)) set(UNIX__NULLOK, ctrl); if (on(UNIX__PRELIM, ctrl)) { /* * obtain and verify the current password (OLDAUTHTOK) for * the user. */ char *Announce; D(("prelim check")); if (_unix_blankpasswd(pamh, ctrl, user)) { return PAM_SUCCESS; } else if (off(UNIX__IAMROOT, ctrl)) { /* instruct user what is happening */ if (asprintf(&Announce, _("Changing password for %s."), user) < 0) { pam_syslog(pamh, LOG_CRIT, "password - out of memory"); return PAM_BUF_ERR; } lctrl = ctrl; set(UNIX__OLD_PASSWD, lctrl); retval = _unix_read_password(pamh, lctrl ,Announce ,_("(current) UNIX password: "******"password - (old) token not obtained"); return retval; } /* verify that this is the password for this user */ retval = _unix_verify_password(pamh, user, pass_old, ctrl); } else { D(("process run by root so do nothing this time around")); pass_old = NULL; retval = PAM_SUCCESS; /* root doesn't have too */ } if (retval != PAM_SUCCESS) { D(("Authentication failed")); pass_old = NULL; return retval; } retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); pass_old = NULL; if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_CRIT, "failed to set PAM_OLDAUTHTOK"); } retval = _unix_verify_shadow(pamh,user, ctrl); if (retval == PAM_AUTHTOK_ERR) { if (off(UNIX__IAMROOT, ctrl)) _make_remark(pamh, ctrl, PAM_ERROR_MSG, _("You must wait longer to change your password")); else retval = PAM_SUCCESS; } } else if (on(UNIX__UPDATE, ctrl)) { /* * tpass is used below to store the _pam_md() return; it * should be _pam_delete()'d. */ char *tpass = NULL; int retry = 0; /* * obtain the proposed password */ D(("do update")); /* * get the old token back. NULL was ok only if root [at this * point we assume that this has already been enforced on a * previous call to this function]. */ if (off(UNIX_NOT_SET_PASS, ctrl)) { retval = pam_get_item(pamh, PAM_OLDAUTHTOK ,&pass_old); } else { retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK ,&pass_old); if (retval == PAM_NO_MODULE_DATA) { retval = PAM_SUCCESS; pass_old = NULL; } } D(("pass_old [%s]", pass_old)); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "user not authenticated"); return retval; } D(("get new password now")); lctrl = ctrl; if (on(UNIX_USE_AUTHTOK, lctrl)) { set(UNIX_USE_FIRST_PASS, lctrl); } retry = 0; retval = PAM_AUTHTOK_ERR; while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) { /* * use_authtok is to force the use of a previously entered * password -- needed for pluggable password strength checking */ retval = _unix_read_password(pamh, lctrl ,NULL ,_("Enter new UNIX password: "******"Retype new UNIX password: "******"password - new password not obtained"); } pass_old = NULL; /* tidy up */ return retval; } D(("returned to _unix_chauthtok")); /* * At this point we know who the user is and what they * propose as their new password. Verify that the new * password is acceptable. */ if (*(const char *)pass_new == '\0') { /* "\0" password = NULL */ pass_new = NULL; } retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new, pass_min_len); if (retval != PAM_SUCCESS && off(UNIX_NOT_SET_PASS, ctrl)) { pam_set_item(pamh, PAM_AUTHTOK, NULL); } } if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "new password not acceptable"); pass_new = pass_old = NULL; /* tidy up */ return retval; } if (lock_pwdf() != PAM_SUCCESS) { return PAM_AUTHTOK_LOCK_BUSY; } if (pass_old) { retval = _unix_verify_password(pamh, user, pass_old, ctrl); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "user password changed by another process"); unlock_pwdf(); return retval; } } retval = _unix_verify_shadow(pamh, user, ctrl); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "user shadow entry expired"); unlock_pwdf(); return retval; } retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new, pass_min_len); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "new password not acceptable 2"); pass_new = pass_old = NULL; /* tidy up */ unlock_pwdf(); return retval; } /* * By reaching here we have approved the passwords and must now * rebuild the password database file. */ /* * First we encrypt the new password. */ tpass = create_password_hash(pamh, pass_new, ctrl, rounds); if (tpass == NULL) { pam_syslog(pamh, LOG_CRIT, "out of memory for password"); pass_new = pass_old = NULL; /* tidy up */ unlock_pwdf(); return PAM_BUF_ERR; } D(("password processed")); /* update the password database(s) -- race conditions..? */ retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, remember); /* _do_setpass has called unlock_pwdf for us */ _pam_delete(tpass); pass_old = pass_new = NULL; } else { /* something has broken with the module */ pam_syslog(pamh, LOG_ALERT, "password received unknown request"); retval = PAM_ABORT; } D(("retval was %d", retval)); return retval; }
/* * This is where we check if the password expired. * If the password is correct, but has expired, we return * PAM_NEW_AUTHTOK_REQD instead of PAM_SUCCESS */ int pam_sm_acct_mgmt( pam_handle_t* pamh, int flags, int argc, const char** argv ) { DWORD dwError = 0; PPAMCONTEXT pPamContext = NULL; HANDLE hLsaConnection = (HANDLE)NULL; PLSA_USER_INFO_2 pUserInfo = NULL; DWORD dwUserInfoLevel = 2; PSTR pszLoginId = NULL; PLSA_PAM_CONFIG pConfig = NULL; int iPamError = 0; PSTR pszExpireDone; LSA_LOG_PAM_DEBUG("pam_sm_acct_mgmt::begin"); dwError = LsaPamGetConfig(&pConfig); BAIL_ON_LSA_ERROR(dwError); LsaPamSetLogLevel(pConfig->dwLogLevel); dwError = LsaPamGetContext( pamh, flags, argc, argv, &pPamContext); BAIL_ON_LSA_ERROR(dwError); dwError = LsaPamGetLoginId( pamh, pPamContext, &pszLoginId, TRUE); BAIL_ON_LSA_ERROR(dwError); if (LsaShouldIgnoreUser(pszLoginId)) { LSA_LOG_PAM_DEBUG("By passing lsassd for local account"); dwError = LW_ERROR_NOT_HANDLED; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaOpenServer(&hLsaConnection); BAIL_ON_LSA_ERROR(dwError); dwError = LsaCheckUserInList( hLsaConnection, pszLoginId, NULL); if (dwError && dwError != LW_ERROR_NO_SUCH_USER) { if (dwError == LW_ERROR_NO_SUCH_USER) { BAIL_ON_LSA_ERROR(dwError); } LSA_LOG_PAM_ERROR("User %s is denied access because they are not in the 'require membership of' list", LSA_SAFE_LOG_STRING(pszLoginId)); if (!LW_IS_NULL_OR_EMPTY_STR(pConfig->pszAccessDeniedMessage)) { LsaPamConverse(pamh, pConfig->pszAccessDeniedMessage, PAM_TEXT_INFO, NULL); } } BAIL_ON_LSA_ERROR(dwError); dwError = LsaValidateUser( hLsaConnection, pszLoginId, NULL); if (dwError == LW_ERROR_PASSWORD_EXPIRED) { dwError = 0; pPamContext->bPasswordExpired = TRUE; } BAIL_ON_LSA_ERROR(dwError); if (pPamContext->bPasswordExpired) { // If during pam_sm_authenticate, // we detected that the password expired, // we handle it here if (!pPamContext->bPasswordMessageShown) { LsaPamConverse( pamh, "Your password has expired", PAM_ERROR_MSG, NULL); pPamContext->bPasswordMessageShown = TRUE; } dwError = LW_ERROR_PASSWORD_EXPIRED; BAIL_ON_LSA_ERROR(dwError); } iPamError = pam_get_data( pamh, PAM_LSASS_EXPIRE_WARNING_DONE, (PAM_GET_DATA_TYPE)&pszExpireDone); if (iPamError == PAM_NO_MODULE_DATA) { dwError = LsaFindUserByName( hLsaConnection, pszLoginId, dwUserInfoLevel, (PVOID*)&pUserInfo); BAIL_ON_LSA_ERROR(dwError); if (pUserInfo->bPromptPasswordChange == TRUE && pUserInfo->bPasswordExpired == FALSE && pUserInfo->bPasswordNeverExpires == FALSE) { CHAR szMessage[512]; switch (pUserInfo->dwDaysToPasswordExpiry) { case 0: sprintf(szMessage, "Your password will expire today\n"); break; case 1: sprintf(szMessage, "Your password will expire in 1 day\n"); break; default: sprintf(szMessage, "Your password will expire in %u days\n", pUserInfo->dwDaysToPasswordExpiry); break; } LsaPamConverse(pamh, szMessage, PAM_TEXT_INFO, NULL); } dwError = LsaPamSetDataString( pamh, PAM_LSASS_EXPIRE_WARNING_DONE, "TRUE"); BAIL_ON_LSA_ERROR(dwError); } cleanup: if (pUserInfo) { LsaFreeUserInfo(dwUserInfoLevel, (PVOID)pUserInfo); } if (hLsaConnection != (HANDLE)NULL) { LsaCloseServer(hLsaConnection); } if (pConfig) { LsaPamFreeConfig(pConfig); } LW_SAFE_FREE_STRING(pszLoginId); LSA_LOG_PAM_DEBUG("pam_sm_acct_mgmt::end"); return LsaPamOpenPamFilterAcctMgmt( LsaPamMapErrorCode(dwError, pPamContext)); error: if (dwError == LW_ERROR_NO_SUCH_USER || dwError == LW_ERROR_NOT_HANDLED) { LSA_LOG_PAM_WARNING("pam_sm_acct_mgmt failed [login:%s][error code:%u]", LSA_SAFE_LOG_STRING(pszLoginId), dwError); } else { LSA_LOG_PAM_ERROR("pam_sm_acct_mgmt failed [login:%s][error code:%u]", LSA_SAFE_LOG_STRING(pszLoginId), dwError); if (pszLoginId && !strcmp(pszLoginId, "root")) { dwError = LW_ERROR_NO_SUCH_USER; LSA_LOG_PAM_ERROR("Converting error to %u for root", dwError); } } goto cleanup; }
int pam_sm_open_session( pam_handle_t* pamh, int flags, int argc, const char** argv ) { DWORD dwError = 0; PPAMCONTEXT pPamContext = NULL; HANDLE hLsaConnection = (HANDLE)NULL; PSTR pszLoginId = NULL; PLSA_PAM_CONFIG pConfig = NULL; #ifdef HAVE_PAM_PUTENV PSTR pszSmartCardReader = NULL; PSTR pszSmartCardReaderEnv = NULL; #endif /* HAVE_PAM_PUTENV */ LSA_LOG_PAM_DEBUG("pam_sm_open_session::begin"); dwError = LsaPamGetConfig(&pConfig); BAIL_ON_LSA_ERROR(dwError); LsaPamSetLogLevel(pConfig->dwLogLevel); dwError = LsaPamGetContext( pamh, flags, argc, argv, &pPamContext); BAIL_ON_LSA_ERROR(dwError); dwError = LsaPamGetLoginId( pamh, pPamContext, &pszLoginId, TRUE); BAIL_ON_LSA_ERROR(dwError); #ifdef HAVE_PAM_PUTENV dwError = pam_get_data( pamh, PAM_LSASS_SMART_CARD_READER, (PAM_GET_DATA_TYPE)&pszSmartCardReader); /* pszSmartCardReader will be freed when the module is closed. */ if (dwError == PAM_SUCCESS && pszSmartCardReader != NULL) { dwError = LwAllocateStringPrintf( &pszSmartCardReaderEnv, "LW_SMART_CARD_READER=%s", pszSmartCardReader); BAIL_ON_LSA_ERROR(dwError); dwError = pam_putenv( pamh, pszSmartCardReaderEnv); BAIL_ON_LSA_ERROR(dwError); } #endif /* HAVE_PAM_PUTENV */ if (LsaShouldIgnoreUser(pszLoginId)) { LSA_LOG_PAM_DEBUG("By passing lsassd for local account"); dwError = LW_ERROR_NOT_HANDLED; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaOpenServer(&hLsaConnection); BAIL_ON_LSA_ERROR(dwError); dwError = LsaOpenSession( hLsaConnection, pszLoginId); BAIL_ON_LSA_ERROR(dwError); if (pPamContext && pConfig->bLsaPamDisplayMOTD) { dwError = LsaPamDisplayMOTD( pamh, pPamContext); BAIL_ON_LSA_ERROR(dwError); } if (pPamContext && pPamContext->bOnlineLogon) { dwError = LsaPamNotifyUserLogon( pszLoginId); if (dwError == LW_ERROR_LOAD_LIBRARY_FAILED || dwError == LW_ERROR_LOOKUP_SYMBOL_FAILED ) { dwError = 0; } BAIL_ON_LSA_ERROR(dwError); } cleanup: if (hLsaConnection != (HANDLE)NULL) { LsaCloseServer(hLsaConnection); } if (pConfig) { LsaPamFreeConfig(pConfig); } LW_SAFE_FREE_STRING(pszLoginId); #ifdef HAVE_PAM_PUTENV LW_SAFE_FREE_STRING(pszSmartCardReaderEnv); #endif /* HAVE_PAM_PUTENV */ LSA_LOG_PAM_DEBUG("pam_sm_open_session::end"); return LsaPamOpenPamFilterOpenSession( LsaPamMapErrorCode(dwError, pPamContext)); error: if ((dwError == LW_ERROR_NO_SUCH_USER) || (dwError == LW_ERROR_NOT_HANDLED)) { LSA_LOG_PAM_WARNING("pam_sm_open_session failed [login:%s][error code: %u]", LSA_SAFE_LOG_STRING(pszLoginId), dwError); } else { LSA_LOG_PAM_ERROR("pam_sm_open_session failed [login:%s][error code: %u]", LSA_SAFE_LOG_STRING(pszLoginId), dwError); } goto cleanup; }
int od_record_create(pam_handle_t *pamh, ODRecordRef *record, CFStringRef cfUser) { int retval = PAM_SERVICE_ERR; const int attr_num = 5; ODNodeRef cfNode = NULL; CFErrorRef cferror = NULL; CFArrayRef attrs = NULL; CFTypeRef cfVals[attr_num]; if (NULL == record || NULL == cfUser) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } #ifdef OPENDIRECTORY_CACHE #define CFRECORDNAME_CACHE "CFRecordName" #define CFRECORDNAME_NAME CFSTR("name") #define CFRECORDNAME_RECORD CFSTR("record") CFDictionaryRef cfdict; CFStringRef cachedUser; if (pam_get_data(pamh, CFRECORDNAME_CACHE, (void *)&cfdict) == PAM_SUCCESS && (CFGetTypeID(cfdict) == CFDictionaryGetTypeID()) && (cachedUser = CFDictionaryGetValue(cfdict, CFRECORDNAME_NAME)) != NULL && CFGetTypeID(cachedUser) == CFStringGetTypeID() && CFStringCompare(cfUser, cachedUser, 0) == kCFCompareEqualTo && (*record = (ODRecordRef)CFDictionaryGetValue(cfdict, CFRECORDNAME_RECORD)) != NULL) { CFRetain(*record); return PAM_SUCCESS; } #endif /* OPENDIRECTORY_CACHE */ int current_iterations = 0; cfNode = ODNodeCreateWithNodeType(kCFAllocatorDefault, kODSessionDefault, eDSAuthenticationSearchNodeName, &cferror); if (NULL == cfNode || NULL != cferror) { openpam_log(PAM_LOG_ERROR, "ODNodeCreateWithNodeType failed."); retval = PAM_SERVICE_ERR; goto cleanup; } cfVals[0] = kODAttributeTypeAuthenticationAuthority; cfVals[1] = kODAttributeTypeHomeDirectory; cfVals[2] = kODAttributeTypeNFSHomeDirectory; cfVals[3] = kODAttributeTypeUserShell; cfVals[4] = kODAttributeTypeUniqueID; attrs = CFArrayCreate(kCFAllocatorDefault, cfVals, (CFIndex)attr_num, &kCFTypeArrayCallBacks); if (NULL == attrs) { openpam_log(PAM_LOG_DEBUG, "CFArrayCreate() failed"); retval = PAM_BUF_ERR; goto cleanup; } retval = PAM_SERVICE_ERR; while (current_iterations <= kMaxIterationCount) { CFIndex unreachable_count = 0; CFArrayRef unreachable_nodes = ODNodeCopyUnreachableSubnodeNames(cfNode, NULL); if (unreachable_nodes) { unreachable_count = CFArrayGetCount(unreachable_nodes); CFRelease(unreachable_nodes); openpam_log(PAM_LOG_DEBUG, "%lu OD nodes unreachable.", unreachable_count); } *record = ODNodeCopyRecord(cfNode, kODRecordTypeUsers, cfUser, attrs, &cferror); if (*record) break; if (0 == unreachable_count) break; openpam_log(PAM_LOG_DEBUG, "Waiting %d seconds for nodes to become reachable", kWaitSeconds); sleep(kWaitSeconds); ++current_iterations; } if (*record) { #ifdef OPENDIRECTORY_CACHE const void *keys[] = { CFRECORDNAME_NAME, CFRECORDNAME_RECORD }; const void *values[] = { cfUser, *record }; CFDictionaryRef dict; dict = CFDictionaryCreate(NULL, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (dict) pam_set_data(pamh, CFRECORDNAME_CACHE, (void *)dict, cleanup_cache); #endif /* OPENDIRECTORY_CACHE */ retval = PAM_SUCCESS; } else { retval = PAM_USER_UNKNOWN; } if (current_iterations > 0) { char *wt = NULL, *found = NULL; int retval2; if (*record) found = "failure"; else found = "success"; retval2 = asprintf(&wt, "%d", kWaitSeconds * current_iterations); if (-1 == retval2) { openpam_log(PAM_LOG_DEBUG, "Failed to convert current wait time to string."); retval = PAM_BUF_ERR; goto cleanup; } aslmsg m = asl_new(ASL_TYPE_MSG); asl_set(m, "com.apple.message.domain", "com.apple.pam_modules.odAvailableWaitTime" ); asl_set(m, "com.apple.message.signature", "wait_time"); asl_set(m, "com.apple.message.value", wt); asl_set(m, "com.apple.message.result", found); asl_log(NULL, m, ASL_LEVEL_NOTICE, "OD nodes online delay: %ss. User record lookup: %s.", wt, found); asl_free(m); free(wt); } cleanup: if (NULL != attrs) { CFRelease(attrs); } if (NULL != cferror) { CFRelease(cferror); } if (NULL != cfNode) { CFRelease(cfNode); } if (PAM_SUCCESS != retval) { openpam_log(PAM_LOG_ERROR, "failed: %d", retval); if (NULL != *record) { CFRelease(*record); *record = NULL; } } return retval; }
/* * pam_sm_setcred */ int pam_sm_setcred( pam_handle_t *pamh, int flags, int argc, const char **argv) { int debug = 0; int warn = 1; int i; dce_module_data_t *dsd; error_status_t st; int err; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; if (strcmp(argv[i], "nowarn") == 0) warn = 0; } if (flags & PAM_SILENT) warn = 0; if (debug) syslog(LOG_DEBUG, "DCE pam_setcred"); if (pam_get_data(pamh, DCE_DATA, (void**)&dsd) != PAM_SUCCESS || dsd == NULL) { if (flags & PAM_DELETE_CRED) { sec_login_handle_t context; /* attempt to get current context and purge */ sec_login_get_current_context(&context, &st); if (st == error_status_ok) { sec_login_purge_context(&context, &st); } return (st == error_status_ok ? PAM_SUCCESS : PAM_CRED_UNAVAIL); } if (warn) do_cred_warn(pamh); return (PAM_IGNORE); /* since pam_auth was never called */ } if (dsd->auth_status != PAM_SUCCESS) return (dsd->auth_status); if (flags & PAM_DELETE_CRED) { (void) sec_login_purge_context(dsd->login_context, &st); if (debug) { dce_error_string_t text; syslog(LOG_DEBUG, "PAM: DCE sec_login_purge_context: %s", get_dce_error_message(st, text)); } } else { if (dsd->auth_src == sec_login_auth_src_local) { /* we can't set_context on locally authenticated */ /* contexts */ st = sec_login_s_auth_local; } else { (void) sec_login_set_context(dsd->login_context, &st); } if (debug) { dce_error_string_t text; syslog(LOG_DEBUG, "PAM: DCE sec_login_set_context: %s", get_dce_error_message(st, text)); } } /* might want an option to return success even if set_context failed */ if (st == error_status_ok) { return (PAM_SUCCESS); } else { if (warn) do_cred_warn(pamh); if (debug) syslog(LOG_DEBUG, "Can't set user login context"); return (PAM_CRED_ERR); } }
/* * pam_krb5 acct_mgmt * * we do * - check if pw expired (flag set in auth) * - warn user if pw is set to expire * * notes * - we require the auth module to have already run (sets module data) * - we don't worry about an expired princ cuz if that's the case, * auth would have failed */ int pam_sm_acct_mgmt( pam_handle_t *pamh, int flags, int argc, const char **argv) { char *user = NULL; char *userdata = NULL; int err; int i; krb5_module_data_t *kmd = NULL; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; int debug = 0; /* pam.conf entry option */ int nowarn = 0; /* pam.conf entry option, no expire warnings */ pam_repository_t *rep_data = NULL; for (i = 0; i < argc; i++) { if (strcasecmp(argv[i], "debug") == 0) debug = 1; else if (strcasecmp(argv[i], "nowarn") == 0) { nowarn = 1; flags = flags | PAM_SILENT; } else { __pam_log(LOG_AUTH | LOG_ERR, "PAM-KRB5 (acct): illegal option %s", argv[i]); } } if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): debug=%d, nowarn=%d", debug, nowarn); (void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data); if (rep_data != NULL) { /* * If the repository is not ours, * return PAM_IGNORE. */ if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) { if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): wrong" "repository found (%s), returning " "PAM_IGNORE", rep_data->type); return (PAM_IGNORE); } } /* get user name */ (void) pam_get_item(pamh, PAM_USER, (void **) &user); if (user == NULL || *user == '\0') { err = PAM_USER_UNKNOWN; goto out; } /* get pam_krb5_migrate specific data */ err = pam_get_data(pamh, KRB5_AUTOMIGRATE_DATA, (const void **)&userdata); if (err != PAM_SUCCESS) { if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): " "no module data for KRB5_AUTOMIGRATE_DATA"); } else { /* * We try and reauthenticate, since this user has a * newly created krb5 principal via the pam_krb5_migrate * auth module. That way, this new user will have fresh * creds (assuming pam_sm_authenticate() succeeds). */ if (strcmp(user, userdata) == 0) (void) pam_sm_authenticate(pamh, flags, argc, (const char **)argv); else if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): PAM_USER %s" "does not match user %s from pam_get_data()", user, (char *)userdata); } /* get krb5 module data */ if ((err = pam_get_data(pamh, KRB5_DATA, (const void **)&kmd)) != PAM_SUCCESS) { if (err == PAM_NO_MODULE_DATA) { /* * pam_auth never called (possible config * error; no pam_krb5 auth entry in pam.conf), */ if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): no module data"); } err = PAM_IGNORE; goto out; } else { __pam_log(LOG_AUTH | LOG_ERR, "PAM-KRB5 (acct): get module" " data failed: err=%d", err); } goto out; } debug = debug || kmd->debug; /* * auth mod set status to ignore, most likely cuz root key is * in keytab, so skip other checks and return ignore */ if (kmd->auth_status == PAM_IGNORE) { if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): kmd auth_status is IGNORE"); err = PAM_IGNORE; goto out; } /* * If there is no Kerberos related user and there is authentication * data, this means that while the user has successfully passed * authentication, Kerberos is not the account authority because there * is no valid Kerberos principal. PAM_IGNORE is returned since * Kerberos is not authoritative for this user. Other modules in the * account stack will need to determine the success or failure for this * user. */ if (kmd->auth_status == PAM_USER_UNKNOWN) { if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (acct): kmd auth_status is USER UNKNOWN"); err = PAM_IGNORE; goto out; } /* * age_status will be set to PAM_NEW_AUTHTOK_REQD in pam_krb5's * 'auth' if the user's key/pw has expired and needs to be changed */ if (kmd->age_status == PAM_NEW_AUTHTOK_REQD) { if (!nowarn) { (void) snprintf(messages[0], sizeof (messages[0]), dgettext(TEXT_DOMAIN, "Your Kerberos password has expired.\n")); (void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1, messages, NULL); } err = PAM_NEW_AUTHTOK_REQD; goto out; } if (kmd->auth_status == PAM_SUCCESS && !(flags & PAM_SILENT) && !nowarn && kmd->password) { /* if we fail, let it slide, it's only a warning brah */ (void) exp_warn(pamh, user, kmd, debug); } /* * If Kerberos is treated as optional in the PAM stack, it is possible * that there is a KRB5_DATA item and a non-Kerberos account authority. * In that case, PAM_IGNORE is returned. */ err = kmd->auth_status != PAM_SUCCESS ? PAM_IGNORE : kmd->auth_status; out: if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): end: %s", pam_strerror(pamh, err)); return (err); }
int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { unsigned int ctrl; int retval; extern BOOL in_client; SAM_ACCOUNT *sampass = NULL; void (*oldsig_handler)(int); const char *user; char *pass_old; char *pass_new; NTSTATUS nt_status; /* Samba initialization. */ setup_logging( "pam_smbpass", False ); in_client = True; ctrl = set_ctrl(flags, argc, argv); /* * First get the name of a user. No need to do anything if we can't * determine this. */ retval = pam_get_user( pamh, &user, "Username: "******"password: could not identify user" ); } return retval; } if (on( SMB_DEBUG, ctrl )) { _log_err( LOG_DEBUG, "username [%s] obtained", user ); } /* Getting into places that might use LDAP -- protect the app from a SIGPIPE it's not expecting */ oldsig_handler = CatchSignal(SIGPIPE, SIGNAL_CAST SIG_IGN); if (!initialize_password_db(True)) { _log_err( LOG_ALERT, "Cannot access samba password database" ); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return PAM_AUTHINFO_UNAVAIL; } /* obtain user record */ if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(&sampass))) { CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return nt_status_to_pam(nt_status); } if (!pdb_getsampwnam(sampass,user)) { _log_err( LOG_ALERT, "Failed to find entry for user %s.", user ); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return PAM_USER_UNKNOWN; } if (flags & PAM_PRELIM_CHECK) { /* * obtain and verify the current password (OLDAUTHTOK) for * the user. */ char *Announce; if (_smb_blankpasswd( ctrl, sampass )) { pdb_free_sam(&sampass); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return PAM_SUCCESS; } /* Password change by root, or for an expired token, doesn't require authentication. Is this a good choice? */ if (getuid() != 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) { /* tell user what is happening */ #define greeting "Changing password for " Announce = (char *) malloc(sizeof(greeting)+strlen(user)); if (Announce == NULL) { _log_err(LOG_CRIT, "password: out of memory"); pdb_free_sam(&sampass); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return PAM_BUF_ERR; } strncpy( Announce, greeting, sizeof(greeting) ); strncpy( Announce+sizeof(greeting)-1, user, strlen(user)+1 ); #undef greeting set( SMB__OLD_PASSWD, ctrl ); retval = _smb_read_password( pamh, ctrl, Announce, "Current SMB password: "******"password - (old) token not obtained" ); pdb_free_sam(&sampass); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return retval; } /* verify that this is the password for this user */ retval = _smb_verify_password( pamh, sampass, pass_old, ctrl ); } else { pass_old = NULL; retval = PAM_SUCCESS; /* root doesn't have to */ } pass_old = NULL; pdb_free_sam(&sampass); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return retval; } else if (flags & PAM_UPDATE_AUTHTOK) { /* * obtain the proposed password */ /* * get the old token back. NULL was ok only if root [at this * point we assume that this has already been enforced on a * previous call to this function]. */ if (off( SMB_NOT_SET_PASS, ctrl )) { retval = pam_get_item( pamh, PAM_OLDAUTHTOK, (const void **)&pass_old ); } else { retval = pam_get_data( pamh, _SMB_OLD_AUTHTOK, (const void **)&pass_old ); if (retval == PAM_NO_MODULE_DATA) { pass_old = NULL; retval = PAM_SUCCESS; } } if (retval != PAM_SUCCESS) { _log_err( LOG_NOTICE, "password: user not authenticated" ); pdb_free_sam(&sampass); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return retval; } /* * use_authtok is to force the use of a previously entered * password -- needed for pluggable password strength checking * or other module stacking */ if (on( SMB_USE_AUTHTOK, ctrl )) { set( SMB_USE_FIRST_PASS, ctrl ); } retval = _smb_read_password( pamh, ctrl , NULL , "Enter new SMB password: "******"Retype new SMB password: "******"password: new password not obtained" ); } pass_old = NULL; /* tidy up */ pdb_free_sam(&sampass); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return retval; } /* * At this point we know who the user is and what they * propose as their new password. Verify that the new * password is acceptable. */ if (pass_new[0] == '\0') { /* "\0" password = NULL */ pass_new = NULL; } retval = _pam_smb_approve_pass(pamh, ctrl, pass_old, pass_new); if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, "new password not acceptable"); pass_new = pass_old = NULL; /* tidy up */ pdb_free_sam(&sampass); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return retval; } /* * By reaching here we have approved the passwords and must now * rebuild the smb password file. */ /* update the password database */ retval = smb_update_db(pamh, ctrl, user, pass_new); if (retval == PAM_SUCCESS) { uid_t uid; /* password updated */ if (!NT_STATUS_IS_OK(sid_to_uid(pdb_get_user_sid(sampass), &uid))) { _log_err( LOG_NOTICE, "Unable to get uid for user %s", pdb_get_username(sampass)); _log_err( LOG_NOTICE, "password for (%s) changed by (%s/%d)", user, uidtoname(getuid()), getuid()); } else { _log_err( LOG_NOTICE, "password for (%s/%d) changed by (%s/%d)", user, uid, uidtoname(getuid()), getuid()); } } else { _log_err( LOG_ERR, "password change failed for user %s", user); } pass_old = pass_new = NULL; if (sampass) { pdb_free_sam(&sampass); sampass = NULL; } } else { /* something has broken with the library */ _log_err( LOG_ALERT, "password received unknown request" ); retval = PAM_ABORT; } if (sampass) { pdb_free_sam(&sampass); sampass = NULL; } pdb_free_sam(&sampass); CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler); return retval; }
/***************************************************************************** Func Name: pam_local_session_update Date Created: 2009/2/23 Author: chendong Description: 更新本地计费会话信息 Input: pam_handle_t* pamh PAM Handle sqlite3 *db 数据库句柄 Output: 无 Return: 无 Caution: ----------------------------------------------------------------------------- Modification History DATE NAME DESCRIPTION ----------------------------------------------------------------------------- ******************************************************************************/ static int pam_local_session_update (pam_handle_t * pamh, sqlite3 *db) { time_t now; int rc; const int *seq = NULL; struct pam_ext_item *item = NULL; s8 sql[MAX_SQL_STR] = {0}; unsigned int pkt_in = 0, pkt_out = 0, oct_in = 0, oct_out = 0; void *item_tmp = (void *)item; /* 获取start的时候保持的序列号 */ rc = pam_get_data (pamh, PAM_LOCAL_ACCT_SEQ, (const void **)&item_tmp); item = (struct pam_ext_item *)item_tmp; if (PAM_SUCCESS != rc || NULL == seq) { return PAM_BUF_ERR; } /* 获取统计项 */ rc = pam_get_item (pamh, PAM_EXT_ACCT_INPUT_PACKETS, (const void **)&item_tmp); item = (struct pam_ext_item *)item_tmp; if (PAM_SUCCESS == rc) { pkt_in = *(unsigned int *) item->item_value; } rc = pam_get_item (pamh, PAM_EXT_ACCT_OUTPUT_PACKETS, (const void **)&item_tmp); item = (struct pam_ext_item *)item_tmp; if (PAM_SUCCESS == rc) { pkt_out= *(unsigned int *) item->item_value; } rc = pam_get_item (pamh, PAM_EXT_ACCT_INPUT_OCTETS, (const void **)&item_tmp); item = (struct pam_ext_item *)item_tmp; if (PAM_SUCCESS == rc) { oct_in = *(unsigned int *) item->item_value; } rc = pam_get_item (pamh, PAM_EXT_ACCT_OUTPUT_OCTETS, (const void **)&item_tmp); item = (struct pam_ext_item *)item_tmp; if (PAM_SUCCESS == rc) { oct_out = *(unsigned int *) item->item_value; } /* 获取当前时间,将下线时间更新为当前时间 */ now = time (NULL); /* 更新计费表项 */ sprintf((char *)sql, "update tb_pam_account set logout_time = %ld, input_packets = %d, output_packets = %d, input_octets = %d, output_octets = %d where sequence = %d;", now, pkt_in, pkt_out, oct_in, oct_out, *seq); rc= (int)sqlite3_exec_ex(db, sql); if (0 != rc) { pam_local_logger ("dba error %d", rc); return PAM_SYSTEM_ERR; } return PAM_SUCCESS; }
extern int pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv) { int retcode = PAM_SUCCESS; int errcode = PAM_SUCCESS; int origmask; int logmask = LOG_UPTO(LOG_INFO); int nowarn = 0; int use_first_pass = 1; /* use the password passed in by auth */ int try_first_pass = 0; int ignore_uid = 0; uid_t ignore_uid_id = 0; int refresh_token = 0; int set_expires = 0; /* the default is to not to set the env variable */ int use_klog = 0; int i; PAM_CONST struct pam_conv *pam_convp = NULL; char my_password_buf[256]; char *cell_ptr = NULL; char sbuffer[100]; char *torch_password = NULL; int auth_ok = 0; PAM_CONST char *user = NULL; const char *password = NULL; int password_expires = -1; char *reason = NULL; struct passwd *upwd = NULL; #if !(defined(AFS_LINUX20_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV) || defined(AFS_NBSD_ENV)) char upwd_buf[2048]; /* size is a guess. */ struct passwd unix_pwd; #endif #ifndef AFS_SUN5_ENV openlog(pam_afs_ident, LOG_CONS, LOG_AUTH); #endif origmask = setlogmask(logmask); /* * Parse the user options. Log an error for any unknown options. */ for (i = 0; i < argc; i++) { if (strcasecmp(argv[i], "debug") == 0) { logmask |= LOG_MASK(LOG_DEBUG); (void)setlogmask(logmask); } else if (strcasecmp(argv[i], "nowarn") == 0) { nowarn = 1; } else if (strcasecmp(argv[i], "use_first_pass") == 0) { use_first_pass = 1; /* practically redundant */ } else if (strcasecmp(argv[i], "try_first_pass") == 0) { try_first_pass = 1; } else if (strcasecmp(argv[i], "ignore_root") == 0) { ignore_uid = 1; ignore_uid_id = 0; } else if (strcasecmp(argv[i], "ignore_uid") == 0) { i++; if (i == argc) { pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID, "ignore_uid missing argument"); ignore_uid = 0; } else { ignore_uid = 1; ignore_uid_id = (uid_t) strtol(argv[i], (char **)NULL, 10); if (ignore_uid_id > IGNORE_MAX) { ignore_uid = 0; pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID, argv[i]); } } } else if (strcasecmp(argv[i], "cell") == 0) { i++; if (i == argc) { pam_afs_syslog(LOG_ERR, PAMAFS_OTHERCELL, "cell missing argument"); } else { cell_ptr = (char *)argv[i]; pam_afs_syslog(LOG_INFO, PAMAFS_OTHERCELL, cell_ptr); } } else if (strcasecmp(argv[i], "no_unlog") == 0) { ; } else if (strcasecmp(argv[i], "refresh_token") == 0) { refresh_token = 1; } else if (strcasecmp(argv[i], "set_token") == 0) { ; } else if (strcasecmp(argv[i], "dont_fork") == 0) { ; } else if (strcasecmp(argv[i], "use_klog") == 0) { use_klog = 1; } else if (strcasecmp(argv[i], "setenv_password_expires") == 0) { set_expires = 1; } else { pam_afs_syslog(LOG_ERR, PAMAFS_UNKNOWNOPT, argv[i]); } } if (use_first_pass) try_first_pass = 0; if (logmask & LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass, try_first_pass, ignore_uid, ignore_uid_id, 8, 8, 8, 8); /* Try to get the user-interaction info, if available. */ errcode = pam_get_item(pamh, PAM_CONV, (PAM_CONST void **)&pam_convp); if (errcode != PAM_SUCCESS) { if (logmask & LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_NO_USER_INT); pam_convp = NULL; } /* Who are we trying to authenticate here? */ if ((errcode = pam_get_user(pamh, (PAM_CONST char **)&user, "AFS username:"******"local" (or via nss, possibly nss_dce) pwent, * and its uid==0, and "ignore_root" was given in pam.conf, * ignore the user. */ /* enhanced: use "ignore_uid <number>" to specify the largest uid * which should be ignored by this module */ #if defined(AFS_HPUX_ENV) || defined(AFS_DARWIN100_ENV) || defined(AFS_SUN5_ENV) #if defined(AFS_HPUX110_ENV) || defined(AFS_DARWIN100_ENV) || defined(AFS_SUN5_ENV) i = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf), &upwd); #else /* AFS_HPUX110_ENV */ i = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf)); if (i == 0) /* getpwnam_r success */ upwd = &unix_pwd; #endif /* AFS_HPUX110_ENV */ if (ignore_uid && i == 0 && upwd && upwd->pw_uid <= ignore_uid_id) { pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user); RET(PAM_AUTH_ERR); } #else #if defined(AFS_LINUX20_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV) || defined(AFS_NBSD_ENV) upwd = getpwnam(user); #else upwd = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf)); #endif if (ignore_uid && upwd != NULL && upwd->pw_uid <= ignore_uid_id) { pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user); RET(PAM_AUTH_ERR); } #endif if (flags & PAM_DELETE_CRED) { if (logmask & LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_DELCRED, user); RET(PAM_SUCCESS); } else if (flags & PAM_REINITIALIZE_CRED) { if (logmask & LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_REINITCRED, user); RET(PAM_SUCCESS); } else { /* flags are PAM_REFRESH_CRED, PAM_ESTABLISH_CRED, unknown */ if (logmask & LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_ESTABCRED, user); errcode = pam_get_data(pamh, pam_afs_lh, (const void **)&password); if (errcode != PAM_SUCCESS || password == NULL) { if (use_first_pass) { pam_afs_syslog(LOG_ERR, PAMAFS_PASSWD_REQ, user); RET(PAM_AUTH_ERR); } password = NULL; /* In case it isn't already NULL */ if (logmask & LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user); } else if (password[0] == '\0') { /* Actually we *did* get one but it was empty. */ /* So don't use it. */ password = NULL; if (use_first_pass) { pam_afs_syslog(LOG_ERR, PAMAFS_PASSWD_REQ, user); RET(PAM_NEW_AUTHTOK_REQD); } if (logmask & LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_NILPASSWORD, user); } else { if (logmask & LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user); } if (!(use_first_pass || try_first_pass)) { password = NULL; } try_auth: if (password == NULL) { char *prompt_password; if (use_first_pass) RET(PAM_AUTH_ERR); /* shouldn't happen */ if (try_first_pass) try_first_pass = 0; /* we come back if try_first_pass==1 below */ if (pam_convp == NULL || pam_convp->conv == NULL) { pam_afs_syslog(LOG_ERR, PAMAFS_CANNOT_PROMPT); RET(PAM_AUTH_ERR); } errcode = pam_afs_prompt(pam_convp, &prompt_password, 0, PAMAFS_PWD_PROMPT); if (errcode != PAM_SUCCESS || prompt_password == NULL) { pam_afs_syslog(LOG_ERR, PAMAFS_GETPASS_FAILED); RET(PAM_AUTH_ERR); } if (prompt_password[0] == '\0') { if (logmask & LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_NILPASSWORD); RET(PAM_NEW_AUTHTOK_REQD); } /* * We aren't going to free the password later (we will wipe it, * though), because the storage for it if we get it from other * paths may belong to someone else. Since we do need to free * this storage, copy it to a buffer that won't need to be freed * later, and free this storage now. */ strncpy(my_password_buf, prompt_password, sizeof(my_password_buf)); my_password_buf[sizeof(my_password_buf) - 1] = '\0'; memset(prompt_password, 0, strlen(prompt_password)); free(prompt_password); password = torch_password = my_password_buf; } /* * We only set a PAG here, if we haven't got one before in * pam_sm_authenticate() or if it was destroyed by the application */ if ((!refresh_token) && (getPAG() == -1)) { if (logmask & LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "New PAG created in pam_setcred()"); setpag(); #ifdef AFS_KERBEROS_ENV ktc_newpag(); #endif } if (flags & PAM_REFRESH_CRED) { if (use_klog) { auth_ok = !do_klog(user, password, "00:00:01", cell_ptr); ktc_ForgetAllTokens(); } else { if (ka_VerifyUserPassword(KA_USERAUTH_VERSION, (char *)user, /* kerberos name */ NULL, /* instance */ cell_ptr, /* realm */ (char*)password, /* password */ 0, /* spare 2 */ &reason /* error string */ )) { pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user, reason); } else { auth_ok = 1; } } } if (flags & PAM_ESTABLISH_CRED) { if (use_klog) auth_ok = !do_klog(user, password, NULL, cell_ptr); else { if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, (char *)user, /* kerberos name */ NULL, /* instance */ cell_ptr, /* realm */ (char*)password, /* password */ 0, /* default lifetime */ &password_expires, 0, /* spare 2 */ &reason /* error string */ )) { pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user, reason); } else { auth_ok = 1; } } } if (!auth_ok && try_first_pass) { password = NULL; goto try_auth; } /* pam_sm_authenticate should have set this * if (auth_ok && !got_authtok) { * torch_password = NULL; * (void) pam_set_item(pamh, PAM_AUTHTOK, password); * } */ if (auth_ok) { if (set_expires && !use_klog && (password_expires >= 0)) { strcpy(sbuffer, "PASSWORD_EXPIRES="); strcat(sbuffer, cv2string(&sbuffer[100], password_expires)); errcode = pam_putenv(pamh, sbuffer); if (errcode != PAM_SUCCESS) pam_afs_syslog(LOG_ERR, PAMAFS_PASSEXPFAIL, user); } #if defined(AFS_KERBEROS_ENV) if (upwd) { if (chown(ktc_tkt_string(), upwd->pw_uid, upwd->pw_gid) < 0) pam_afs_syslog(LOG_ERR, PAMAFS_CHOWNKRB, user); sprintf(sbuffer, "KRBTKFILE=%s", ktc_tkt_string()); errcode = pam_putenv(pamh, sbuffer); if (errcode != PAM_SUCCESS) pam_afs_syslog(LOG_ERR, PAMAFS_KRBFAIL, user); } #endif RET(PAM_SUCCESS); } else { RET(PAM_CRED_ERR); } } out: if (password && torch_password) memset(torch_password, 0, strlen(torch_password)); (void)setlogmask(origmask); #ifndef AFS_SUN5_ENV closelog(); #endif return retcode; }
DWORD LsaPamGetContext( pam_handle_t* pamh, int flags, int argc, const char** argv, PPAMCONTEXT* ppPamContext ) { DWORD dwError = 0; PPAMCONTEXT pPamContext = NULL; BOOLEAN bFreeContext = FALSE; int iPamError = 0; LSA_LOG_PAM_DEBUG("LsaPamGetContext::begin"); iPamError = pam_get_data(pamh, MODULE_NAME, (PAM_GET_DATA_TYPE)&pPamContext); dwError = LsaPamUnmapErrorCode(iPamError); if (dwError) { if (dwError == LsaPamUnmapErrorCode(PAM_NO_MODULE_DATA)) { dwError = LwAllocateMemory( sizeof(PAMCONTEXT), (PVOID*)&pPamContext); BAIL_ON_LSA_ERROR(dwError); bFreeContext = TRUE; iPamError = pam_set_data( pamh, MODULE_NAME, (PVOID)pPamContext, &LsaPamCleanupContext); dwError = LsaPamUnmapErrorCode(iPamError); BAIL_ON_LSA_ERROR(dwError); bFreeContext = FALSE; } else { BAIL_ON_LSA_ERROR(dwError); } } dwError = LsaPamGetLoginId(pamh, pPamContext, NULL, FALSE); BAIL_ON_LSA_ERROR(dwError); dwError = LsaPamGetOptions( pamh, flags, argc, argv, &pPamContext->pamOptions); BAIL_ON_LSA_ERROR(dwError); *ppPamContext = pPamContext; cleanup: LSA_LOG_PAM_DEBUG("LsaPamGetContext::end"); return dwError; error: if (pPamContext && bFreeContext) { LsaPamFreeContext(pPamContext); } *ppPamContext = NULL; LSA_LOG_PAM_ERROR("LsaPamGetContext failed [error code: %u]", dwError); goto cleanup; }
struct passwd * pam_modutil_getpwuid(pam_handle_t *pamh, uid_t uid) { #ifdef HAVE_GETPWUID_R void *buffer=NULL; size_t length = PWD_INITIAL_LENGTH; do { int status; void *new_buffer; struct passwd *result = NULL; new_buffer = realloc(buffer, sizeof(struct passwd) + length); if (new_buffer == NULL) { D(("out of memory")); /* no memory for the user - so delete the memory */ if (buffer) { free(buffer); } return NULL; } buffer = new_buffer; /* make the re-entrant call to get the pwd structure */ errno = 0; status = getpwuid_r(uid, buffer, sizeof(struct passwd) + (char *) buffer, length, &result); if (!status && (result == buffer)) { char *data_name; const void *ignore; int i; data_name = malloc(strlen("_pammodutil_getpwuid") + 1 + longlen((long) uid) + 1 + intlen(INT_MAX) + 1); if ((pamh != NULL) && (data_name == NULL)) { D(("was unable to register the data item [%s]", pam_strerror(pamh, status))); free(buffer); return NULL; } if (pamh != NULL) { for (i = 0; i < INT_MAX; i++) { sprintf(data_name, "_pammodutil_getpwuid_%ld_%d", (long) uid, i); status = PAM_NO_MODULE_DATA; if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) { status = pam_set_data(pamh, data_name, result, pam_modutil_cleanup); } if (status == PAM_SUCCESS) { break; } } } else { status = PAM_SUCCESS; } free(data_name); if (status == PAM_SUCCESS) { D(("success")); return result; } D(("was unable to register the data item [%s]", pam_strerror(pamh, status))); free(buffer); return NULL; } else if (errno != ERANGE && errno != EINTR) { /* no sense in repeating the call */ break; } length <<= PWD_LENGTH_SHIFT; } while (length < PWD_ABSURD_PWD_LENGTH); D(("pwd structure took %u bytes or so of memory", length+sizeof(struct passwd))); free(buffer); return NULL; #else /* ie. ifndef HAVE_GETPWUID_R */ /* * Sorry, there does not appear to be a reentrant version of * getpwuid(). So, we use the standard libc function. */ return getpwuid(uid); #endif /* def HAVE_GETPWUID_R */ }
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { pam_syslog(pamh, LOG_INFO, "pam_sm_authenticate\n"); if (get_env(pamh, "PAM_KWALLET_LOGIN") != NULL) { pam_syslog(pamh, LOG_INFO, "pam_kwallet: we were already executed"); return PAM_SUCCESS; } parseArguments(argc, argv); int result; //Fetch the user, needed to get user information const char *username; result = pam_get_user(pamh, &username, NULL); if (result != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get username %s", pam_strerror(pamh, result)); return PAM_IGNORE;//Since we are not an essential module, just make pam ignore us } struct passwd *userInfo; userInfo = getpwnam(username); if (!userInfo) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get user info (passwd) info"); return PAM_IGNORE; } const char *password; result = pam_get_item(pamh, PAM_AUTHTOK, (const void**)&password); if (result != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get password %s", pam_strerror(pamh, result)); return PAM_IGNORE; } if (!password) { pam_syslog(pamh, LOG_NOTICE, "pam_kwallet: Couldn't get password (it is empty)"); //Asking for the password ourselves result = prompt_for_password(pamh); if (result != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Prompt for password failed %s", pam_strerror(pamh, result) ); return PAM_IGNORE; } } //even though we just set it, better check to be 100% sure result = pam_get_item(pamh, PAM_AUTHTOK, (const void**)&password); if (result != PAM_SUCCESS || !password) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Password is not there even though we set it %s", pam_strerror(pamh, result)); return PAM_IGNORE; } char *key = malloc(sizeof(char) * KWALLET_PAM_KEYSIZE); if (kwallet_hash(password, userInfo, key) != 0) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Fail into creating the hash"); return PAM_IGNORE; } result = pam_set_data(pamh, "kwallet_key", key, NULL); if (result != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: Impossible to store the hashed password: %s" , pam_strerror(pamh, result)); return PAM_IGNORE; } //if sm_open_session has already been called (but we did not have password), call it now const char *session_bit; result = pam_get_data(pamh, "sm_open_session", (const void **)&session_bit); if (result == PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "pam_kwallet: open_session was called before us, calling it now"); return pam_sm_open_session(pamh, flags, argc, argv); } //TODO unlock kwallet that is already executed return PAM_SUCCESS; }