summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/auth/pampass.c541
-rw-r--r--source3/include/proto.h9
-rw-r--r--source3/passdb/pampass.c541
-rw-r--r--source3/smbd/chgpasswd.c21
-rw-r--r--source3/smbd/password.c44
-rw-r--r--source3/smbd/session.c20
6 files changed, 888 insertions, 288 deletions
diff --git a/source3/auth/pampass.c b/source3/auth/pampass.c
index 9f4a8f57b9..83640bf5c8 100644
--- a/source3/auth/pampass.c
+++ b/source3/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/source3/include/proto.h b/source3/include/proto.h
index 12a63ca23c..ba13dd43c9 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -2022,9 +2022,11 @@ BOOL pdb_generate_sam_sid(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 */
@@ -3885,6 +3887,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, SAM_ACCOUNT **hnd);
BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar * pass1,
diff --git a/source3/passdb/pampass.c b/source3/passdb/pampass.c
index 9f4a8f57b9..83640bf5c8 100644
--- a/source3/passdb/pampass.c
+++ b/source3/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/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c
index 21b7722307..72e97abc3b 100644
--- a/source3/smbd/chgpasswd.c
+++ b/source3/smbd/chgpasswd.c
@@ -54,6 +54,24 @@ extern struct passdb_ops pdb_ops;
#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;
@@ -527,7 +545,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/source3/smbd/password.c b/source3/smbd/password.c
index ba882f2bf2..03d96bebc0 100644
--- a/source3/smbd/password.c
+++ b/source3/smbd/password.c
@@ -453,25 +453,21 @@ BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8],
user_name = pdb_get_username(sampass);
- DEBUG(4,("Checking SMB password for user %s\n",user_name));
+ DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n",user_name));
if(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
- DEBUG(1,("account for user %s was disabled.\n", user_name));
+ DEBUG(1,("smb_password_ok: account for user %s was disabled.\n", user_name));
return(False);
}
- if (chal == NULL)
- {
- DEBUG(5,("use last SMBnegprot challenge\n"));
- if (!last_challenge(challenge))
- {
- DEBUG(1,("no challenge done - password failed\n"));
+ if (chal == NULL) {
+ DEBUG(5,("smb_password_ok: use last SMBnegprot challenge\n"));
+ if (!last_challenge(challenge)) {
+ DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
return False;
}
- }
- else
- {
- DEBUG(5,("challenge received\n"));
+ } else {
+ DEBUG(5,("smb_password_ok: challenge received\n"));
memcpy(challenge, chal, 8);
}
@@ -482,35 +478,33 @@ BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8],
use it (ie. does it exist in the smbpasswd file).
*/
DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
- if (smb_password_check((char *)nt_pass, (uchar *)nt_pw, challenge))
- {
- DEBUG(4,("NT MD4 password check succeeded\n"));
+ if (smb_password_check((char *)nt_pass, (uchar *)nt_pw, challenge)) {
+ DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
return(True);
}
- DEBUG(4,("NT MD4 password check failed\n"));
+ DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
}
/* Try against the lanman password. pdb_get_lanman_passwd(sampass) == NULL
means no password, allow access. */
- DEBUG(4,("Checking LM MD4 password\n"));
-
lm_pw = pdb_get_lanman_passwd(sampass);
if((lm_pw == NULL) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ))
{
- DEBUG(4,("no password required for user %s\n",user_name));
+ DEBUG(4,("smb_password_ok: no password required for user %s\n",user_name));
return True;
}
- if((lm_pw != NULL) && smb_password_check((char *)lm_pass,(uchar *)lm_pw, challenge))
- {
- DEBUG(4,("LM MD4 password check succeeded\n"));
- return(True);
+ if(lp_lanman_auth() && (lm_pw != NULL)) {
+ DEBUG(4,("smb_password_ok: Checking LM password\n"));
+ if(smb_password_check((char *)lm_pass,(uchar *)lm_pw, challenge)) {
+ DEBUG(4,("smb_password_ok: LM password check succeeded\n"));
+ return(True);
+ }
+ DEBUG(4,("smb_password_ok: LM password check failed\n"));
}
- DEBUG(4,("LM MD4 password check failed\n"));
-
return False;
}
diff --git a/source3/smbd/session.c b/source3/smbd/session.c
index 3131fb9f54..40654c0f43 100644
--- a/source3/smbd/session.c
+++ b/source3/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);
}