From 92dcbd617bd978259521755ddf5c847ccc5388b8 Mon Sep 17 00:00:00 2001 From: Ulrich Hahn Date: Mon, 5 Mar 2001 16:22:53 +0000 Subject: [PATCH] pam-afs-password-changing-support-20010305 support for changing passwords when user has kaserver password only --- src/pam/afs_message.c | 11 +- src/pam/afs_message.h | 7 +- src/pam/afs_password.c | 280 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 293 insertions(+), 5 deletions(-) diff --git a/src/pam/afs_message.c b/src/pam/afs_message.c index 0845f9a1b..da3c70817 100644 --- a/src/pam/afs_message.c +++ b/src/pam/afs_message.c @@ -36,7 +36,7 @@ static char *fallback_messages[] = { "AFS not available", /* 10: AFS_UNAVAIL */ "AFS error code 0x%x", /* 11: AFS_ERROR */ "AFS Authentication succeeded.\n", /* 12: LOGIN_OK */ - "AFS Authentication failed for user %s. %s\n", + "AFS Authentication failed for user %s %s\n", /* 13: LOGIN_FAILED */ "AFS PAM error, code=%d", /* 14: PAMERROR */ "AFS uid exceeds OS bounds.\n", /* 15: UID_OVERFLOW */ @@ -68,8 +68,13 @@ static char *fallback_messages[] = { /* 33: */ "", /* 34: */ - "AFS blindly trusting user %s\n", - /* 35: TRUSTROOT */ + "AFS blindly trusting user %s\n", /* 35: TRUSTROOT */ + "New AFS Password: ", /* 36: NEW_PWD_PROMPT */ + "New AFS Password (again): ", /* 37: VERIFY_PWD_PROMPT */ + "Failed to change AFS password", /* 38: KRBPASS_FAIL */ + "Missing PAM flag: %s", /* 39: FLAGS */ + "ka error, code=%d", /* 40: KAERROR */ + "Passwords are not equal" /* 41: NE_PASSWORD */ }; static int num_fallbacks = sizeof(fallback_messages)/sizeof(char *); diff --git a/src/pam/afs_message.h b/src/pam/afs_message.h index 6b7ec9bac..8b211b045 100644 --- a/src/pam/afs_message.h +++ b/src/pam/afs_message.h @@ -46,7 +46,12 @@ #define PAMAFS_CHOWNKRB 33 /* "Failed to chown krb ticketfile" */ #define PAMAFS_KRBFAIL 34 /* "Failed to set KRBTKTFILE" */ #define PAMAFS_TRUSTROOT 35 /* "Ignoring superuser %s" */ - +#define PAMAFS_NEW_PWD_PROMPT 36 /* "New AFS Password:" */ +#define PAMAFS_VERIFY_PWD_PROMPT 37 /* "New AFS Password (again):" */ +#define PAMAFS_KAPASS_FAIL 38 /* "Failed to change AFS password" */ +#define PAMAFS_FLAGS 39 /* "Missing PAM flag:" */ +#define PAMAFS_KAERROR 40 /* "ka error, code=%d" */ +#define PAMAFS_NE_PASSWORD 41 /* "Passwords are not equal" */ char *pam_afs_message(int msgnum, int *freeit); void pam_afs_syslog(int priority, int msgid, ...); diff --git a/src/pam/afs_password.c b/src/pam/afs_password.c index 3bd3dd830..c644e8568 100644 --- a/src/pam/afs_password.c +++ b/src/pam/afs_password.c @@ -9,6 +9,22 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include "afs_message.h" +#include "afs_util.h" +#include "afs_pam_msg.h" +#include +#include +#include + +#define RET(x) { retcode = (x); goto out; } extern int pam_sm_chauthtok( @@ -17,5 +33,267 @@ pam_sm_chauthtok( int argc, const char **argv) { - return PAM_PERM_DENIED; + 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_root = 0; + int got_authtok = 0; /* got PAM_AUTHTOK upon entry */ + int torch_password = 1; + int i; + char my_password_buf[256]; + char instance[256]; + char realm[256]; + char cell[256]; + char *localcell; + char *user = NULL, *password = NULL; + char *new_password = NULL, *verify_password = NULL; + char upwd_buf[2048]; /* size is a guess. */ + char* reason = NULL; + struct ktc_encryptionKey oldkey, newkey; + struct ktc_token token; + struct ubik_client *conn = 0; + struct pam_conv *pam_convp = NULL; + struct passwd unix_pwd, *upwd = NULL; + +#ifndef AFS_SUN56_ENV + openlog(pam_afs_ident, LOG_CONS, LOG_AUTH); +#endif + origmask = setlogmask(logmask); + + /* + * Parse the user options. Log an error for any unknown options. + * + * Todo options: PAM_SILENT + */ + 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_root = 1; + } else { + pam_afs_syslog(LOG_ERR, PAMAFS_UNKNOWNOPT, argv[i]); + } + } + + if (use_first_pass) try_first_pass = 0; + + pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass, try_first_pass); + pam_afs_syslog(LOG_DEBUG, PAMAFS_PAMERROR, flags); + + /* 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, "AFS username: ")) != PAM_SUCCESS) { + pam_afs_syslog(LOG_ERR, PAMAFS_NOUSER, errcode); + RET(PAM_USER_UNKNOWN); + } + + pam_afs_syslog(LOG_DEBUG, PAMAFS_USERNAMEDEBUG, user); + + /* + * If the user has a "local" (or via nss, possibly nss_dce) pwent, + * and its uid==0, and "ignore_root" was given in pam.conf, + * ignore the user. + */ +#if defined(AFS_HPUX_ENV) +#if defined(AFS_HPUX110_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_root && i == 0 && upwd->pw_uid == 0) { + pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user); + RET(PAM_AUTH_ERR); + } +#else +#ifdef AFS_LINUX20_ENV + upwd = getpwnam(user); +#else + upwd = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf)); +#endif + if (ignore_root && upwd != NULL && upwd->pw_uid == 0) { + 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 */ + 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 { + pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user); + torch_password = 0; + got_authtok = 1; + } + if (!(use_first_pass || try_first_pass)) { + password = NULL; + } + + 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; + 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; + } + + if ( (code = ka_VerifyUserPassword(KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, + user, /* kerberos name */ + (char *)0, /* instance */ + (char *)0, /* realm */ + password, /* password */ + 0, /* spare 2 */ + &reason /* error string */ )) !=0 ) { + pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user, reason); + RET(PAM_AUTH_ERR); + } + torch_password = 0; + pam_set_item(pamh, PAM_AUTHTOK, password); + pam_set_item(pamh, PAM_OLDAUTHTOK, password); + if (flags & PAM_PRELIM_CHECK) { + /* only auth check was requested, so return success here */ + return(PAM_SUCCESS); + } + if (!(flags & PAM_UPDATE_AUTHTOK)) { + /* these lines are never executed ... */ + /* UPDATE_AUTHTOK flag is required, return with error */ + pam_afs_syslog(LOG_ERR, PAMAFS_FLAGS, "PAM_UPDATE_AUTHTOK"); + RET(PAM_AUTH_ERR); + } + + /* get the new passwd and verify it */ + errcode = pam_afs_prompt(pam_convp, &new_password, 0, PAMAFS_NEW_PWD_PROMPT); + if (errcode != PAM_SUCCESS || new_password == NULL) { + pam_afs_syslog(LOG_ERR, PAMAFS_GETPASS_FAILED); + RET(PAM_AUTH_ERR); + } + if (new_password[0] == '\0') { + pam_afs_syslog(LOG_INFO, PAMAFS_NILPASSWORD, user); + RET(PAM_AUTH_ERR); + } + errcode = pam_afs_prompt(pam_convp, &verify_password, 0, PAMAFS_VERIFY_PWD_PROMPT); + if (errcode != PAM_SUCCESS || verify_password == NULL) { + pam_afs_syslog(LOG_ERR, PAMAFS_GETPASS_FAILED); + memset(new_password, 0, strlen(new_password)); + RET(PAM_AUTH_ERR); + } + if (verify_password[0] == '\0') { + pam_afs_syslog(LOG_INFO, PAMAFS_NILPASSWORD, user); + memset(new_password, 0, strlen(new_password)); + RET(PAM_AUTH_ERR); + } + if (strcmp(new_password, verify_password) != 0) { + pam_afs_syslog(LOG_INFO, PAMAFS_NE_PASSWORD); + memset(new_password, 0, strlen(new_password)); + memset(verify_password, 0, strlen(verify_password)); + RET(PAM_AUTH_ERR); + } + memset(verify_password, 0, strlen(verify_password)); + /* checking password length and quality is up to other PAM modules */ + + /* set the new password */ + if ((code = ka_Init(0)) != 0) { + pam_afs_syslog(LOG_ERR, PAMAFS_KAERROR, code); + RET(PAM_AUTH_ERR); + } + if ((code = rx_Init(0)) != 0) { + pam_afs_syslog(LOG_ERR, PAMAFS_KAERROR, code); + RET(PAM_AUTH_ERR); + } + strcpy(instance,""); + if ((localcell = ka_LocalCell()) == NULL) { + pam_afs_syslog(LOG_ERR, PAMAFS_NOCELLNAME); + RET(PAM_AUTH_ERR); + } + strcpy(realm,localcell); + strcpy(cell,realm); + /* oldkey is not used in ka_ChangePassword (only for ka_auth) */ + ka_StringToKey(password, realm, &oldkey); + ka_StringToKey(new_password, realm, &newkey); + if ((code = ka_GetAdminToken(user, instance, realm, &oldkey, 20, &token, 0)) != 0) { + pam_afs_syslog(LOG_ERR, PAMAFS_KAERROR, code); + RET(PAM_AUTH_ERR); + } + if ((code = ka_AuthServerConn(realm, KA_MAINTENANCE_SERVICE, &token, &conn)) != 0) { + pam_afs_syslog(LOG_ERR, PAMAFS_KAERROR, code); + RET(PAM_AUTH_ERR); + } + if ((code = ka_ChangePassword(user, /* kerberos name */ + instance, /* instance */ + conn, /* conn */ + 0, /* old password unused */ + &newkey /* new password */ )) != 0) { + pam_afs_syslog(LOG_ERR, PAMAFS_KAPASS_FAIL); + memset(new_password, 0, strlen(new_password)); + RET(PAM_AUTH_ERR); + } else { + pam_set_item(pamh, PAM_AUTHTOK, new_password); + RET(PAM_SUCCESS); + } + + out: + if (password && torch_password) { + memset(password, 0, strlen(password)); + } + (void) setlogmask(origmask); +#ifndef AFS_SUN56_ENV + closelog(); +#endif + return retcode; } -- 2.39.5