summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2001-04-30 20:37:44 +0000
committerJeremy Allison <jra@samba.org>2001-04-30 20:37:44 +0000
commitbda358eaa27aae4a0feb2c37f86845722d29361a (patch)
tree9a230798a5bcac6f3448d85242551a71c16a9c1e
parentb1e6176edef398133eb2a070cc0ae6713510023a (diff)
downloadsamba-bda358eaa27aae4a0feb2c37f86845722d29361a.tar.gz
samba-bda358eaa27aae4a0feb2c37f86845722d29361a.tar.xz
samba-bda358eaa27aae4a0feb2c37f86845722d29361a.zip
Based on an original PAM patch by Andrew Bartlett, re-written by me to
remove global static PAM variables, and to tidy up the PAM internals code. Now looks like the rest of Samba. Still needs testing. Jeremy.
-rw-r--r--source/auth/pampass.c541
-rw-r--r--source/include/proto.h9
-rw-r--r--source/passdb/pampass.c541
-rw-r--r--source/rpc_server/srv_netlog_nt.c8
-rw-r--r--source/smbd/chgpasswd.c21
-rw-r--r--source/smbd/password.c24
-rw-r--r--source/smbd/session.c20
7 files changed, 886 insertions, 278 deletions
diff --git a/source/auth/pampass.c b/source/auth/pampass.c
index 9f4a8f57b91..83640bf5c86 100644
--- a/source/auth/pampass.c
+++ b/source/auth/pampass.c
@@ -44,31 +44,58 @@ extern int DEBUGLEVEL;
#include <security/pam_appl.h>
/*
- * Static variables used to communicate between the conversation function
- * and the server_login function
+ * Structure used to communicate between the conversation function
+ * and the server_login/change password functions.
*/
-static char *PAM_username;
-static char *PAM_password;
+struct smb_pam_userdata {
+ char *PAM_username;
+ char *PAM_password;
+ char *PAM_newpassword;
+};
+
+typedef int (*smb_pam_conv_fn)(int, const struct pam_message **, struct pam_response **, void *appdata_ptr);
/*
* Macros to help make life easy
*/
#define COPY_STRING(s) (s) ? strdup(s) : NULL
-/*
- * PAM error handler.
- */
+/*******************************************************************
+ PAM error handler.
+ *********************************************************************/
+
static BOOL smb_pam_error_handler(pam_handle_t *pamh, int pam_error, char *msg, int dbglvl)
{
if( pam_error != PAM_SUCCESS) {
- DEBUG(dbglvl, ("PAM: %s : %s\n", msg, pam_strerror(pamh, pam_error)));
+ DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n",
+ msg, pam_strerror(pamh, pam_error)));
return False;
}
return True;
}
+/*******************************************************************
+ This function is a sanity check, to make sure that we NEVER report
+ failure as sucess.
+*********************************************************************/
+
+static BOOL smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error,
+ char *msg, int dbglvl, uint32 *nt_status)
+{
+ if (smb_pam_error_handler(pamh, pam_error, msg, dbglvl))
+ return True;
+
+ if (*nt_status == NT_STATUS_NOPROBLEMO) {
+ /* Complain LOUDLY */
+ DEBUG(0, ("smb_pam_nt_status_error_handler: PAM: BUG: PAM and NT_STATUS \
+error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));
+ *nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+ return False;
+}
+
/*
* PAM conversation function
* Here we assume (for now, at least) that echo on means login name, and
@@ -82,6 +109,9 @@ static int smb_pam_conv(int num_msg,
{
int replies = 0;
struct pam_response *reply = NULL;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+
+ *resp = NULL;
reply = malloc(sizeof(struct pam_response) * num_msg);
if (!reply)
@@ -91,15 +121,13 @@ static int smb_pam_conv(int num_msg,
switch (msg[replies]->msg_style) {
case PAM_PROMPT_ECHO_ON:
reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp =
- COPY_STRING(PAM_username);
+ reply[replies].resp = COPY_STRING(udp->PAM_username);
/* PAM frees resp */
break;
case PAM_PROMPT_ECHO_OFF:
reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp =
- COPY_STRING(PAM_password);
+ reply[replies].resp = COPY_STRING(udp->PAM_password);
/* PAM frees resp */
break;
@@ -123,41 +151,158 @@ static int smb_pam_conv(int num_msg,
return PAM_SUCCESS;
}
-static struct pam_conv smb_pam_conversation = {
- &smb_pam_conv,
- NULL
-};
+/*
+ * PAM password change conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static int smb_pam_passchange_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ fstring currentpw_prompt;
+ fstring newpw_prompt;
+ fstring repeatpw_prompt;
+ char *p = lp_passwd_chat();
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+
+ /* Get the prompts... */
+
+ if (!next_token(&p, currentpw_prompt, NULL, sizeof(fstring)))
+ return PAM_CONV_ERR;
+ if (!next_token(&p, newpw_prompt, NULL, sizeof(fstring)))
+ return PAM_CONV_ERR;
+ if (!next_token(&p, repeatpw_prompt, NULL, sizeof(fstring)))
+ return PAM_CONV_ERR;
+
+ *resp = NULL;
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply)
+ return PAM_CONV_ERR;
+
+ for (replies = 0; replies < num_msg; replies++) {
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_username);
+ /* PAM frees resp */
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ DEBUG(10,("smb_pam_passchange_conv: PAM Replied: %s\n", msg[replies]->msg));
+ if (strncmp(currentpw_prompt, msg[replies]->msg, strlen(currentpw_prompt)) == 0) {
+ reply[replies].resp = COPY_STRING(udp->PAM_password);
+ } else if (strncmp(newpw_prompt, msg[replies]->msg, strlen(newpw_prompt)) == 0) {
+ reply[replies].resp = COPY_STRING(udp->PAM_newpassword);
+ } else if (strncmp(repeatpw_prompt, msg[replies]->msg, strlen(repeatpw_prompt)) == 0) {
+ reply[replies].resp = COPY_STRING(udp->PAM_newpassword);
+ } else {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ DEBUG(5,("smb_pam_passchange_conv: Prompts available:\n CurrentPW: \"%s\"\n NewPW: \"%s\"\n \
+RepeatPW: \"%s\"\n",currentpw_prompt,newpw_prompt,repeatpw_prompt));
+ }
+ /* PAM frees resp */
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ free(reply);
+ reply = NULL;
+ return PAM_CONV_ERR;
+ }
+ }
+
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/***************************************************************************
+ Free up a malloced pam_conv struct.
+****************************************************************************/
+
+static void smb_free_pam_conv(struct pam_conv *pconv)
+{
+ if (pconv)
+ safe_free(pconv->appdata_ptr);
+
+ safe_free(pconv);
+}
+
+/***************************************************************************
+ Allocate a pam_conv struct.
+****************************************************************************/
+
+static struct pam_conv *smb_setup_pam_conv(smb_pam_conv_fn smb_pam_conv_fnptr, char *user,
+ char *passwd, char *newpass)
+{
+ struct pam_conv *pconv = (struct pam_conv *)malloc(sizeof(struct pam_conv));
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)malloc(sizeof(struct smb_pam_userdata));
+
+ if (pconv == NULL || udp == NULL) {
+ safe_free(pconv);
+ safe_free(udp);
+ return NULL;
+ }
+
+ udp->PAM_username = user;
+ udp->PAM_password = passwd;
+ udp->PAM_newpassword = newpass;
+
+ pconv->conv = smb_pam_conv_fnptr;
+ pconv->appdata_ptr = (void *)udp;
+ return pconv;
+}
/*
* PAM Closing out cleanup handler
*/
-static BOOL smb_pam_end(pam_handle_t *pamh)
+
+static BOOL smb_pam_end(pam_handle_t *pamh, struct pam_conv *smb_pam_conv_ptr)
{
int pam_error;
+
+ smb_free_pam_conv(smb_pam_conv_ptr);
if( pamh != NULL ) {
pam_error = pam_end(pamh, 0);
if(smb_pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
- DEBUG(4, ("PAM: PAM_END OK.\n"));
+ DEBUG(4, ("smb_pam_end: PAM: PAM_END OK.\n"));
return True;
}
}
- DEBUG(2,("PAM: not initialised"));
+ DEBUG(2,("smb_pam_end: PAM: not initialised"));
return False;
}
/*
* Start PAM authentication for specified account
*/
-static BOOL smb_pam_start(pam_handle_t **pamh, char *user, char *rhost)
+
+static BOOL smb_pam_start(pam_handle_t **pamh, char *user, char *rhost, struct pam_conv *pconv)
{
int pam_error;
*pamh = (pam_handle_t *)NULL;
- DEBUG(4,("PAM: Init user: %s\n", user));
+ DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", user));
- pam_error = pam_start("samba", user, &smb_pam_conversation, pamh);
+ pam_error = pam_start("samba", user, pconv, pamh);
if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
*pamh = (pam_handle_t *)NULL;
return False;
@@ -170,117 +315,134 @@ static BOOL smb_pam_start(pam_handle_t **pamh, char *user, char *rhost)
}
#ifdef PAM_RHOST
- DEBUG(4,("PAM: setting rhost to: %s\n", rhost));
+ DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", rhost));
pam_error = pam_set_item(*pamh, PAM_RHOST, rhost);
if(!smb_pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) {
- smb_pam_end(*pamh);
+ smb_pam_end(*pamh, pconv);
*pamh = (pam_handle_t *)NULL;
return False;
}
#endif
#ifdef PAM_TTY
- DEBUG(4,("PAM: setting tty\n"));
+ DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
if (!smb_pam_error_handler(*pamh, pam_error, "set tty failed", 0)) {
- smb_pam_end(*pamh);
+ smb_pam_end(*pamh, pconv);
*pamh = (pam_handle_t *)NULL;
return False;
}
#endif
- DEBUG(4,("PAM: Init passed for user: %s\n", user));
+ DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", user));
return True;
}
/*
* PAM Authentication Handler
*/
-static BOOL smb_pam_auth(pam_handle_t *pamh, char *user, char *password)
+static uint32 smb_pam_auth(pam_handle_t *pamh, char *user)
{
int pam_error;
+ uint32 nt_status = NT_STATUS_LOGON_FAILURE;
/*
* To enable debugging set in /etc/pam.d/samba:
* auth required /lib/security/pam_pwdb.so nullok shadow audit
*/
- DEBUG(4,("PAM: Authenticate User: %s\n", user));
- pam_error = pam_authenticate(pamh, PAM_SILENT); /* Can we authenticate user? */
+ DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
+ pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
switch( pam_error ){
case PAM_AUTH_ERR:
- DEBUG(2, ("PAM: Athentication Error\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
+ nt_status = NT_STATUS_WRONG_PASSWORD;
break;
case PAM_CRED_INSUFFICIENT:
- DEBUG(2, ("PAM: Insufficient Credentials\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
+ nt_status = NT_STATUS_INSUFFICIENT_LOGON_INFO;
break;
case PAM_AUTHINFO_UNAVAIL:
- DEBUG(2, ("PAM: Authentication Information Unavailable\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
break;
case PAM_USER_UNKNOWN:
- DEBUG(2, ("PAM: Username NOT known to Authentication system\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
break;
case PAM_MAXTRIES:
- DEBUG(2, ("PAM: One or more authentication modules reports user limit exceeeded\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
+ nt_status = NT_STATUS_REMOTE_SESSION_LIMIT;
break;
case PAM_ABORT:
- DEBUG(0, ("PAM: One or more PAM modules failed to load\n"));
+ DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
+ nt_status = NT_STATUS_NOPROBLEMO;
break;
- case PAM_SUCCESS:
- DEBUG(4, ("PAM: User %s Authenticated OK\n", user));
- break;
default:
- DEBUG(0, ("PAM: UNKNOWN ERROR while authenticating user %s\n", user));
- }
- if(!smb_pam_error_handler(pamh, pam_error, "Authentication Failure", 2)) {
- smb_pam_end(pamh);
- return False;
+ DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
}
- /* If this point is reached, the user has been authenticated. */
- return (True);
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status);
+ return nt_status;
}
/*
* PAM Account Handler
*/
-static BOOL smb_pam_account(pam_handle_t *pamh, char * user, char * password, BOOL pam_auth)
+static uint32 smb_pam_account(pam_handle_t *pamh, char * user)
{
int pam_error;
+ uint32 nt_status = NT_STATUS_ACCOUNT_DISABLED;
- DEBUG(4,("PAM: Account Management for User: %s\n", user));
+ DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
switch( pam_error ) {
case PAM_AUTHTOK_EXPIRED:
- DEBUG(2, ("PAM: User is valid but password is expired\n"));
+ DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
break;
case PAM_ACCT_EXPIRED:
- DEBUG(2, ("PAM: User no longer permitted to access system\n"));
+ DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
+ nt_status = NT_STATUS_ACCOUNT_EXPIRED;
break;
case PAM_AUTH_ERR:
- DEBUG(2, ("PAM: There was an authentication error\n"));
+ DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
break;
case PAM_PERM_DENIED:
- DEBUG(0, ("PAM: User is NOT permitted to access system at this time\n"));
+ DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
+ nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
break;
case PAM_USER_UNKNOWN:
- DEBUG(0, ("PAM: User \"%s\" is NOT known to account management\n", user));
+ DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
+ nt_status = NT_STATUS_NOPROBLEMO;
break;
- case PAM_SUCCESS:
- DEBUG(4, ("PAM: Account OK for User: %s\n", user));
- break;
default:
- DEBUG(0, ("PAM: UNKNOWN ERROR for User: %s\n", user));
- }
- if(!smb_pam_error_handler(pamh, pam_error, "Account Check Failed", 2)) {
- smb_pam_end(pamh);
- return False;
+ nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
+ break;
}
- /* Skip the pam_setcred() call if we didn't use pam_authenticate()
- for authentication -- it's an error to call pam_setcred without
- calling pam_authenticate first */
- if (!pam_auth) {
- DEBUG(4, ("PAM: Skipping setcred for user: %s (using encrypted passwords)\n", user));
- return True;
- }
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Credential Setting
+ */
+
+static uint32 smb_pam_setcred(pam_handle_t *pamh, char * user)
+{
+ int pam_error;
+ uint32 nt_status = NT_STATUS_NO_TOKEN;
/*
* This will allow samba to aquire a kerberos token. And, when
@@ -291,32 +453,34 @@ static BOOL smb_pam_account(pam_handle_t *pamh, char * user, char * password, BO
pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
switch( pam_error ) {
case PAM_CRED_UNAVAIL:
- DEBUG(0, ("PAM: Credentials not found for user:%s", user ));
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
+ nt_status = NT_STATUS_NO_TOKEN;
break;
case PAM_CRED_EXPIRED:
- DEBUG(0, ("PAM: Credentials for user: \"%s\" EXPIRED!", user ));
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
break;
case PAM_USER_UNKNOWN:
- DEBUG(0, ("PAM: User: \"%s\" is NOT known so can not set credentials!", user ));
+ DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
+ nt_status = NT_STATUS_NO_SUCH_USER;
break;
case PAM_CRED_ERR:
- DEBUG(0, ("PAM: Unknown setcredentials error - unable to set credentials for %s", user ));
+ DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
+ nt_status = NT_STATUS_NOPROBLEMO;
break;
- case PAM_SUCCESS:
- DEBUG(4, ("PAM: SetCredentials OK for User: %s\n", user));
- break;
default:
- DEBUG(0, ("PAM: Error Condition Unknown in pam_setcred function call!"));
- }
- if(!smb_pam_error_handler(pamh, pam_error, "Set Credential Failure", 2)) {
- smb_pam_end(pamh);
- return False;
+ DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
+ nt_status = NT_STATUS_NO_TOKEN;
+ break;
}
-
- /* If this point is reached, the user has been authenticated. */
- return (True);
-}
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Set Credential Failure", 2, &nt_status);
+ return nt_status;
+}
/*
* PAM Internal Session Handler
@@ -325,11 +489,8 @@ static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty,
{
int pam_error;
- PAM_password = NULL;
- PAM_username = user;
-
#ifdef PAM_TTY
- DEBUG(4,("PAM: tty set to: %s\n", tty));
+ DEBUG(4,("smb_internal_pam_session: PAM: tty set to: %s\n", tty));
pam_error = pam_set_item(pamh, PAM_TTY, tty);
if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
return False;
@@ -340,7 +501,8 @@ static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty,
if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
return False;
} else {
- pam_error = pam_close_session(pamh, PAM_SILENT);
+ pam_setcred(pamh, (PAM_DELETE_CRED|PAM_SILENT)); /* We don't care if this fails */
+ pam_error = pam_close_session(pamh, PAM_SILENT); /* This will probably pick up the error anyway */
if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
return False;
}
@@ -348,69 +510,147 @@ static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty,
}
/*
+ * Internal PAM Password Changer.
+ */
+
+static BOOL smb_pam_chauthtok(pam_handle_t *pamh, char * user)
+{
+ int pam_error;
+
+ DEBUG(4,("smb_pam_chauthtok: PAM: Password Change for User: %s\n", user));
+
+ pam_error = pam_chauthtok(pamh, PAM_SILENT); /* Change Password */
+
+ switch( pam_error ) {
+ case PAM_AUTHTOK_ERR:
+ DEBUG(2, ("PAM: unable to obtain the new authentication token - is password to weak?\n"));
+ break;
+ case PAM_AUTHTOK_RECOVER_ERR:
+ DEBUG(2, ("PAM: unable to obtain the old authentication token - was the old password wrong?.\n"));
+ break;
+ case PAM_AUTHTOK_LOCK_BUSY:
+ DEBUG(2, ("PAM: unable to change the authentication token since it is currently locked.\n"));
+ break;
+ case PAM_AUTHTOK_DISABLE_AGING:
+ DEBUG(2, ("PAM: Authentication token aging has been disabled.\n"));
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("PAM: Permission denied.\n"));
+ break;
+ case PAM_TRY_AGAIN:
+ DEBUG(0, ("PAM: Could not update all authentication token(s). No authentication tokens were updated.\n"));
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("PAM: User not known to PAM\n"));
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("PAM: Account OK for User: %s\n", user));
+ break;
+ default:
+ DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) for User: %s\n", pam_error, user));
+ }
+
+ if(!smb_pam_error_handler(pamh, pam_error, "Password Change Failed", 2)) {
+ return False;
+ }
+
+ /* If this point is reached, the password has changed. */
+ return True;
+}
+
+/*
* PAM Externally accessible Session handler
*/
-BOOL smb_pam_session(BOOL flag, const char *in_user, char *tty, char *rhost)
+BOOL smb_pam_claim_session(char *user, char *tty, char *rhost)
{
pam_handle_t *pamh = NULL;
- char * user;
+ struct pam_conv *pconv = NULL;
/* Ignore PAM if told to. */
if (!lp_obey_pam_restrictions())
return True;
- user = strdup(in_user);
- if ( user == NULL ) {
- DEBUG(0, ("PAM: PAM_session Malloc Failed!\n"));
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
return False;
- }
- if (!smb_pam_start(&pamh, user, rhost)) {
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
return False;
- }
- if (!smb_internal_pam_session(pamh, user, tty, flag)) {
- smb_pam_end(pamh);
+ if (!smb_internal_pam_session(pamh, user, tty, True)) {
+ smb_pam_end(pamh, pconv);
return False;
}
- return smb_pam_end(pamh);
+
+ return smb_pam_end(pamh, pconv);
}
/*
- * PAM Externally accessible Account handler
+ * PAM Externally accessible Session handler
*/
-BOOL smb_pam_accountcheck(char * user)
+
+BOOL smb_pam_close_session(char *user, char *tty, char *rhost)
{
pam_handle_t *pamh = NULL;
-
- PAM_username = user;
- PAM_password = NULL;
+ struct pam_conv *pconv = NULL;
/* Ignore PAM if told to. */
if (!lp_obey_pam_restrictions())
return True;
- if( smb_pam_start(&pamh, user, NULL)) {
- if ( smb_pam_account(pamh, user, NULL, False)) {
- return( smb_pam_end(pamh));
- }
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, False)) {
+ smb_pam_end(pamh, pconv);
+ return False;
}
- DEBUG(0, ("PAM: Account Validation Failed - Rejecting User!\n"));
- return( False );
+
+ return smb_pam_end(pamh, pconv);
}
/*
- * PAM Password Validation Suite
+ * PAM Externally accessible Account handler
*/
-BOOL smb_pam_passcheck(char * user, char * password)
+
+uint32 smb_pam_accountcheck(char * user)
{
+ uint32 nt_status = NT_STATUS_ACCOUNT_DISABLED;
pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
- PAM_username = user;
- PAM_password = password;
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return NT_STATUS_NOPROBLEMO;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_ACCOUNT_DISABLED;
+
+ if ((nt_status = smb_pam_account(pamh, user)) != NT_STATUS_NOPROBLEMO)
+ DEBUG(0, ("smb_pam_accountcheck: PAM: Account Validation Failed - Rejecting User %s!\n", user));
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Validation Suite
+ */
+
+uint32 smb_pam_passcheck(char * user, char * password)
+{
+ pam_handle_t *pamh = NULL;
+ uint32 nt_status = NT_STATUS_LOGON_FAILURE;
+ struct pam_conv *pconv = NULL;
/*
* Note we can't ignore PAM here as this is the only
@@ -418,23 +658,76 @@ BOOL smb_pam_passcheck(char * user, char * password)
* compiled --with-pam.
*/
- if( smb_pam_start(&pamh, user, NULL)) {
- if ( smb_pam_auth(pamh, user, password)) {
- if ( smb_pam_account(pamh, user, password, True)) {
- return( smb_pam_end(pamh));
- }
- }
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, password, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, NULL, NULL))
+ return NT_STATUS_LOGON_FAILURE;
+
+ if ((nt_status = smb_pam_auth(pamh, user)) != NT_STATUS_NOPROBLEMO) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_auth failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if ((nt_status = smb_pam_account(pamh, user)) != NT_STATUS_NOPROBLEMO) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_account failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if ((nt_status = smb_pam_setcred(pamh, user)) != NT_STATUS_NOPROBLEMO) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_setcred failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
}
- DEBUG(0, ("PAM: System Validation Failed - Rejecting User!\n"));
- return( False );
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Change Suite
+ */
+
+BOOL smb_pam_passchange(char * user, char * oldpassword, char * newpassword)
+{
+ /* Appropriate quantities of root should be obtained BEFORE calling this function */
+ struct pam_conv *pconv = NULL;
+ pam_handle_t *pamh = NULL;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_passchange_conv, user, oldpassword, newpassword)) == NULL)
+ return False;
+
+ if(!smb_pam_start(&pamh, user, NULL, pconv))
+ return False;
+
+ if (!smb_pam_chauthtok(pamh, user)) {
+ DEBUG(0, ("smb_pam_passchange: PAM: Password Change Failed for user %s!\n", user));
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
}
#else
/* If PAM not used, no PAM restrictions on accounts. */
- BOOL smb_pam_accountcheck(char * user)
+ uint32 smb_pam_accountcheck(char * user)
+{
+ return NT_STATUS_NOPROBLEMO;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+ BOOL smb_pam_claim_session(const char *user, char *tty, char *rhost)
{
return True;
}
+/* If PAM not used, also no PAM restrictions on sessions. */
+ BOOL smb_pam_close_session(const char *in_user, char *tty, char *rhost)
+{
+ return True;
+}
#endif /* WITH_PAM */
diff --git a/source/include/proto.h b/source/include/proto.h
index 0989c2dd34b..6bb7c24ce5c 100644
--- a/source/include/proto.h
+++ b/source/include/proto.h
@@ -1984,9 +1984,11 @@ struct passdb_ops *nisplus_initialize_password_db(void);
/*The following definitions come from passdb/pampass.c */
-BOOL smb_pam_session(BOOL flag, const char *in_user, char *tty, char *rhost);
-BOOL smb_pam_accountcheck(char * user);
-BOOL smb_pam_passcheck(char * user, char * password);
+BOOL smb_pam_claim_session(char *user, char *tty, char *rhost);
+BOOL smb_pam_close_session(char *user, char *tty, char *rhost);
+uint32 smb_pam_accountcheck(char * user);
+uint32 smb_pam_passcheck(char * user, char * password);
+BOOL smb_pam_passchange(char * user, char * oldpassword, char * newpassword);
/*The following definitions come from passdb/pass_check.c */
@@ -3860,6 +3862,7 @@ void process_blocking_lock_queue(time_t t);
BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root);
BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root);
+BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root);
BOOL check_lanman_password(char *user, uchar * pass1,
uchar * pass2, struct smb_passwd **psmbpw);
BOOL change_lanman_password(struct smb_passwd *smbpw, uchar * pass1,
diff --git a/source/passdb/pampass.c b/source/passdb/pampass.c
index 9f4a8f57b91..83640bf5c86 100644
--- a/source/passdb/pampass.c
+++ b/source/passdb/pampass.c
@@ -44,31 +44,58 @@ extern int DEBUGLEVEL;
#include <security/pam_appl.h>
/*
- * Static variables used to communicate between the conversation function
- * and the server_login function
+ * Structure used to communicate between the conversation function
+ * and the server_login/change password functions.
*/
-static char *PAM_username;
-static char *PAM_password;
+struct smb_pam_userdata {
+ char *PAM_username;
+ char *PAM_password;
+ char *PAM_newpassword;
+};
+
+typedef int (*smb_pam_conv_fn)(int, const struct pam_message **, struct pam_response **, void *appdata_ptr);
/*
* Macros to help make life easy
*/
#define COPY_STRING(s) (s) ? strdup(s) : NULL
-/*
- * PAM error handler.
- */
+/*******************************************************************
+ PAM error handler.
+ *********************************************************************/
+
static BOOL smb_pam_error_handler(pam_handle_t *pamh, int pam_error, char *msg, int dbglvl)
{
if( pam_error != PAM_SUCCESS) {
- DEBUG(dbglvl, ("PAM: %s : %s\n", msg, pam_strerror(pamh, pam_error)));
+ DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n",
+ msg, pam_strerror(pamh, pam_error)));
return False;
}
return True;
}
+/*******************************************************************
+ This function is a sanity check, to make sure that we NEVER report
+ failure as sucess.
+*********************************************************************/
+
+static BOOL smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error,
+ char *msg, int dbglvl, uint32 *nt_status)
+{
+ if (smb_pam_error_handler(pamh, pam_error, msg, dbglvl))
+ return True;
+
+ if (*nt_status == NT_STATUS_NOPROBLEMO) {
+ /* Complain LOUDLY */
+ DEBUG(0, ("smb_pam_nt_status_error_handler: PAM: BUG: PAM and NT_STATUS \
+error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));
+ *nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+ return False;
+}
+
/*
* PAM conversation function
* Here we assume (for now, at least) that echo on means login name, and
@@ -82,6 +109,9 @@ static int smb_pam_conv(int num_msg,
{
int replies = 0;
struct pam_response *reply = NULL;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+
+ *resp = NULL;
reply = malloc(sizeof(struct pam_response) * num_msg);
if (!reply)
@@ -91,15 +121,13 @@ static int smb_pam_conv(int num_msg,
switch (msg[replies]->msg_style) {
case PAM_PROMPT_ECHO_ON:
reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp =
- COPY_STRING(PAM_username);
+ reply[replies].resp = COPY_STRING(udp->PAM_username);
/* PAM frees resp */
break;
case PAM_PROMPT_ECHO_OFF:
reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp =
- COPY_STRING(PAM_password);
+ reply[replies].resp = COPY_STRING(udp->PAM_password);
/* PAM frees resp */
break;
@@ -123,41 +151,158 @@ static int smb_pam_conv(int num_msg,
return PAM_SUCCESS;
}
-static struct pam_conv smb_pam_conversation = {
- &smb_pam_conv,
- NULL
-};
+/*
+ * PAM password change conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static int smb_pam_passchange_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ fstring currentpw_prompt;
+ fstring newpw_prompt;
+ fstring repeatpw_prompt;
+ char *p = lp_passwd_chat();
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+
+ /* Get the prompts... */
+
+ if (!next_token(&p, currentpw_prompt, NULL, sizeof(fstring)))
+ return PAM_CONV_ERR;
+ if (!next_token(&p, newpw_prompt, NULL, sizeof(fstring)))
+ return PAM_CONV_ERR;
+ if (!next_token(&p, repeatpw_prompt, NULL, sizeof(fstring)))
+ return PAM_CONV_ERR;
+
+ *resp = NULL;
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply)
+ return PAM_CONV_ERR;
+
+ for (replies = 0; replies < num_msg; replies++) {
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_username);
+ /* PAM frees resp */
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ DEBUG(10,("smb_pam_passchange_conv: PAM Replied: %s\n", msg[replies]->msg));
+ if (strncmp(currentpw_prompt, msg[replies]->msg, strlen(currentpw_prompt)) == 0) {
+ reply[replies].resp = COPY_STRING(udp->PAM_password);
+ } else if (strncmp(newpw_prompt, msg[replies]->msg, strlen(newpw_prompt)) == 0) {
+ reply[replies].resp = COPY_STRING(udp->PAM_newpassword);
+ } else if (strncmp(repeatpw_prompt, msg[replies]->msg, strlen(repeatpw_prompt)) == 0) {
+ reply[replies].resp = COPY_STRING(udp->PAM_newpassword);
+ } else {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ DEBUG(5,("smb_pam_passchange_conv: Prompts available:\n CurrentPW: \"%s\"\n NewPW: \"%s\"\n \
+RepeatPW: \"%s\"\n",currentpw_prompt,newpw_prompt,repeatpw_prompt));
+ }
+ /* PAM frees resp */
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ free(reply);
+ reply = NULL;
+ return PAM_CONV_ERR;
+ }
+ }
+
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/***************************************************************************
+ Free up a malloced pam_conv struct.
+****************************************************************************/
+
+static void smb_free_pam_conv(struct pam_conv *pconv)
+{
+ if (pconv)
+ safe_free(pconv->appdata_ptr);
+
+ safe_free(pconv);
+}
+
+/***************************************************************************
+ Allocate a pam_conv struct.
+****************************************************************************/
+
+static struct pam_conv *smb_setup_pam_conv(smb_pam_conv_fn smb_pam_conv_fnptr, char *user,
+ char *passwd, char *newpass)
+{
+ struct pam_conv *pconv = (struct pam_conv *)malloc(sizeof(struct pam_conv));
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)malloc(sizeof(struct smb_pam_userdata));
+
+ if (pconv == NULL || udp == NULL) {
+ safe_free(pconv);
+ safe_free(udp);
+ return NULL;
+ }
+
+ udp->PAM_username = user;
+ udp->PAM_password = passwd;
+ udp->PAM_newpassword = newpass;
+
+ pconv->conv = smb_pam_conv_fnptr;
+ pconv->appdata_ptr = (void *)udp;
+ return pconv;
+}
/*
* PAM Closing out cleanup handler
*/
-static BOOL smb_pam_end(pam_handle_t *pamh)
+
+static BOOL smb_pam_end(pam_handle_t *pamh, struct pam_conv *smb_pam_conv_ptr)
{
int pam_error;
+
+ smb_free_pam_conv(smb_pam_conv_ptr);
if( pamh != NULL ) {
pam_error = pam_end(pamh, 0);
if(smb_pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
- DEBUG(4, ("PAM: PAM_END OK.\n"));
+ DEBUG(4, ("smb_pam_end: PAM: PAM_END OK.\n"));
return True;
}
}
- DEBUG(2,("PAM: not initialised"));
+ DEBUG(2,("smb_pam_end: PAM: not initialised"));
return False;
}
/*
* Start PAM authentication for specified account
*/
-static BOOL smb_pam_start(pam_handle_t **pamh, char *user, char *rhost)
+
+static BOOL smb_pam_start(pam_handle_t **pamh, char *user, char *rhost, struct pam_conv *pconv)
{
int pam_error;
*pamh = (pam_handle_t *)NULL;
- DEBUG(4,("PAM: Init user: %s\n", user));
+ DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", user));
- pam_error = pam_start("samba", user, &smb_pam_conversation, pamh);
+ pam_error = pam_start("samba", user, pconv, pamh);
if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
*pamh = (pam_handle_t *)NULL;
return False;
@@ -170,117 +315,134 @@ static BOOL smb_pam_start(pam_handle_t **pamh, char *user, char *rhost)
}
#ifdef PAM_RHOST
- DEBUG(4,("PAM: setting rhost to: %s\n", rhost));
+ DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", rhost));
pam_error = pam_set_item(*pamh, PAM_RHOST, rhost);
if(!smb_pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) {
- smb_pam_end(*pamh);
+ smb_pam_end(*pamh, pconv);
*pamh = (pam_handle_t *)NULL;
return False;
}
#endif
#ifdef PAM_TTY
- DEBUG(4,("PAM: setting tty\n"));
+ DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
if (!smb_pam_error_handler(*pamh, pam_error, "set tty failed", 0)) {
- smb_pam_end(*pamh);
+ smb_pam_end(*pamh, pconv);
*pamh = (pam_handle_t *)NULL;
return False;
}
#endif
- DEBUG(4,("PAM: Init passed for user: %s\n", user));
+ DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", user));
return True;
}
/*
* PAM Authentication Handler
*/
-static BOOL smb_pam_auth(pam_handle_t *pamh, char *user, char *password)
+static uint32 smb_pam_auth(pam_handle_t *pamh, char *user)
{
int pam_error;
+ uint32 nt_status = NT_STATUS_LOGON_FAILURE;
/*
* To enable debugging set in /etc/pam.d/samba:
* auth required /lib/security/pam_pwdb.so nullok shadow audit
*/
- DEBUG(4,("PAM: Authenticate User: %s\n", user));
- pam_error = pam_authenticate(pamh, PAM_SILENT); /* Can we authenticate user? */
+ DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
+ pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
switch( pam_error ){
case PAM_AUTH_ERR:
- DEBUG(2, ("PAM: Athentication Error\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
+ nt_status = NT_STATUS_WRONG_PASSWORD;
break;
case PAM_CRED_INSUFFICIENT:
- DEBUG(2, ("PAM: Insufficient Credentials\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
+ nt_status = NT_STATUS_INSUFFICIENT_LOGON_INFO;
break;
case PAM_AUTHINFO_UNAVAIL:
- DEBUG(2, ("PAM: Authentication Information Unavailable\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
break;
case PAM_USER_UNKNOWN:
- DEBUG(2, ("PAM: Username NOT known to Authentication system\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
break;
case PAM_MAXTRIES:
- DEBUG(2, ("PAM: One or more authentication modules reports user limit exceeeded\n"));
+ DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
+ nt_status = NT_STATUS_REMOTE_SESSION_LIMIT;
break;
case PAM_ABORT:
- DEBUG(0, ("PAM: One or more PAM modules failed to load\n"));
+ DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
+ nt_status = NT_STATUS_NOPROBLEMO;
break;
- case PAM_SUCCESS:
- DEBUG(4, ("PAM: User %s Authenticated OK\n", user));
- break;
default:
- DEBUG(0, ("PAM: UNKNOWN ERROR while authenticating user %s\n", user));
- }
- if(!smb_pam_error_handler(pamh, pam_error, "Authentication Failure", 2)) {
- smb_pam_end(pamh);
- return False;
+ DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
}
- /* If this point is reached, the user has been authenticated. */
- return (True);
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status);
+ return nt_status;
}
/*
* PAM Account Handler
*/
-static BOOL smb_pam_account(pam_handle_t *pamh, char * user, char * password, BOOL pam_auth)
+static uint32 smb_pam_account(pam_handle_t *pamh, char * user)
{
int pam_error;
+ uint32 nt_status = NT_STATUS_ACCOUNT_DISABLED;
- DEBUG(4,("PAM: Account Management for User: %s\n", user));
+ DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
switch( pam_error ) {
case PAM_AUTHTOK_EXPIRED:
- DEBUG(2, ("PAM: User is valid but password is expired\n"));
+ DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
break;
case PAM_ACCT_EXPIRED:
- DEBUG(2, ("PAM: User no longer permitted to access system\n"));
+ DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
+ nt_status = NT_STATUS_ACCOUNT_EXPIRED;
break;
case PAM_AUTH_ERR:
- DEBUG(2, ("PAM: There was an authentication error\n"));
+ DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
break;
case PAM_PERM_DENIED:
- DEBUG(0, ("PAM: User is NOT permitted to access system at this time\n"));
+ DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
+ nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
break;
case PAM_USER_UNKNOWN:
- DEBUG(0, ("PAM: User \"%s\" is NOT known to account management\n", user));
+ DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
+ nt_status = NT_STATUS_NOPROBLEMO;
break;
- case PAM_SUCCESS:
- DEBUG(4, ("PAM: Account OK for User: %s\n", user));
- break;
default:
- DEBUG(0, ("PAM: UNKNOWN ERROR for User: %s\n", user));
- }
- if(!smb_pam_error_handler(pamh, pam_error, "Account Check Failed", 2)) {
- smb_pam_end(pamh);
- return False;
+ nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
+ break;
}
- /* Skip the pam_setcred() call if we didn't use pam_authenticate()
- for authentication -- it's an error to call pam_setcred without
- calling pam_authenticate first */
- if (!pam_auth) {
- DEBUG(4, ("PAM: Skipping setcred for user: %s (using encrypted passwords)\n", user));
- return True;
- }
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Credential Setting
+ */
+
+static uint32 smb_pam_setcred(pam_handle_t *pamh, char * user)
+{
+ int pam_error;
+ uint32 nt_status = NT_STATUS_NO_TOKEN;
/*
* This will allow samba to aquire a kerberos token. And, when
@@ -291,32 +453,34 @@ static BOOL smb_pam_account(pam_handle_t *pamh, char * user, char * password, BO
pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
switch( pam_error ) {
case PAM_CRED_UNAVAIL:
- DEBUG(0, ("PAM: Credentials not found for user:%s", user ));
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
+ nt_status = NT_STATUS_NO_TOKEN;
break;
case PAM_CRED_EXPIRED:
- DEBUG(0, ("PAM: Credentials for user: \"%s\" EXPIRED!", user ));
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
break;
case PAM_USER_UNKNOWN:
- DEBUG(0, ("PAM: User: \"%s\" is NOT known so can not set credentials!", user ));
+ DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
+ nt_status = NT_STATUS_NO_SUCH_USER;
break;
case PAM_CRED_ERR:
- DEBUG(0, ("PAM: Unknown setcredentials error - unable to set credentials for %s", user ));
+ DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
+ nt_status = NT_STATUS_NOPROBLEMO;
break;
- case PAM_SUCCESS:
- DEBUG(4, ("PAM: SetCredentials OK for User: %s\n", user));
- break;
default:
- DEBUG(0, ("PAM: Error Condition Unknown in pam_setcred function call!"));
- }
- if(!smb_pam_error_handler(pamh, pam_error, "Set Credential Failure", 2)) {
- smb_pam_end(pamh);
- return False;
+ DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
+ nt_status = NT_STATUS_NO_TOKEN;
+ break;
}
-
- /* If this point is reached, the user has been authenticated. */
- return (True);
-}
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Set Credential Failure", 2, &nt_status);
+ return nt_status;
+}
/*
* PAM Internal Session Handler
@@ -325,11 +489,8 @@ static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty,
{
int pam_error;
- PAM_password = NULL;
- PAM_username = user;
-
#ifdef PAM_TTY
- DEBUG(4,("PAM: tty set to: %s\n", tty));
+ DEBUG(4,("smb_internal_pam_session: PAM: tty set to: %s\n", tty));
pam_error = pam_set_item(pamh, PAM_TTY, tty);
if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
return False;
@@ -340,7 +501,8 @@ static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty,
if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
return False;
} else {
- pam_error = pam_close_session(pamh, PAM_SILENT);
+ pam_setcred(pamh, (PAM_DELETE_CRED|PAM_SILENT)); /* We don't care if this fails */
+ pam_error = pam_close_session(pamh, PAM_SILENT); /* This will probably pick up the error anyway */
if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
return False;
}
@@ -348,69 +510,147 @@ static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty,
}
/*
+ * Internal PAM Password Changer.
+ */
+
+static BOOL smb_pam_chauthtok(pam_handle_t *pamh, char * user)
+{
+ int pam_error;
+
+ DEBUG(4,("smb_pam_chauthtok: PAM: Password Change for User: %s\n", user));
+
+ pam_error = pam_chauthtok(pamh, PAM_SILENT); /* Change Password */
+
+ switch( pam_error ) {
+ case PAM_AUTHTOK_ERR:
+ DEBUG(2, ("PAM: unable to obtain the new authentication token - is password to weak?\n"));
+ break;
+ case PAM_AUTHTOK_RECOVER_ERR:
+ DEBUG(2, ("PAM: unable to obtain the old authentication token - was the old password wrong?.\n"));
+ break;
+ case PAM_AUTHTOK_LOCK_BUSY:
+ DEBUG(2, ("PAM: unable to change the authentication token since it is currently locked.\n"));
+ break;
+ case PAM_AUTHTOK_DISABLE_AGING:
+ DEBUG(2, ("PAM: Authentication token aging has been disabled.\n"));
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("PAM: Permission denied.\n"));
+ break;
+ case PAM_TRY_AGAIN:
+ DEBUG(0, ("PAM: Could not update all authentication token(s). No authentication tokens were updated.\n"));
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("PAM: User not known to PAM\n"));
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("PAM: Account OK for User: %s\n", user));
+ break;
+ default:
+ DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) for User: %s\n", pam_error, user));
+ }
+
+ if(!smb_pam_error_handler(pamh, pam_error, "Password Change Failed", 2)) {
+ return False;
+ }
+
+ /* If this point is reached, the password has changed. */
+ return True;
+}
+
+/*
* PAM Externally accessible Session handler
*/
-BOOL smb_pam_session(BOOL flag, const char *in_user, char *tty, char *rhost)
+BOOL smb_pam_claim_session(char *user, char *tty, char *rhost)
{
pam_handle_t *pamh = NULL;
- char * user;
+ struct pam_conv *pconv = NULL;
/* Ignore PAM if told to. */
if (!lp_obey_pam_restrictions())
return True;
- user = strdup(in_user);
- if ( user == NULL ) {
- DEBUG(0, ("PAM: PAM_session Malloc Failed!\n"));
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
return False;
- }
- if (!smb_pam_start(&pamh, user, rhost)) {
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
return False;
- }
- if (!smb_internal_pam_session(pamh, user, tty, flag)) {
- smb_pam_end(pamh);
+ if (!smb_internal_pam_session(pamh, user, tty, True)) {
+ smb_pam_end(pamh, pconv);
return False;
}
- return smb_pam_end(pamh);
+
+ return smb_pam_end(pamh, pconv);
}
/*
- * PAM Externally accessible Account handler
+ * PAM Externally accessible Session handler
*/
-BOOL smb_pam_accountcheck(char * user)
+
+BOOL smb_pam_close_session(char *user, char *tty, char *rhost)
{
pam_handle_t *pamh = NULL;
-
- PAM_username = user;
- PAM_password = NULL;
+ struct pam_conv *pconv = NULL;
/* Ignore PAM if told to. */
if (!lp_obey_pam_restrictions())
return True;
- if( smb_pam_start(&pamh, user, NULL)) {
- if ( smb_pam_account(pamh, user, NULL, False)) {
- return( smb_pam_end(pamh));
- }
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, False)) {
+ smb_pam_end(pamh, pconv);
+ return False;
}
- DEBUG(0, ("PAM: Account Validation Failed - Rejecting User!\n"));
- return( False );
+
+ return smb_pam_end(pamh, pconv);
}
/*
- * PAM Password Validation Suite
+ * PAM Externally accessible Account handler
*/
-BOOL smb_pam_passcheck(char * user, char * password)
+
+uint32 smb_pam_accountcheck(char * user)
{
+ uint32 nt_status = NT_STATUS_ACCOUNT_DISABLED;
pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
- PAM_username = user;
- PAM_password = password;
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return NT_STATUS_NOPROBLEMO;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_ACCOUNT_DISABLED;
+
+ if ((nt_status = smb_pam_account(pamh, user)) != NT_STATUS_NOPROBLEMO)
+ DEBUG(0, ("smb_pam_accountcheck: PAM: Account Validation Failed - Rejecting User %s!\n", user));
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Validation Suite
+ */
+
+uint32 smb_pam_passcheck(char * user, char * password)
+{
+ pam_handle_t *pamh = NULL;
+ uint32 nt_status = NT_STATUS_LOGON_FAILURE;
+ struct pam_conv *pconv = NULL;
/*
* Note we can't ignore PAM here as this is the only
@@ -418,23 +658,76 @@ BOOL smb_pam_passcheck(char * user, char * password)
* compiled --with-pam.
*/
- if( smb_pam_start(&pamh, user, NULL)) {
- if ( smb_pam_auth(pamh, user, password)) {
- if ( smb_pam_account(pamh, user, password, True)) {
- return( smb_pam_end(pamh));
- }
- }
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, password, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, NULL, NULL))
+ return NT_STATUS_LOGON_FAILURE;
+
+ if ((nt_status = smb_pam_auth(pamh, user)) != NT_STATUS_NOPROBLEMO) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_auth failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if ((nt_status = smb_pam_account(pamh, user)) != NT_STATUS_NOPROBLEMO) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_account failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if ((nt_status = smb_pam_setcred(pamh, user)) != NT_STATUS_NOPROBLEMO) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_setcred failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
}
- DEBUG(0, ("PAM: System Validation Failed - Rejecting User!\n"));
- return( False );
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Change Suite
+ */
+
+BOOL smb_pam_passchange(char * user, char * oldpassword, char * newpassword)
+{
+ /* Appropriate quantities of root should be obtained BEFORE calling this function */
+ struct pam_conv *pconv = NULL;
+ pam_handle_t *pamh = NULL;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_passchange_conv, user, oldpassword, newpassword)) == NULL)
+ return False;
+
+ if(!smb_pam_start(&pamh, user, NULL, pconv))
+ return False;
+
+ if (!smb_pam_chauthtok(pamh, user)) {
+ DEBUG(0, ("smb_pam_passchange: PAM: Password Change Failed for user %s!\n", user));
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
}
#else
/* If PAM not used, no PAM restrictions on accounts. */
- BOOL smb_pam_accountcheck(char * user)
+ uint32 smb_pam_accountcheck(char * user)
+{
+ return NT_STATUS_NOPROBLEMO;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+ BOOL smb_pam_claim_session(const char *user, char *tty, char *rhost)
{
return True;
}
+/* If PAM not used, also no PAM restrictions on sessions. */
+ BOOL smb_pam_close_session(const char *in_user, char *tty, char *rhost)
+{
+ return True;
+}
#endif /* WITH_PAM */
diff --git a/source/rpc_server/srv_netlog_nt.c b/source/rpc_server/srv_netlog_nt.c
index d41ae44ac60..fa6b9458152 100644
--- a/source/rpc_server/srv_netlog_nt.c
+++ b/source/rpc_server/srv_netlog_nt.c
@@ -594,9 +594,11 @@ uint32 _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_
}
#ifdef WITH_PAM
- if (!smb_pam_accountcheck(nt_username)) {
- return NT_STATUS_ACCOUNT_DISABLED;
- }
+ become_root();
+ status = smb_pam_accountcheck(nt_username);
+ unbecome_root();
+ if (status != NT_STATUS_NOPROBLEMO)
+ return status;
#endif
if (!(smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index 63f425f4cc3..1b879890813 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -53,6 +53,24 @@ extern int DEBUGLEVEL;
#if ALLOW_CHANGE_PASSWORD
+#ifdef WITH_PAM
+BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
+{
+ BOOL ret;
+
+ if (as_root)
+ become_root();
+
+ ret = smb_pam_passchange(name, oldpass, newpass);
+
+ if (as_root)
+ unbecome_root();
+
+ return ret;
+}
+
+#else /* WITH_PAM */
+
static int findpty(char **slave)
{
int master;
@@ -526,7 +544,10 @@ BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
(passwordprogram, name, chatsequence, as_root));
}
+#endif /* WITH_PAM */
+
#else /* ALLOW_CHANGE_PASSWORD */
+
BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
{
DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
diff --git a/source/smbd/password.c b/source/smbd/password.c
index ef457739c67..4beedbe2a5f 100644
--- a/source/smbd/password.c
+++ b/source/smbd/password.c
@@ -491,24 +491,24 @@ BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8],
/* Try against the lanman password. smb_pass->smb_passwd == NULL means
no password, allow access. */
- DEBUG(4,("Checking LM MD4 password\n"));
-
if((smb_pass->smb_passwd == NULL) &&
(smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
- DEBUG(4,("no password required for user %s\n",
+ DEBUG(4,("smb_password_ok: no password required for user %s\n",
smb_pass->smb_name));
return True;
}
- if((smb_pass->smb_passwd != NULL) &&
- smb_password_check((char *)lm_pass,
+ if(lp_lanman_auth() && (smb_pass->smb_passwd != NULL)) {
+ DEBUG(4,("smb_password_ok: Checking LM password\n"));
+
+ if (smb_password_check((char *)lm_pass,
(uchar *)smb_pass->smb_passwd, challenge)) {
- DEBUG(4,("LM MD4 password check succeeded\n"));
- return(True);
+ DEBUG(4,("smb_password_ok: LM password check succeeded\n"));
+ return(True);
+ }
+ DEBUG(4,("LM password check failed\n"));
}
- DEBUG(4,("LM MD4 password check failed\n"));
-
return False;
}
@@ -621,14 +621,14 @@ BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd)
*/
if (ret)
- return smb_pam_accountcheck(user);
+ return (smb_pam_accountcheck(user) == NT_STATUS_NOPROBLEMO);
return ret;
}
- return pass_check(user, password, pwlen, pwd,
+ return (pass_check(user, password, pwlen, pwd,
lp_update_encrypted() ?
- update_smbpassword_file : NULL);
+ update_smbpassword_file : NULL));
}
/****************************************************************************
diff --git a/source/smbd/session.c b/source/smbd/session.c
index 3131fb9f542..40654c0f43c 100644
--- a/source/smbd/session.c
+++ b/source/smbd/session.c
@@ -99,6 +99,13 @@ BOOL session_claim(uint16 vuid)
sessionid.id_num = i;
sessionid.pid = pid;
+ if (!smb_pam_claim_session(sessionid.username, sessionid.id_str, sessionid.hostname)) {
+ DEBUG(1,("pam_session rejected the session for %s [%s]\n",
+ sessionid.username, sessionid.id_str));
+ tdb_delete(tdb, key);
+ return False;
+ }
+
dlen = tdb_pack(dbuf, sizeof(dbuf), "fffdd",
sessionid.username, sessionid.hostname, sessionid.id_str,
sessionid.id_num, sessionid.pid);
@@ -110,15 +117,6 @@ BOOL session_claim(uint16 vuid)
return False;
}
-#if WITH_PAM
- if (!smb_pam_session(True, sessionid.username, sessionid.id_str, sessionid.hostname)) {
- DEBUG(1,("smb_pam_session rejected the session for %s [%s]\n",
- sessionid.username, sessionid.id_str));
- tdb_delete(tdb, key);
- return False;
- }
-#endif
-
#if WITH_UTMP
if (lp_utmp()) {
sys_utmp_claim(sessionid.username, sessionid.hostname,
@@ -169,9 +167,7 @@ void session_yield(uint16 vuid)
}
#endif
-#if WITH_PAM
- smb_pam_session(False, sessionid.username, sessionid.id_str, sessionid.hostname);
-#endif
+ smb_pam_close_session(sessionid.username, sessionid.id_str, sessionid.hostname);
tdb_delete(tdb, key);
}