svn commit: samba r12343 - in trunk/source/nsswitch: .

gd at samba.org gd at samba.org
Mon Dec 19 03:28:10 GMT 2005


Author: gd
Date: 2005-12-19 03:28:10 +0000 (Mon, 19 Dec 2005)
New Revision: 12343

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=12343

Log:
Change a password using rpccli_samr_chgpasswd3 in WINBINDD_PAM_CHAUTHTOK
and give back the password policy in the winbindd_response.

Guenther

Modified:
   trunk/source/nsswitch/winbindd_nss.h
   trunk/source/nsswitch/winbindd_pam.c


Changeset:
Modified: trunk/source/nsswitch/winbindd_nss.h
===================================================================
--- trunk/source/nsswitch/winbindd_nss.h	2005-12-19 03:15:50 UTC (rev 12342)
+++ trunk/source/nsswitch/winbindd_nss.h	2005-12-19 03:28:10 UTC (rev 12343)
@@ -178,6 +178,8 @@
 /* Flag to say this is a winbindd internal send - don't recurse. */
 #define WBFLAG_RECURSE			0x0800
 
+#define WBFLAG_PAM_KRB5			0x1000
+
 #define WINBINDD_MAX_EXTRA_DATA (128*1024)
 
 /* Winbind request structure */
@@ -310,6 +312,14 @@
 			int pam_error;
 			char user_session_key[16];
 			char first_8_lm_hash[8];
+			struct policy_settings {
+				uint16 min_length_password;
+				uint16 password_history;
+				uint32 password_properties;
+				time_t expire;
+				time_t min_passwordage;
+			} policy;
+			uint32 reject_reason;
 		} auth;
 		uint32 rid;	/* create user or group or allocate rid */
 		struct {

Modified: trunk/source/nsswitch/winbindd_pam.c
===================================================================
--- trunk/source/nsswitch/winbindd_pam.c	2005-12-19 03:15:50 UTC (rev 12342)
+++ trunk/source/nsswitch/winbindd_pam.c	2005-12-19 03:28:10 UTC (rev 12343)
@@ -181,10 +181,34 @@
 	resp->data.auth.pam_error = nt_status_to_pam(result);
 }
 
-/**********************************************************************
- Authenticate a user with a clear text password
-**********************************************************************/
+static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
+				       struct winbindd_cli_state *state)
+{
+	struct winbindd_methods *methods;
+	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+	SAM_UNK_INFO_1 password_policy;
 
+	methods = domain->methods;
+
+	status = methods->password_policy(domain, state->mem_ctx, &password_policy);
+	if (NT_STATUS_IS_ERR(status)) {
+		return status;
+	}
+
+	state->response.data.auth.policy.min_length_password =
+		password_policy.min_length_password;
+	state->response.data.auth.policy.password_history =
+		password_policy.password_history;
+	state->response.data.auth.policy.password_properties =
+		password_policy.password_properties;
+	state->response.data.auth.policy.expire	=
+		nt_time_to_unix_abs(&(password_policy.expire));
+	state->response.data.auth.policy.min_passwordage = 
+		nt_time_to_unix_abs(&(password_policy.min_passwordage));
+
+	return NT_STATUS_OK;
+}
+
 void winbindd_pam_auth(struct winbindd_cli_state *state)
 {
 	struct winbindd_domain *domain;
@@ -762,12 +786,15 @@
 
 void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
 {
-	NTSTATUS result;
+	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
 	char *oldpass, *newpass;
 	fstring domain, user;
 	POLICY_HND dom_pol;
 	struct winbindd_domain *contact_domain;
 	struct rpc_pipe_client *cli;
+	BOOL got_info = False;
+	SAM_UNK_INFO_1 *info;
+	SAMR_CHANGE_REJECT *reject;
 
 	DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
 		state->request.data.chauthtok.user));
@@ -788,6 +815,36 @@
 	oldpass = state->request.data.chauthtok.oldpass;
 	newpass = state->request.data.chauthtok.newpass;
 
+
+	if (contact_domain->active_directory &&
+	    (state->request.flags & WBFLAG_PAM_KRB5)) {
+
+		/* the error mapping is just too hard to get correct (at least at the moment) - Guenther */
+		DEBUG(3,("winbindd_pam_chauthtok: password change over Kerberos is currently disabled;"
+			"falling back to msrpc method\n"));
+
+		goto chauthtok_rpc;
+#if 0
+		ADS_STATUS status;
+
+		status = kerberos_set_password(contact_domain->dcname, user, 
+					       oldpass, user, newpass, 
+					       0);
+
+		/* derive the resulting NT_STATUS code from the ADS_ERROR */
+		result = krb5_to_nt_status(status.err.rc);
+
+		if (!ADS_ERR_OK(status)) {
+			DEBUG(0,("failed to set password using Kerberos: %s\n",
+				nt_errstr(result)));
+		}
+
+		goto done;
+#endif
+	}
+
+chauthtok_rpc:
+
 	/* Get sam handle */
 
 	result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
@@ -797,10 +854,56 @@
 		goto done;
 	}
 
-	result = rpccli_samr_chgpasswd_user(cli, state->mem_ctx, user, newpass,
-					    oldpass);
+	result = rpccli_samr_chgpasswd3(cli, state->mem_ctx, user, newpass, oldpass, &info, &reject);
 
-done:    
+	/* FIXME: need to check for other error codes ? */
+	if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION)) {
+
+		state->response.data.auth.policy.min_length_password = 
+			info->min_length_password;
+		state->response.data.auth.policy.password_history = 
+			info->password_history;
+		state->response.data.auth.policy.password_properties = 
+			info->password_properties;
+		state->response.data.auth.policy.expire = 
+			nt_time_to_unix_abs(&info->expire);
+		state->response.data.auth.policy.min_passwordage = 
+			nt_time_to_unix_abs(&info->min_passwordage);
+
+		state->response.data.auth.reject_reason = 
+			reject->reject_reason;
+
+		got_info = True;
+		
+	} else if (!NT_STATUS_IS_OK(result)) {
+
+		DEBUG(10,("Password change with chgpasswd3 failed with: %s, retrying chgpasswd_user\n", 
+			nt_errstr(result)));
+		
+		state->response.data.auth.reject_reason = 0;
+
+		result = rpccli_samr_chgpasswd_user(cli, state->mem_ctx, user, newpass, oldpass);
+	}
+
+done: 
+	if (!NT_STATUS_IS_OK(result) && !got_info) {
+
+		NTSTATUS policy_ret;
+		
+		policy_ret = fillup_password_policy(contact_domain, state);
+
+		/* failure of this is non critical, it will just provide no
+		 * additional information to the client why the change has
+		 * failed - Guenther */
+
+		if (!NT_STATUS_IS_OK(policy_ret)) {
+			DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
+			goto process_result;
+		}
+	}
+
+process_result:
+
 	state->response.data.auth.nt_status = NT_STATUS_V(result);
 	fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
 	fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));



More information about the samba-cvs mailing list