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 setup_environment (char *line, void *arg) { pam_handle_t *ph = (pam_handle_t*)arg; char *x; int ret; /* * Called for each stdout output line from the daemon * presumably environment variables. */ assert (line); assert (arg); /* Make sure it is in fact an environment variable */ if (!strchr (line, '=')) return PAM_SUCCESS; line = strbtrim (line); ret = pam_putenv (ph, line); /* If it's the PID line then we're interested in it */ if (strncmp (line, ENV_PID, strlen (ENV_PID)) == 0) { x = line + strlen (ENV_PID); if (x[0] == '=') pam_set_data (ph, "gkr-pam-pid", strdup (x + 1), cleanup_free); } return ret; }
/* 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; }
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", &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*/ }
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); }
void gray_make_str(pam_handle_t *pamh, const char *str, const char *name, char **ret) { int retval; char *newstr = XSTRDUP(str); retval = pam_set_data(pamh, name, (void *)newstr, gray_cleanup_string); if (retval != PAM_SUCCESS) { _pam_log(LOG_CRIT, "can't keep data [%s]: %s", name, pam_strerror(pamh, retval)); gray_pam_delete(newstr); } else { *ret = newstr; newstr = NULL; } }
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; }
DWORD LsaPamSetDataString( pam_handle_t* pamh, PCSTR pszKey, PCSTR pszStr ) { DWORD dwError = 0; PSTR pszStrCopy = NULL; int iPamError = 0; dwError = LwAllocateString(pszStr, &pszStrCopy); BAIL_ON_LSA_ERROR(dwError); iPamError = pam_set_data(pamh, pszKey, pszStrCopy, LsaPamCleanupDataString); dwError = LsaPamUnmapErrorCode(iPamError); BAIL_ON_LSA_ERROR(dwError); error: return dwError; }
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); }
static int _pam_get_password(pam_handle_t *pamh, char **password, const char *prompt) { char *item, *token; int retval; struct pam_message msg[3], *pmsg[3]; struct pam_response *resp; int i, replies; DEBUG(90,("enter _pam_get_password")); if (cntl_flags & CNTL_AUTHTOK) { /* * get the password from the PAM item */ retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &item); if (retval != PAM_SUCCESS) { /* very strange. */ _pam_log(LOG_ALERT, "can't retrieve password item: %s", pam_strerror(pamh, retval)); return retval; } else if (item != NULL) { *password = item; item = NULL; return PAM_SUCCESS; } else return PAM_AUTHTOK_RECOVER_ERR; } /* * ask user for the password */ /* prepare to converse */ i = 0; pmsg[i] = &msg[i]; msg[i].msg_style = PAM_PROMPT_ECHO_OFF; msg[i++].msg = (const void*)prompt; replies = 1; /* run conversation */ resp = NULL; token = NULL; retval = gray_converse(pamh, i, pmsg, &resp); if (resp != NULL && resp[i - replies].resp) { if (retval == PAM_SUCCESS) { /* a good conversation */ token = XSTRDUP(resp[i - replies].resp); DEBUG(100,("app returned [%s]", token)); pam_set_item(pamh, PAM_AUTHTOK, token); PAM_DROP_REPLY(resp, 1); } else { _pam_log(LOG_ERR, "conversation error: %s", pam_strerror(pamh, retval)); } } else { retval = (retval == PAM_SUCCESS) ? PAM_AUTHTOK_RECOVER_ERR : retval; } if (retval == PAM_SUCCESS) { /* * keep password as data specific to this module. pam_end() * will arrange to clean it up. */ retval = pam_set_data(pamh, "password", (void *)token, gray_cleanup_string); if (retval != PAM_SUCCESS) { _pam_log(LOG_CRIT, "can't keep password: %s", pam_strerror(pamh, retval)); gray_pam_delete(token); } else { *password = token; token = NULL; /* break link to password */ } } else { _pam_log(LOG_ERR, "unable to obtain a password: %s", pam_strerror(pamh, retval)); } DEBUG(90,("exit _pam_get_password: %d", retval)); return retval; }
PAM_EXTERN int pam_sm_authenticate (pam_handle_t * pamh, int flags, int argc, const char **argv) { int retval, *ret_data=NULL; int try_first_pass=0, use_first_pass=0; const char *user = NULL; const char *password = NULL; struct pam_conv *conv; struct pam_message *pmsg[1], msg[1]; struct pam_response *resp; int nargs = 1, i; ret_data = malloc(sizeof(int)); for (i=0; i<argc; i++) { if (strcmp(argv[i], "try_first_pass") == 0) try_first_pass = 1; else if (strcmp(argv[i], "use_first_pass") == 0) use_first_pass = 1; } retval = pam_get_user (pamh, &user, NULL); if (retval != PAM_SUCCESS) { DBG (("get user returned error: %s", pam_strerror (pamh, retval))); goto done; } DBG (("get user returned: %s", user)); if (ask_server(user, "test", SERVER_LINK) == CHK_UNKNOWN) { DBG(("User [%s] unknown: not going further", user)); retval = PAM_USER_UNKNOWN; goto done; } if (try_first_pass || use_first_pass) { retval = pam_get_item (pamh, PAM_AUTHTOK, (const void **) &password); if (retval != PAM_SUCCESS) { DBG (("get password returned error: %s", pam_strerror (pamh, retval))); goto done; } DBG (("get password returned: %s", password)); } if (use_first_pass && password == NULL) { DBG (("use_first_pass set and no password, giving up")); retval = PAM_AUTH_ERR; goto done; } if (password) { retval = ask_server(user, password, SERVER_LINK); switch(retval) { case CHK_OK: retval = PAM_SUCCESS; goto done; case CHK_UNKNOWN: retval = PAM_USER_UNKNOWN; goto done; default: password = NULL; } } retval = pam_get_item (pamh, PAM_CONV, (const void **) &conv); if (retval != PAM_SUCCESS) { DBG (("get conv returned error: %s", pam_strerror (pamh, retval))); goto done; } pmsg[0] = &msg[0]; msg[0].msg = _("Password: "******"conv returned error: %s", pam_strerror (pamh, retval))); goto done; } if (resp->resp == NULL) { DBG (("conv returned NULL passwd?")); goto done; } DBG (("conv returned: %s", resp->resp)); password = resp->resp; retval = ask_server(user, password, SERVER_LINK); DBG (("ask_server returned: %d", retval)); switch(retval) { case CHK_OK: retval = PAM_SUCCESS; break; case CHK_UNKNOWN: retval = PAM_USER_UNKNOWN; break; default: retval = PAM_AUTH_ERR; } done: *ret_data = retval; pam_set_data(pamh, "yubikey_setcred_return", (void *) ret_data, setcred_free); DBG (("done. [%s]", pam_strerror (pamh, retval))); return retval; }
/* Initiate session management by creating Xauthority file. */ int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; int pamret; int n; const char *user; struct passwd *pw; char xauth[MAXBUF]; char envput[MAXBUF]; const char *dir = "/tmp"; int xauth_fd; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; else if (strncmp(argv[i], "dir=", 4) == 0) dir = argv[i] + 4; } if ((pamret = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { syslog(LOG_ERR, "pam_athena-locker: pam_get_user: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } errno = 0; pw = getpwnam(user); if (pw == NULL) { if (errno != 0) syslog(LOG_ERR, "pam_xauthority: getpwnam: %s", strerror(errno)); else syslog(LOG_ERR, "pam_xauthority: no such user: %s", user); return PAM_SESSION_ERR; } n = snprintf(xauth, MAXBUF, "%s/xauth-%d-XXXXXX", dir, pw->pw_uid); if (n < 0 || n >= MAXBUF) { syslog(LOG_ERR, "pam_xauthority: snprintf failed"); return PAM_SESSION_ERR; } xauth_fd = mkstemp(xauth); if (xauth_fd == -1) { syslog(LOG_ERR, "pam_xauthority: mkstemp: %s", strerror(errno)); return PAM_SESSION_ERR; } if (fchown(xauth_fd, pw->pw_uid, -1) != 0) { syslog(LOG_ERR, "pam_xauthority: fchown: %s", strerror(errno)); return PAM_SESSION_ERR; } if (close(xauth_fd) != 0) { syslog(LOG_ERR, "pam_xauthority: close: %s", strerror(errno)); return PAM_SESSION_ERR; } if (debug) syslog(LOG_DEBUG, "pam_xauthority: using Xauthority file %s", xauth); n = snprintf(envput, MAXBUF, "%s=%s", XAUTH, xauth); if (n < 0 || n >= MAXBUF) { syslog(LOG_ERR, "pam_xauthority: snprintf failed"); return PAM_SESSION_ERR; } pamret = pam_putenv(pamh, envput); if (pamret != PAM_SUCCESS) { syslog(LOG_ERR, "pam_xauthority: pam_putenv: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } pamret = pam_set_data(pamh, XAUTH, xauth, xauth_cleanup); if (pamret != PAM_SUCCESS) { syslog(LOG_ERR, "pam_xauthority: pam_set_data: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } return PAM_SUCCESS; }
PAM_EXTERN int pam_sm_authenticate (pam_handle_t *ph, int unused, int argc, const char **argv) { struct passwd *pwd; const char *user, *password; const char *control; int started_daemon; uint args; int ret; args = parse_args (ph, argc, argv); if (args & ARG_IGNORE_SERVICE) return PAM_SUCCESS; /* Figure out and/or prompt for 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"); return PAM_SERVICE_ERR; } /* Look up the password */ ret = pam_get_item (ph, PAM_AUTHTOK, (const void**)&password); if (ret != PAM_SUCCESS || password == NULL) { if (ret == PAM_SUCCESS) syslog (GKR_LOG_WARN, "gkr-pam: no password is available for user"); else syslog (GKR_LOG_WARN, "gkr-pam: no password is available for user: %s", pam_strerror (ph, ret)); return PAM_SUCCESS; } 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; } control = get_any_env (ph, ENV_CONTROL); /* If mate keyring is running, then unlock now */ if (control) { /* If we started the daemon, its already unlocked, since we passed the password */ if (!started_daemon) { ret = unlock_keyring (ph, pwd, password); if (ret != PAM_SUCCESS) return ret; } /* Otherwise start later in open session, store password */ } else { if (pam_set_data (ph, "gkr_system_authtok", strdup (password), cleanup_free_password) != PAM_SUCCESS) { syslog (GKR_LOG_ERR, "gkr-pam: error storing authtok"); return PAM_AUTHTOK_RECOVER_ERR; } } return PAM_SUCCESS; }
PAM_EXTERN int pam_sm_authenticate (pam_handle_t * pamh, int flags, int argc, const char **argv) { int retval, rc; const char *user = NULL; const char *password = NULL; char otp[MAX_TOKEN_ID_LEN + TOKEN_OTP_LEN + 1] = { 0 }; char otp_id[MAX_TOKEN_ID_LEN + 1] = { 0 }; int password_len = 0; int skip_bytes = 0; int valid_token = 0; struct pam_conv *conv; struct pam_message *pmsg[1], msg[1]; struct pam_response *resp; int nargs = 1; ykclient_t *ykc = NULL; struct cfg cfg_st; struct cfg *cfg = &cfg_st; /* for DBG macro */ parse_cfg (flags, argc, argv, cfg); retval = pam_get_user (pamh, &user, NULL); if (retval != PAM_SUCCESS) { DBG (("get user returned error: %s", pam_strerror (pamh, retval))); goto done; } DBG (("get user returned: %s", user)); if (cfg->mode == CHRESP) { #if HAVE_LIBYKPERS_1 return do_challenge_response(pamh, cfg, user); #else DBG (("no support for challenge/response")); retval = PAM_AUTH_ERR; goto done; #endif } if (cfg->try_first_pass || cfg->use_first_pass) { retval = pam_get_item (pamh, PAM_AUTHTOK, (const void **) &password); if (retval != PAM_SUCCESS) { DBG (("get password returned error: %s", pam_strerror (pamh, retval))); goto done; } DBG (("get password returned: %s", password)); } if (cfg->use_first_pass && password == NULL) { DBG (("use_first_pass set and no password, giving up")); retval = PAM_AUTH_ERR; goto done; } rc = ykclient_init (&ykc); if (rc != YKCLIENT_OK) { DBG (("ykclient_init() failed (%d): %s", rc, ykclient_strerror (rc))); retval = PAM_AUTHINFO_UNAVAIL; goto done; } rc = ykclient_set_client_b64 (ykc, cfg->client_id, cfg->client_key); if (rc != YKCLIENT_OK) { DBG (("ykclient_set_client_b64() failed (%d): %s", rc, ykclient_strerror (rc))); retval = PAM_AUTHINFO_UNAVAIL; goto done; } if (cfg->capath) ykclient_set_ca_path (ykc, cfg->capath); if (cfg->url) ykclient_set_url_template (ykc, cfg->url); if (password == NULL) { retval = pam_get_item (pamh, PAM_CONV, (const void **) &conv); if (retval != PAM_SUCCESS) { DBG (("get conv returned error: %s", pam_strerror (pamh, retval))); goto done; } pmsg[0] = &msg[0]; { const char *query_template = "Yubikey for `%s': "; size_t len = strlen (query_template) + strlen (user); size_t wrote; msg[0].msg = malloc (len); if (!msg[0].msg) { retval = PAM_BUF_ERR; goto done; } wrote = snprintf ((char *) msg[0].msg, len, query_template, user); if (wrote < 0 || wrote >= len) { retval = PAM_BUF_ERR; goto done; } } msg[0].msg_style = cfg->verbose_otp ? PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF; resp = NULL; retval = conv->conv (nargs, (const struct pam_message **) pmsg, &resp, conv->appdata_ptr); free ((char *) msg[0].msg); if (retval != PAM_SUCCESS) { DBG (("conv returned error: %s", pam_strerror (pamh, retval))); goto done; } if (resp->resp == NULL) { DBG (("conv returned NULL passwd?")); goto done; } DBG (("conv returned %i bytes", strlen(resp->resp))); password = resp->resp; } password_len = strlen (password); if (password_len < (cfg->token_id_length + TOKEN_OTP_LEN)) { DBG (("OTP too short to be considered : %i < %i", password_len, (cfg->token_id_length + TOKEN_OTP_LEN))); retval = PAM_AUTH_ERR; goto done; } /* In case the input was systempassword+YubiKeyOTP, we want to skip over "systempassword" when copying the token_id and OTP to separate buffers */ skip_bytes = password_len - (cfg->token_id_length + TOKEN_OTP_LEN); DBG (("Skipping first %i bytes. Length is %i, token_id set to %i and token OTP always %i.", skip_bytes, password_len, cfg->token_id_length, TOKEN_OTP_LEN)); /* Copy full YubiKey output (public ID + OTP) into otp */ strncpy (otp, password + skip_bytes, sizeof (otp) - 1); /* Copy only public ID into otp_id. Destination buffer is zeroed. */ strncpy (otp_id, password + skip_bytes, cfg->token_id_length); DBG (("OTP: %s ID: %s ", otp, otp_id)); /* user entered their system password followed by generated OTP? */ if (password_len > TOKEN_OTP_LEN + cfg->token_id_length) { char *onlypasswd = strdup (password); onlypasswd[password_len - (TOKEN_OTP_LEN + cfg->token_id_length)] = '\0'; DBG (("Extracted a probable system password entered before the OTP - " "setting item PAM_AUTHTOK")); retval = pam_set_item (pamh, PAM_AUTHTOK, onlypasswd); free (onlypasswd); if (retval != PAM_SUCCESS) { DBG (("set_item returned error: %s", pam_strerror (pamh, retval))); goto done; } } else password = NULL; rc = ykclient_request (ykc, otp); DBG (("ykclient return value (%d): %s", rc, ykclient_strerror (rc))); switch (rc) { case YKCLIENT_OK: break; case YKCLIENT_BAD_OTP: case YKCLIENT_REPLAYED_OTP: retval = PAM_AUTH_ERR; goto done; default: retval = PAM_AUTHINFO_UNAVAIL; goto done; } /* authorize the user with supplied token id */ if (cfg->ldapserver != NULL || cfg->ldap_uri != NULL) valid_token = authorize_user_token_ldap (cfg, user, otp_id); else valid_token = authorize_user_token (cfg, user, otp_id); if (valid_token == 0) { DBG (("Yubikey not authorized to login as user")); retval = PAM_AUTHINFO_UNAVAIL; goto done; } retval = PAM_SUCCESS; done: if (ykc) ykclient_done (&ykc); if (cfg->alwaysok && retval != PAM_SUCCESS) { DBG (("alwaysok needed (otherwise return with %d)", retval)); retval = PAM_SUCCESS; } DBG (("done. [%s]", pam_strerror (pamh, retval))); pam_set_data (pamh, "yubico_setcred_return", (void*) (intptr_t) retval, NULL); return retval; }
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_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv) { const char *user = NULL, *passwd = NULL; struct passwd *pwd; int rval, status; pid_t pid; // For checking mount paths: (mount from + target) char path[PATH_MAX]; char targetpath[PATH_MAX]; char encfs_options[USERNAME_MAX]; char fuse_options[USERNAME_MAX]; char *targetpath_store; strcpy(default_encfs_options, ""); strcpy(default_fuse_options, ""); // For execing: char *arg[USERNAME_MAX]; int arg_pos = 0; int i; int inpipe[2], outpipe[2]; rval = pam_get_user(pamh, &user, NULL); if ((rval != PAM_SUCCESS) || (!user)) { _pam_log(LOG_ERR, "can't get username: %s", pam_strerror(pamh, rval)); return PAM_AUTH_ERR; } rval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) (void *) &passwd); if (rval != PAM_SUCCESS) { _pam_log(LOG_ERR, "Could not retrieve user's password"); return PAM_AUTH_ERR; } if (!passwd) { rval = _set_auth_tok(pamh, flags, argc, argv); if (rval != PAM_SUCCESS) { return rval; } rval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) (void *) &passwd); if (rval != PAM_SUCCESS || passwd == NULL) { _pam_log(LOG_ERR, "Could not retrieve user's password"); return PAM_AUTH_ERR; } } if ((pwd = getpwnam(user)) == NULL) { _pam_log(LOG_ERR, "Could not getpwnam"); return PAM_AUTH_ERR; } // Read configfile if (!readconfig (pwd, pamh, pwd->pw_name, path, targetpath, encfs_options, fuse_options)) { // DEBUG _pam_log(LOG_ERR,"No entry for user found in log"); return PAM_IGNORE; } //DEBUG _pam_log(LOG_ERR,"Username : %s, Encpath : %s, Targetmount : %s",pwd->pw_name,path,targetpath); //Store targetpath targetpath_store = strdup(targetpath); if ((i = pam_set_data(pamh, "encfs_targetpath", targetpath_store, targetpath_cleanup)) != PAM_SUCCESS) { _pam_log(LOG_ERR, "Storing targetpath FAIL"); free(targetpath_store); return i; } // Check if we're mounted already. if (checkmnt(targetpath)) { //DEBUG _pam_log(LOG_ERR,"Already mounted"); return PAM_IGNORE; } /* _pam_log(LOG_ERR,"Config output for %s:",user); _pam_log(LOG_ERR," path : %s",path); _pam_log(LOG_ERR," targetpath : %s",targetpath); _pam_log(LOG_ERR," encfs : %s %s",default_encfs_options,encfs_options); _pam_log(LOG_ERR," fuse : %s %s",default_fuse_options,fuse_options); */ arg_pos += buildCmd(arg, arg_pos, "encfs"); arg_pos += buildCmd(arg, arg_pos, "-S"); arg_pos += buildCmd(arg, arg_pos, default_encfs_options); arg_pos += buildCmd(arg, arg_pos, encfs_options); arg_pos += buildCmd(arg, arg_pos, path); arg_pos += buildCmd(arg, arg_pos, targetpath); if (strlen(default_fuse_options) > 0 && strlen(fuse_options) > 0) strcat(fuse_options, ","); strcat(fuse_options,default_fuse_options); if (strlen(fuse_options) > 0) { arg_pos += buildCmd(arg, arg_pos, "--"); arg_pos += buildCmd(arg, arg_pos, "-o"); arg_pos += buildCmd(arg, arg_pos, fuse_options); } arg[arg_pos] = NULL; /* printf("Arguments : "); for (i = 0; i < arg_pos+1;i++) { _pam_log(LOG_ERR,"Data : %s",arg[i]); } _pam_log(LOG_ERR,"Number of arguments : %d",arg_pos); */ /* arg[0] = cmd; arg[1] = params; // arg[2] = params2; arg[2] = params3; arg[3] = path; arg[4] = targetpath; arg[5] = fuseparams; arg[6] = fuseparams2; arg[7] = NULL; */ if (pipe(inpipe) || pipe(outpipe)) { _pam_log(LOG_ERR, "Failed to create pipe"); return PAM_IGNORE; } // Execute switch (pid = fork()) { case -1: _pam_log(LOG_ERR, "Fork failed"); return PAM_SERVICE_ERR; case 0: if (drop_permissions == 1) if ((initgroups(pwd->pw_name, pwd->pw_gid) == -1) || (setgid(pwd->pw_gid) == -1) || (setuid(pwd->pw_uid) == -1)) { _pam_log(LOG_ERR, "Dropping permissions failed"); return PAM_SERVICE_ERR; } close(outpipe[WRITE_END]); dup2(outpipe[READ_END], fileno(stdin)); close(outpipe[READ_END]); close(inpipe[READ_END]); dup2(inpipe[WRITE_END], fileno(stdout)); close(inpipe[WRITE_END]); // For some reason the current directory has to be set to targetpath (or path?) before exec'ing encfs through gdm chdir(targetpath); execvp("encfs", arg); char errstr[128]; snprintf(errstr, 127, "%d - %s", errno, strerror(errno)); _pam_log(LOG_ERR, "Exec failed - %s", errstr); exit(127); } int len; close(inpipe[WRITE_END]); close(outpipe[READ_END]); if (waitpid(pid, &status, WNOHANG) == 0) { len = write(outpipe[WRITE_END], passwd, (size_t) strlen(passwd)); if ((len != (size_t) strlen(passwd)) || (write(outpipe[WRITE_END], "\n", 1) != 1)) _pam_log(LOG_ERR, "Did not send password to pipe (%d sent)", len); close(outpipe[WRITE_END]); } if (waitpid_timeout(pid, &status, 0)) { _pam_log(LOG_ERR, "Timed out waiting for encfs, killing\n"); kill(pid, SIGKILL); } int exitstatus = WEXITSTATUS(status); char buff[512]; len = read(inpipe[READ_END], &buff, 511); close(inpipe[READ_END]); buff[len] = 0; if (!checkmnt(targetpath) && (len > 0 || exitstatus > 0)) { _pam_log(LOG_ERR, "exitcode : %d, errorstring : %s", exitstatus, buff); return PAM_AUTH_ERR; } else { return PAM_IGNORE; } return PAM_AUTH_ERR; }
/* Initiate session management by creating temporary file. */ int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; int pamret; int n; const char *user; struct passwd *pw; char mktemp_buf[MAXBUF]; char envput[MAXBUF]; const char *prefix = "/tmp/tempfile"; const char *var = NULL; int fd; int dir = 0; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; else if (strncmp(argv[i], "prefix=", 7) == 0) prefix = argv[i] + 7; else if (strncmp(argv[i], "var=", 4) == 0) var = argv[i] + 4; else if (strcmp(argv[i], "dir") == 0) dir = 1; } if (var == NULL) { syslog(LOG_ERR, "pam_mktemp: No variable to set"); return PAM_SESSION_ERR; } if ((pamret = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { syslog(LOG_ERR, "pam_mktemp: pam_get_user: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } errno = 0; pw = getpwnam(user); if (pw == NULL) { if (errno != 0) syslog(LOG_ERR, "pam_mktemp: getpwnam: %m"); else syslog(LOG_ERR, "pam_mktemp: no such user: %s", user); return PAM_SESSION_ERR; } n = snprintf(mktemp_buf, MAXBUF, "%s-%d-XXXXXX", prefix, pw->pw_uid); if (n < 0 || n >= MAXBUF) { syslog(LOG_ERR, "pam_mktemp: snprintf failed"); return PAM_SESSION_ERR; } if (dir) { if (mkdtemp(mktemp_buf) == NULL) { syslog(LOG_ERR, "pam_mktemp: mkdtemp: %m"); return PAM_SESSION_ERR; } } else { fd = mkstemp(mktemp_buf); if (fd == -1) { syslog(LOG_ERR, "pam_mktemp: mkstemp: %m"); return PAM_SESSION_ERR; } if (close(fd) != 0) { syslog(LOG_ERR, "pam_mktemp: close: %m"); return PAM_SESSION_ERR; } } if (chown(mktemp_buf, pw->pw_uid, -1) != 0) { syslog(LOG_ERR, "pam_mktemp: chown: %m"); return PAM_SESSION_ERR; } if (debug) syslog(LOG_DEBUG, "pam_mktemp: using temporary file %s", mktemp_buf); n = snprintf(envput, MAXBUF, "%s=%s", var, mktemp_buf); if (n < 0 || n >= MAXBUF) { syslog(LOG_ERR, "pam_mktemp: snprintf failed"); return PAM_SESSION_ERR; } pamret = pam_putenv(pamh, envput); if (pamret != PAM_SUCCESS) { syslog(LOG_ERR, "pam_mktemp: pam_putenv: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } pamret = pam_set_data(pamh, var, mktemp_buf, mktemp_cleanup); if (pamret != PAM_SUCCESS) { syslog(LOG_ERR, "pam_mktemp: pam_set_data: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } return PAM_SUCCESS; }
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; }
int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int status, confFlags = 0; char hostNameBufBuf[5 + MAXHOSTNAMELEN + 1] = "host@"; int isConvPasswordBuf = 0; OM_uint32 major, minor; gss_buffer_desc userNameBuf = GSS_C_EMPTY_BUFFER; gss_buffer_desc hostNameBuf = GSS_C_EMPTY_BUFFER; gss_buffer_desc passwordBuf = GSS_C_EMPTY_BUFFER; gss_name_t userName = GSS_C_NO_NAME; gss_name_t hostName = GSS_C_NO_NAME; gss_cred_id_t initiatorCred = GSS_C_NO_CREDENTIAL; gss_cred_id_t acceptorCred = GSS_C_NO_CREDENTIAL; gss_OID mech = &gss_spnego_mechanism_oid_desc; gss_OID_set_desc mechOids; confFlags = readConfFlags(argc, argv); status = readConfMechOid(argc, argv, &mech); BAIL_ON_PAM_ERROR(status); if (flags & PAM_DISALLOW_NULL_AUTHTOK) confFlags &= ~(FLAG_NULLOK); status = pam_get_user(pamh, (void *)&userNameBuf.value, NULL); BAIL_ON_PAM_ERROR(status); userNameBuf.length = strlen((char *)userNameBuf.value); major = gss_import_name(&minor, &userNameBuf, GSS_C_NT_USER_NAME, &userName); BAIL_ON_GSS_ERROR(major, minor); if (gethostname(&hostNameBufBuf[5], MAXHOSTNAMELEN) != 0) { status = PAM_SYSTEM_ERR; goto cleanup; } hostNameBuf.length = strlen(hostNameBufBuf); hostNameBuf.value = hostNameBufBuf; major = gss_import_name(&minor, &hostNameBuf, GSS_C_NT_HOSTBASED_SERVICE, &hostName); BAIL_ON_GSS_ERROR(major, minor); mechOids.count = 1; mechOids.elements = mech; major = gss_acquire_cred(&minor, hostName, GSS_C_INDEFINITE, &mechOids, GSS_C_ACCEPT, &acceptorCred, NULL, NULL); BAIL_ON_GSS_ERROR(major, minor); status = PAM_AUTHINFO_UNAVAIL; if (confFlags & (FLAG_USE_FIRST_PASS | FLAG_TRY_FIRST_PASS)) { status = pam_get_item(pamh, PAM_AUTHTOK, (void *)&passwordBuf.value); BAIL_ON_PAM_ERROR(status); if (passwordBuf.value != NULL) passwordBuf.length = strlen((char *)passwordBuf.value); status = pamGssAcquireCred(pamh, confFlags, userName, &passwordBuf, mech, &initiatorCred); if (status == PAM_SUCCESS) status = pamGssInitAcceptSecContext(pamh, confFlags, initiatorCred, acceptorCred, hostName, mech); if (confFlags & FLAG_USE_FIRST_PASS) BAIL_ON_PAM_ERROR(status); } if (status != PAM_SUCCESS) { isConvPasswordBuf = 1; if (flags & PAM_SILENT) goto cleanup; status = pamGssGetAuthTok(pamh, confFlags, &passwordBuf); BAIL_ON_PAM_ERROR(status); gss_release_cred(&minor, &initiatorCred); status = pamGssAcquireCred(pamh, confFlags, userName, &passwordBuf, mech, &initiatorCred); if (status == PAM_SUCCESS) status = pamGssInitAcceptSecContext(pamh, confFlags, initiatorCred, acceptorCred, hostName, mech); BAIL_ON_PAM_ERROR(status); } status = pam_set_data(pamh, GSS_CRED_DATA, initiatorCred, pamGssCleanupCred); BAIL_ON_PAM_ERROR(status); initiatorCred = GSS_C_NO_CREDENTIAL; cleanup: gss_release_name(&minor, &userName); gss_release_name(&minor, &hostName); gss_release_cred(&minor, &initiatorCred); gss_release_cred(&minor, &acceptorCred); #ifdef __APPLE__ if (mech != &gss_spnego_mechanism_oid_desc) gss_release_oid(&minor, &mech); #endif if (isConvPasswordBuf) { memset((char *)passwordBuf.value, 0, passwordBuf.length); free(passwordBuf.value); } return status; }
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { const char *user; char *password, *crypt_password, *cached_password; int pam_err, timestamp; /* identify user */ if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) return (pam_err); if (getpwnam(user) == NULL) return (PAM_USER_UNKNOWN); /* get password */ pam_err = pam_get_authtok(pamh, PAM_AUTHTOK, (const char **)&password, NULL); if (pam_err == PAM_CONV_ERR) return (pam_err); if (pam_err != PAM_SUCCESS) return (PAM_AUTH_ERR); cached_password = NULL; if (!read_ticket(user, ×tamp, &cached_password)) { pam_err = PAM_AUTH_ERR; if (crypt_set_format("sha512")) crypt_password = crypt(password, gen_salt()); else crypt_password = NULL; goto done; } if ((crypt_password = crypt(password, cached_password)) != NULL && strcmp(crypt_password, cached_password) == 0) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); /* TODO: timeout should be an argument! */ if ((int)now.tv_sec > timestamp + TIMEOUT) { openpam_log(PAM_LOG_DEBUG, "expired auth ticket: %d > %d", (int)now.tv_sec, timestamp + TIMEOUT); pam_err = PAM_AUTH_ERR; } else { pam_err = PAM_SUCCESS; } } else { openpam_log(PAM_LOG_DEBUG, "passwords do not match"); pam_err = PAM_AUTH_ERR; } done: if (crypt_password != NULL) { char *cp; size_t len; len = strlen(crypt_password) + 1; if ((cp = calloc(len, sizeof(char))) != NULL && strlcpy(cp, crypt_password, len) < len) pam_set_data(pamh, "pam_auth_ticket", cp, cleanup); } free(cached_password); return (pam_err); }
static int pamGssInitAcceptSecContext(pam_handle_t *pamh, int confFlags, gss_cred_id_t cred, gss_cred_id_t acceptorCred, gss_name_t hostName, gss_OID mech) { int status; OM_uint32 major, minor; gss_buffer_desc initiatorToken = GSS_C_EMPTY_BUFFER; gss_buffer_desc acceptorToken = GSS_C_EMPTY_BUFFER; gss_ctx_id_t initiatorContext = GSS_C_NO_CONTEXT; gss_ctx_id_t acceptorContext = GSS_C_NO_CONTEXT; gss_buffer_desc canonUserNameBuf = GSS_C_EMPTY_BUFFER; gss_name_t canonUserName = GSS_C_NO_NAME; gss_OID canonMech = GSS_C_NO_OID; OM_uint32 gssFlags; do { major = gss_init_sec_context(&minor, cred, &initiatorContext, hostName, mech, GSS_C_MUTUAL_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &acceptorToken, NULL, &initiatorToken, &gssFlags, NULL); gss_release_buffer(&minor, &acceptorToken); #ifdef GSS_S_PROMPTING_NEEDED if (major == GSS_S_PROMPTING_NEEDED) { status = PAM_CRED_INSUFFICIENT; goto cleanup; } #endif BAIL_ON_GSS_ERROR(major, minor); if (initiatorToken.length != 0) { major = gss_accept_sec_context(&minor, &acceptorContext, acceptorCred, &initiatorToken, GSS_C_NO_CHANNEL_BINDINGS, &canonUserName, &canonMech, &acceptorToken, NULL, NULL, NULL); gss_release_buffer(&minor, &initiatorToken); } BAIL_ON_GSS_ERROR(major, minor); } while (major == GSS_S_CONTINUE_NEEDED); BAIL_ON_GSS_ERROR(major, minor); if ((gssFlags & GSS_C_MUTUAL_FLAG) == 0) { status = PAM_PERM_DENIED; goto cleanup; } #ifndef __APPLE__ major = gss_localname(&minor, canonUserName, GSS_C_NO_OID, &canonUserNameBuf); if (major == GSS_S_COMPLETE) { status = pam_set_item(pamh, PAM_USER, canonUserNameBuf.value); BAIL_ON_PAM_ERROR(status); } else if (major != GSS_S_UNAVAILABLE) goto cleanup; #endif status = pam_set_data(pamh, GSS_NAME_DATA, canonUserName, pamGssCleanupName); BAIL_ON_PAM_ERROR(status); canonUserName = GSS_C_NO_NAME; status = pam_set_data(pamh, GSS_MECH_DATA, canonMech, pamGssCleanupMech); BAIL_ON_PAM_ERROR(status); canonMech = GSS_C_NO_OID; status = PAM_SUCCESS; cleanup: gss_release_name(&minor, &canonUserName); gss_release_buffer(&minor, &initiatorToken); gss_release_buffer(&minor, &acceptorToken); gss_delete_sec_context(&minor, &initiatorContext, NULL); gss_delete_sec_context(&minor, &acceptorContext, NULL); gss_release_buffer(&minor, &canonUserNameBuf); if (IGNORE_ERR_P(status, confFlags)) status = PAM_IGNORE; return status; }
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; }
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_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { return pam_set_data(pamh, DATA_NAME, NULL, cleanup); }
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { abl_args *args; abl_info *info; abl_context *context; DB *utdb; DB *usdb; DB *htdb; DB *hsdb; int err = PAM_SUCCESS; /*log_debug(args, "pam_sm_authenticate(), flags=%08x", flags);*/ if (args = malloc(sizeof(abl_args)), NULL == args) { return PAM_BUF_ERR; } if (info = malloc(sizeof(abl_info)), NULL == info) { return PAM_BUF_ERR; } if (context = malloc(sizeof(abl_context)), NULL == context) { return PAM_BUF_ERR; } memset(info,0,sizeof(abl_info)); memset(context,0,sizeof(abl_context)); if (err = config_parse_args(pamh, argc, argv, args), PAM_SUCCESS == err) { /* We now keep the database open from the beginning to avoid the cost * of opening them repeatedly. */ err = dbopen(args, args->user_db, DB_TIME, &utdb); if (err) goto psa_fail; info->utdb = utdb; err = dbopen(args, args->user_db, DB_STATE, &usdb); if (err) goto psa_fail; info->usdb = usdb; err = dbopen(args, args->host_db, DB_TIME, &htdb); if (err) goto psa_fail; info->htdb = htdb; err = dbopen(args, args->host_db, DB_STATE, &hsdb); if (err) goto psa_fail; info->hsdb = hsdb; context->args = args; context->info = info; if (err = pam_set_data(pamh, DATA_NAME, context, cleanup), PAM_SUCCESS != err) { log_pam_error(args,err,"setting PAM data"); goto psa_fail; } if (err = pam_get_item(args->pamh, PAM_USER, (const void **) &info->user), PAM_SUCCESS != err) { log_pam_error(args, err, "getting PAM_USER"); goto psa_fail; } if (err = pam_get_item(args->pamh, PAM_SERVICE, (const void **) &info->service), PAM_SUCCESS != err) { log_pam_error(args, err, "getting PAM_SERVICE"); goto psa_fail; } if (err = pam_get_item(args->pamh, PAM_RHOST, (const void **) &info->host), PAM_SUCCESS != err) { log_pam_error(args, err, "getting PAM_RHOST"); goto psa_fail; } check_attempt(args, info); if (info->state == BLOCKED) { log_info("Blocking access from %s to service %s, user %s", info->host, info->service, info->user); return PAM_AUTH_ERR; } else { return PAM_SUCCESS; } } psa_fail: config_free(args); utdb->close(utdb,0); usdb->close(usdb,0); htdb->close(htdb,0); hsdb->close(hsdb,0); free(args); free(info); free(context); return err; }
int main(int argc, char **argv) { char hostname[MAXHOSTNAMELEN]; struct passwd *pwd = NULL; int o, pam_err; uid_t uid; while ((o = getopt(argc, argv, "d:h:loy")) != -1) switch (o) { case 'd': yp_domain = optarg; break; case 'h': yp_host = optarg; break; case 'l': case 'o': case 'y': /* compatibility */ break; default: usage(); } argc -= optind; argv += optind; uid = getuid(); switch (argc) { case 0: if ((pwd = getpwuid(uid)) == NULL) errx(1, "who are you?"); break; case 1: if ((pwd = getpwnam(*argv)) == NULL) errx(1, "%s: no such user", *argv); break; default: usage(); } if (uid != 0 && uid != pwd->pw_uid) errx(1, "permission denied"); /* check where the user's from */ switch (pwd->pw_fields & _PWF_SOURCE) { case _PWF_FILES: fprintf(stderr, "Changing local password for %s\n", pwd->pw_name); break; case _PWF_NIS: fprintf(stderr, "Changing NIS password for %s\n", pwd->pw_name); break; default: fprintf(stderr, "Changing password for %s\n", pwd->pw_name); } #define pam_check(func) do { \ if (pam_err != PAM_SUCCESS) { \ if (pam_err == PAM_AUTH_ERR || pam_err == PAM_PERM_DENIED || \ pam_err == PAM_AUTHTOK_RECOVERY_ERR) \ warnx("sorry"); \ else \ warnx("%s(): %s", func, pam_strerror(pamh, pam_err)); \ goto end; \ } \ } while (0) /* initialize PAM */ pam_err = pam_start("passwd", pwd->pw_name, &pamc, &pamh); pam_check("pam_start"); pam_err = pam_set_item(pamh, PAM_TTY, ttyname(STDERR_FILENO)); pam_check("pam_set_item"); gethostname(hostname, sizeof hostname); pam_err = pam_set_item(pamh, PAM_RHOST, hostname); pam_check("pam_set_item"); pam_err = pam_set_item(pamh, PAM_RUSER, getlogin()); pam_check("pam_set_item"); /* set YP domain and host */ pam_err = pam_set_data(pamh, "yp_domain", yp_domain, NULL); pam_check("pam_set_data"); pam_err = pam_set_data(pamh, "yp_server", yp_host, NULL); pam_check("pam_set_data"); /* set new password */ pam_err = pam_chauthtok(pamh, 0); pam_check("pam_chauthtok"); end: pam_end(pamh, pam_err); exit(pam_err == PAM_SUCCESS ? 0 : 1); }
extern int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv) { int retcode = PAM_SUCCESS; int errcode = PAM_SUCCESS; int code; int origmask; int logmask = LOG_UPTO(LOG_INFO); int nowarn = 0; int use_first_pass = 0; int try_first_pass = 0; int ignore_uid = 0; uid_t ignore_uid_id = 0; char my_password_buf[256]; char *cell_ptr = NULL; /* * these options are added to handle stupid apps, which won't call * pam_set_cred() */ int refresh_token = 0; int set_token = 0; int dont_fork = 0; /* satisfy kdm 2.x */ int use_klog = 0; int set_expires = 0; /* This option is only used in pam_set_cred() */ int got_authtok = 0; /* got PAM_AUTHTOK upon entry */ char *user = NULL, *password = NULL; afs_int32 password_expires = -1; int torch_password = 1; int i; struct pam_conv *pam_convp = NULL; int auth_ok; struct passwd unix_pwd, *upwd = NULL; char upwd_buf[2048]; /* size is a guess. */ char *reason = NULL; pid_t cpid, rcpid; int status; struct sigaction newAction, origAction; #ifndef AFS_SUN56_ENV openlog(pam_afs_ident, LOG_CONS | LOG_PID, 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; } 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 < 0) || (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], "refresh_token") == 0) { refresh_token = 1; } else if (strcasecmp(argv[i], "set_token") == 0) { set_token = 1; } else if (strcasecmp(argv[i], "dont_fork") == 0) { if (!use_klog) dont_fork = 1; else pam_afs_syslog(LOG_ERR, PAMAFS_CONFLICTOPT, "dont_fork"); } else if (strcasecmp(argv[i], "use_klog") == 0) { if (!dont_fork) use_klog = 1; else pam_afs_syslog(LOG_ERR, PAMAFS_CONFLICTOPT, "use_klog"); } else if (strcasecmp(argv[i], "setenv_password_expires") == 0) { set_expires = 1; } else { pam_afs_syslog(LOG_ERR, PAMAFS_UNKNOWNOPT, argv[i]); } } /* Later we use try_first_pass to see if we can try again. */ /* If use_first_pass is true we don't want to ever try again, */ /* so turn that flag off right now. */ 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, refresh_token, set_token, dont_fork, use_klog); /* Try to get the user-interaction info, if available. */ errcode = pam_get_item(pamh, PAM_CONV, (const void **)&pam_convp); if (errcode != PAM_SUCCESS) { pam_afs_syslog(LOG_WARNING, PAMAFS_NO_USER_INT); pam_convp = NULL; } /* Who are we trying to authenticate here? */ if ((errcode = pam_get_user(pamh, (const char **)&user, "login: "******"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) #if defined(AFS_HPUX110_ENV) || defined(AFS_DARWIN100_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 /* else AFS_HPUX110_ENV */ if (ignore_uid && i == 0 && 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); #elif defined(_POSIX_PTHREAD_SEMANTICS) && defined(AFS_SUN5_ENV) getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf), &upwd); #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 errcode = pam_get_item(pamh, PAM_AUTHTOK, (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. */ torch_password = 0; pam_afs_syslog(LOG_INFO, PAMAFS_NILPASSWORD, user); RET(PAM_NEW_AUTHTOK_REQD); } else { if (logmask && LOG_MASK(LOG_DEBUG)) pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user); torch_password = 0; got_authtok = 1; } if (!(use_first_pass || try_first_pass)) { password = NULL; } try_auth: if (password == NULL) { torch_password = 1; 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, &password, 0, PAMAFS_PWD_PROMPT); if (errcode != PAM_SUCCESS || password == NULL) { pam_afs_syslog(LOG_ERR, PAMAFS_GETPASS_FAILED); RET(PAM_AUTH_ERR); } if (password[0] == '\0') { pam_afs_syslog(LOG_INFO, PAMAFS_NILPASSWORD, user); 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, password, sizeof(my_password_buf)); my_password_buf[sizeof(my_password_buf) - 1] = '\0'; memset(password, 0, strlen(password)); free(password); password = my_password_buf; } /* Be sure to allocate a PAG here if we should set a token, * All of the remaining stuff to authenticate the user and to * get a token is done in a child process - if not suppressed by the config, * see below * But dont get a PAG if the refresh_token option was set * We have to do this in such a way because some * apps (such as screensavers) wont call setcred but authenticate :-( */ if (!refresh_token) { setpag(); #ifdef AFS_KERBEROS_ENV ktc_newpag(); #endif if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "New PAG created in pam_authenticate()"); } if (!dont_fork) { /* Prepare for fork(): set SIGCHLD signal handler to default */ sigemptyset(&newAction.sa_mask); newAction.sa_handler = SIG_DFL; newAction.sa_flags = 0; code = sigaction(SIGCHLD, &newAction, &origAction); if (code) { pam_afs_syslog(LOG_ERR, PAMAFS_PAMERROR, errno); RET(PAM_AUTH_ERR); } /* Fork a process and let it verify authentication. So that any * memory/sockets allocated will get cleaned up when the child * exits: defect 11686. */ if (use_klog) { /* used by kdm 2.x */ if (refresh_token || set_token) { i = do_klog(user, password, NULL, cell_ptr); } else { i = do_klog(user, password, "00:00:01", cell_ptr); ktc_ForgetAllTokens(); } if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "do_klog returned %d", i); auth_ok = i ? 0 : 1; } else { if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "forking ..."); cpid = fork(); if (cpid <= 0) { /* The child process */ if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "in child"); if (refresh_token || set_token) code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, user, /* kerberos name */ NULL, /* instance */ cell_ptr, /* realm */ password, /* password */ 0, /* default lifetime */ &password_expires, 0, /* spare 2 */ &reason /* error string */ ); else code = ka_VerifyUserPassword(KA_USERAUTH_VERSION, user, /* kerberos name */ NULL, /* instance */ cell_ptr, /* realm */ password, /* password */ 0, /* spare 2 */ &reason /* error string */ ); if (code) { pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user, reason); auth_ok = 0; } else { auth_ok = 1; } if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "child: auth_ok=%d", auth_ok); if (cpid == 0) exit(auth_ok); } else { do { if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "in parent, waiting ..."); rcpid = waitpid(cpid, &status, 0); } while ((rcpid == -1) && (errno == EINTR)); if ((rcpid == cpid) && WIFEXITED(status)) { auth_ok = WEXITSTATUS(status); } else { auth_ok = 0; } if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "parent: auth_ok=%d", auth_ok); } } /* Restore old signal handler */ code = sigaction(SIGCHLD, &origAction, NULL); if (code) { pam_afs_syslog(LOG_ERR, PAMAFS_PAMERROR, errno); } } else { /* dont_fork, used by httpd */ if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "dont_fork"); if (refresh_token || set_token) code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, user, /* kerberos name */ NULL, /* instance */ cell_ptr, /* realm */ password, /* password */ 0, /* default lifetime */ &password_expires, 0, /* spare 2 */ &reason /* error string */ ); else code = ka_VerifyUserPassword(KA_USERAUTH_VERSION, user, /* kerberos name */ NULL, /* instance */ cell_ptr, /* realm */ password, /* password */ 0, /* spare 2 */ &reason /* error string */ ); if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "dont_fork, code = %d", code); if (code) { pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user, reason); auth_ok = 0; } else { auth_ok = 1; } if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "dont_fork: auth_ok=%d", auth_ok); } if (!auth_ok && try_first_pass) { password = NULL; goto try_auth; } /* We don't care if this fails; all we can do is try. */ /* It is not reasonable to store the password only if it was correct * because it could satisfy another module that is called in the chain * after pam_afs */ if (!got_authtok) { torch_password = 0; (void)pam_set_item(pamh, PAM_AUTHTOK, password); } if (logmask && LOG_MASK(LOG_DEBUG)) syslog(LOG_DEBUG, "leaving auth: auth_ok=%d", auth_ok); if (code == KANOENT) RET(PAM_USER_UNKNOWN); RET(auth_ok ? PAM_SUCCESS : PAM_AUTH_ERR); out: if (password) { /* we store the password in the data portion */ char *tmp = strdup(password); (void)pam_set_data(pamh, pam_afs_lh, tmp, lc_cleanup); if (torch_password) memset(password, 0, strlen(password)); } (void)setlogmask(origmask); #ifndef AFS_SUN56_ENV closelog(); #endif return retcode; }