static int CommandProc(struct cmd_syndesc *as, void *arock) { #define MAXCELLS 20 /* XXX */ struct cmd_item *itp; afs_int32 code, i = 0; char *cells[20]; if (as->parms[0].items) { /* A cell is provided */ for (itp = as->parms[0].items; itp; itp = itp->next) { if (i > MAXCELLS) { printf ("The maximum number of cells (%d) is exceeded; the rest are ignored\n", MAXCELLS); break; } cells[i++] = itp->data; } code = unlog_ForgetCertainTokens(cells, i); } else code = ktc_ForgetAllTokens(); if (code) { printf("unlog: could not discard tickets, code %d\n", code); exit(1); } return 0; }
static int CommandProc (struct cmd_syndesc *as, void *arock) { afs_int32 code, ecode=0; struct ktc_principal server; struct cmd_item *itp; if (as->parms[0].items) { /* A cell is provided */ for (itp=as->parms[0].items; itp; itp = itp->next) { strcpy(server.cell, itp->data); server.instance[0] = '\0'; strcpy(server.name, "afs"); code = ktc_ForgetToken(&server); if (code) { printf("unlog: could not discard tickets for cell %s, code %d\n", itp->data, code); ecode = code; /* return last error */ } } } else { ecode = ktc_ForgetAllTokens (); if (ecode) printf("unlog: could not discard tickets, code %d\n", ecode); } return ecode; }
int Leash_afs_unlog( void ) { #ifdef NO_AFS return(0); #else long rc; char HostName[64]; DWORD CurrentState; if (!AfsAvailable || GetAfsStatus(&AfsOnLine) && !AfsOnLine) return(0); CurrentState = 0; memset(HostName, '\0', sizeof(HostName)); gethostname(HostName, sizeof(HostName)); if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) return(0); if (CurrentState != SERVICE_RUNNING) return(0); rc = ktc_ForgetAllTokens(); return(0); #endif }
/* * Build a list of tokens, delete the bad ones (the ones to remove from the * permissions list,) destroy all tokens, and then re-register the good ones. * Ugly, but it works. */ int uss_fs_UnlogToken(char *celln) { int count = 0, index, index2; afs_int32 code = 0, cnt = 0; struct ktc_principal serviceName; struct tokenInfo *tokenInfoP, *tp; do { code = ktc_ListTokens(count, &count, &serviceName); cnt++; } while (!code); count = cnt - 1; tokenInfoP = malloc((sizeof(struct tokenInfo) * count)); for (code = index = index2 = 0; (!code) && (index < count); index++) { tp = tokenInfoP + index; code = ktc_ListTokens(index2, &index2, &tp->service); if (!code) { code = ktc_GetToken(&tp->service, &tp->token, sizeof(struct ktc_token), &tp->client); if (!code) { tp->deleted = (!strcmp(celln, tp->client.cell) ? 1 : 0); if (tp->deleted) cnt = 1; } } } if ((code = ktc_ForgetAllTokens())) { printf("uss_fs_UnlogToken: could not discard tickets, code %d\n", code); exit(1); } for (code = index = 0; index < count; index++) { tp = tokenInfoP + index; if (!(tp->deleted)) { code = ktc_SetToken(&tp->service, &tp->token, &tp->client, 0); if (code) { printf ("uss_fs_UnlogToken: Couldn't re-register token, code = %d\n", code); } } } return 0; }
static int unlog_ForgetCertainTokens(char **list, int listSize) { int index, index2; int count; afs_int32 code; struct ktc_principal serviceName; struct tokenInfo *tokenInfoP; /* normalize all the names in the list */ unlog_NormalizeCellNames(list, listSize); /* figure out how many tokens exist */ count = 0; do { code = ktc_ListTokens(count, &count, &serviceName); } while (!code); tokenInfoP = (struct tokenInfo *)malloc((sizeof(struct tokenInfo) * count)); if (!tokenInfoP) { perror("unlog_ForgetCertainTokens -- osi_Alloc failed"); exit(1); } for (code = index = index2 = 0; (!code) && (index < count); index++) { code = ktc_ListTokens(index2, &index2, &(tokenInfoP + index)->service); if (!code) { code = ktc_GetToken(&(tokenInfoP + index)->service, &(tokenInfoP + index)->token, sizeof(struct ktc_token), &(tokenInfoP + index)->client); if (!code) (tokenInfoP + index)->deleted = unlog_CheckUnlogList(list, listSize, &(tokenInfoP + index)->client); } } unlog_VerifyUnlog(list, listSize, tokenInfoP, count); code = ktc_ForgetAllTokens(); if (code) { printf("unlog: could not discard tickets, code %d\n", code); exit(1); } for (code = index = 0; index < count; index++) { if (!((tokenInfoP + index)->deleted)) { code = ktc_SetToken(&(tokenInfoP + index)->service, &(tokenInfoP + index)->token, &(tokenInfoP + index)->client, 0); if (code) { fprintf(stderr, "Couldn't re-register token, code = %d\n", code); } } } return 0; }
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; }
void checkpw_cleanup (void *data) { ktc_ForgetAllTokens (); }
int main(void) { struct ktc_principal oldServer[MAXCELLS], newServer[MAXCELLS]; struct ktc_principal oldClient[MAXCELLS], newClient[MAXCELLS]; struct ktc_token oldToken[MAXCELLS], newToken[MAXCELLS]; int cellCount, cellIndex; int i, code; #ifdef AFS_NT40_ENV /* Initialize winsock; required by NT pioctl() */ if (afs_winsockInit()) { printf("\nUnable to initialize winsock (required by NT pioctl()).\n"); exit(1); } #endif /* Get original tokens */ printf("\nFetching original tokens.\n"); cellIndex = 0; for (i = 0; i < MAXCELLS; i++) { /* fetch server principal */ code = ktc_ListTokens(cellIndex, &cellIndex, &oldServer[i]); if (code) { if (code == KTC_NOENT) { /* no more tokens */ break; } else { /* some error occured */ perror("ktc_ListTokens failed fetching original tokens"); exit(1); } } /* fetch token and client identity w.r.t. server */ code = ktc_GetToken(&oldServer[i], &oldToken[i], sizeof(struct ktc_token), &oldClient[i]); if (code) { /* some unexpected error occured */ perror("ktc_GetToken failed fetching original tokens"); exit(1); } } cellCount = i; if (cellCount == 0) { printf("Obtain one or more tokens prior to executing test.\n"); exit(0); } else if (cellCount == MAXCELLS) { printf("Only first %d tokens utilized by test; rest will be lost.\n", MAXCELLS); } for (i = 0; i < cellCount; i++) { printf("Token[%d]: server = %s@%s, client = %s@%s\n", i, oldServer[i].name, oldServer[i].cell, oldClient[i].name, oldClient[i].cell); } /* Forget original tokens */ printf("\nClearing original tokens and verifying disposal.\n"); code = ktc_ForgetAllTokens(); if (code) { perror("ktc_ForgetAllTokens failed on original tokens"); exit(1); } for (i = 0; i < cellCount; i++) { struct ktc_principal dummyPrincipal; struct ktc_token dummyToken; code = ktc_GetToken(&oldServer[i], &dummyToken, sizeof(struct ktc_token), &dummyPrincipal); if (code != KTC_NOENT) { printf("ktc_ForgetAllTokens did not eliminate all tokens.\n"); exit(1); } cellIndex = 0; code = ktc_ListTokens(cellIndex, &cellIndex, &dummyPrincipal); if (code != KTC_NOENT) { printf("ktc_ForgetAllTokens did not eliminate all tokens.\n"); exit(1); } } /* Reinstall tokens */ printf("\nReinstalling original tokens.\n"); for (i = 0; i < cellCount; i++) { code = ktc_SetToken(&oldServer[i], &oldToken[i], &oldClient[i], 0); if (code) { perror("ktc_SetToken failed reinstalling tokens"); exit(1); } } /* Get reinstalled tokens */ printf("\nFetching reinstalled tokens.\n"); cellIndex = 0; for (i = 0; i < MAXCELLS; i++) { /* fetch server principal */ code = ktc_ListTokens(cellIndex, &cellIndex, &newServer[i]); if (code) { if (code == KTC_NOENT) { /* no more tokens */ break; } else { /* some error occured */ perror("ktc_ListTokens failed fetching reinstalled tokens"); exit(1); } } /* fetch token and client identity w.r.t. server */ code = ktc_GetToken(&newServer[i], &newToken[i], sizeof(struct ktc_token), &newClient[i]); if (code) { /* some unexpected error occured */ perror("ktc_GetToken failed fetching reinstalled tokens"); exit(1); } } /* Verify content of reinstalled tokens */ printf("\nVerifying reinstalled tokens against original tokens.\n"); if (i != cellCount) { printf("Reinstalled token count does not match original count.\n"); exit(1); } for (i = 0; i < cellCount; i++) { int k, found; found = 0; for (k = 0; k < cellCount; k++) { if (SamePrincipal(&oldServer[i], &newServer[k]) && SamePrincipal(&oldClient[i], &newClient[k]) && SameToken(&oldToken[i], &newToken[k])) { /* found a matching token */ found = 1; break; } } if (!found) { printf("Reinstalled token does not match any original token.\n"); exit(1); } } /* Test passes */ printf("\nTest completed without error.\n"); return 0; }
VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo ) { DWORD code; TCHAR profileDir[1024] = TEXT(""); DWORD len = 1024; PTOKEN_USER tokenUser = NULL; DWORD retLen; DWORD LSPtype, LSPsize; HKEY NPKey; DWORD LogoffPreserveTokens = 0; LogonOptions_t opt; /* Make sure the AFS Libraries are initialized */ AfsLogonInit(); DebugEvent0("AFS_Logoff_Event - Start"); (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_QUERY_VALUE, &NPKey); LSPsize=sizeof(LogoffPreserveTokens); RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL, &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize); RegCloseKey (NPKey); if (!LogoffPreserveTokens) { memset(&opt, 0, sizeof(LogonOptions_t)); if (pInfo->UserName && pInfo->Domain) { char username[MAX_USERNAME_LENGTH] = ""; char domain[MAX_DOMAIN_LENGTH] = ""; size_t szlen = 0; StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen); WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen, username, sizeof(username), NULL, NULL); StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen); WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen, domain, sizeof(domain), NULL, NULL); GetDomainLogonOptions(NULL, username, domain, &opt); } if (ISREMOTE(opt.flags)) { if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen)) { if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen); if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen)) { DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError()); } } } /* We can't use pInfo->Domain for the domain since in the cross realm case * this is source domain and not the destination domain. */ if (tokenUser && QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) { WCHAR Domain[64]=L""; GetLocalShortDomain(Domain, sizeof(Domain)); if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) { if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len)) GetUserProfileDirectory(pInfo->hToken, profileDir, &len); } } if (strlen(profileDir)) { DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir); if (!IsPathInAfs(profileDir)) { if (code = ktc_ForgetAllTokens()) DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code); else DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded"); } else { DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS"); } } else { DebugEvent0("AFS_Logoff_Event - Unable to load profile"); } if ( tokenUser ) LocalFree(tokenUser); } else { DebugEvent0("AFS_Logoff_Event - Local Logon"); if (code = ktc_ForgetAllTokens()) DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code); else DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded"); } } else { DebugEvent0("AFS_Logoff_Event - Preserving Tokens"); } DebugEvent0("AFS_Logoff_Event - End"); }
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; }