mirror of
https://git.openafs.org/openafs.git
synced 2025-01-31 21:47:45 +00:00
33ca19acbd
Casting NULL shouldn't be necessary in most cases. Eliminate this in favor of shorter lines and consistency. Function pointers, variadic arguments should still be cast. Change-Id: Ibcd67378556e45c2b24f7aa85a4d73c72cd88e02 Reviewed-on: http://gerrit.openafs.org/8151 Reviewed-by: Garrett Wollman <wollman@csail.mit.edu> Tested-by: BuildBot <buildbot@rampaginggeek.com> Reviewed-by: Derrick Brashear <shadow@your-file-system.com>
360 lines
11 KiB
C
360 lines
11 KiB
C
/*
|
|
* Copyright 2000, International Business Machines Corporation and others.
|
|
* All Rights Reserved.
|
|
*
|
|
* This software has been released under the terms of the IBM Public
|
|
* License. For details, see the LICENSE file in the top-level source
|
|
* directory or online at http://www.openafs.org/dl/license10.html
|
|
*/
|
|
|
|
#include <afsconfig.h>
|
|
#include <afs/param.h>
|
|
|
|
#include <roken.h>
|
|
|
|
#include <security/pam_appl.h>
|
|
#include <security/pam_modules.h>
|
|
|
|
#include <afs/sys_prototypes.h>
|
|
#include <afs/kautils.h>
|
|
|
|
#include "afs_message.h"
|
|
#include "afs_pam_msg.h"
|
|
#include "afs_util.h"
|
|
|
|
|
|
|
|
#define RET(x) { retcode = (x); goto out; }
|
|
|
|
#if defined(AFS_KERBEROS_ENV)
|
|
extern char *ktc_tkt_string(void);
|
|
#endif
|
|
|
|
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], 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:")) != PAM_SUCCESS) {
|
|
pam_afs_syslog(LOG_ERR, PAMAFS_NOUSER, errcode);
|
|
RET(PAM_USER_UNKNOWN);
|
|
}
|
|
/*
|
|
* 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.
|
|
*/
|
|
/* 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;
|
|
}
|