svn commit: samba r24052 - in branches/SAMBA_4_0/source: librpc/idl rpc_server/samr torture/rpc

abartlet at samba.org abartlet at samba.org
Thu Jul 26 03:50:26 GMT 2007


Author: abartlet
Date: 2007-07-26 03:50:24 +0000 (Thu, 26 Jul 2007)
New Revision: 24052

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

Log:
Fix some of the NT4 usrmgr.exe portions of bug 4815.

 - The icons in usermgr were incorrect, because the acct_flags were
   not filled in (due to missing attribute in ldb query)

 - The Full name was missing, and the description used as the full
   name (due to missing attributes in ldb query and incorrect IDL)

To prove the correctness of these fixes, I added a substantial new
test to RPC-SAMR-USERS, to ensure cross-consistancy between
QueryDisplayInfo and QueryUserInfo on each user.

This showed that for some reason, we must add ACB_NORMAL to the
acct_flags on level 2 queries (for machine trust accounts)...

Getting this right is important, because Samba3's RPC winbind methods
uses these queries.

Andrew Bartlett

Modified:
   branches/SAMBA_4_0/source/librpc/idl/samr.idl
   branches/SAMBA_4_0/source/rpc_server/samr/dcesrv_samr.c
   branches/SAMBA_4_0/source/torture/rpc/samr.c


Changeset:
Modified: branches/SAMBA_4_0/source/librpc/idl/samr.idl
===================================================================
--- branches/SAMBA_4_0/source/librpc/idl/samr.idl	2007-07-25 23:17:02 UTC (rev 24051)
+++ branches/SAMBA_4_0/source/librpc/idl/samr.idl	2007-07-26 03:50:24 UTC (rev 24052)
@@ -871,8 +871,8 @@
 		uint32    rid;
 		samr_AcctFlags acct_flags;
 		lsa_String account_name;
+		lsa_String description;
 		lsa_String full_name;
-		lsa_String description;
 	} samr_DispEntryGeneral;
 
 	typedef struct {

Modified: branches/SAMBA_4_0/source/rpc_server/samr/dcesrv_samr.c
===================================================================
--- branches/SAMBA_4_0/source/rpc_server/samr/dcesrv_samr.c	2007-07-25 23:17:02 UTC (rev 24051)
+++ branches/SAMBA_4_0/source/rpc_server/samr/dcesrv_samr.c	2007-07-26 03:50:24 UTC (rev 24052)
@@ -508,7 +508,7 @@
 		break;
 	}
 
-	/* TODO: Should these filter on SID, to avoid counting BUILTIN? */
+	/* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
 	info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn, 
 					     "(objectClass=user)");
 	info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
@@ -3573,8 +3573,8 @@
 	struct samr_domain_state *d_state;
 	struct ldb_message **res;
 	int ldb_cnt, count, i;
-	const char * const attrs[4] = { "objectSid", "sAMAccountName",
-					"description", NULL };
+	const char * const attrs[] = { "objectSid", "sAMAccountName", "displayName",
+					"description", "userAccountControl", NULL };
 	struct samr_DispEntryFull *entriesFull = NULL;
 	struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
 	struct samr_DispEntryAscii *entriesAscii = NULL;
@@ -3674,12 +3674,21 @@
 				samdb_result_string(res[i], "description", "");
 			break;
 		case 2:
+			if (!(samdb_result_acct_flags(res[i], 
+						      "userAccountControl") & ACB_WSTRUST)) {
+				/* Domain controllers match the
+				 * filter, but should not be included
+				 * in the output */
+				continue;
+			}
 			entriesFull[count].idx = count + 1;
 			entriesFull[count].rid =
 				objectsid->sub_auths[objectsid->num_auths-1];
+
+			/* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
 			entriesFull[count].acct_flags =
 				samdb_result_acct_flags(res[i], 
-							"userAccountControl");
+							"userAccountControl") | ACB_NORMAL;
 			entriesFull[count].account_name.string =
 				samdb_result_string(res[i], "sAMAccountName",
 						    "");

Modified: branches/SAMBA_4_0/source/torture/rpc/samr.c
===================================================================
--- branches/SAMBA_4_0/source/torture/rpc/samr.c	2007-07-25 23:17:02 UTC (rev 24051)
+++ branches/SAMBA_4_0/source/torture/rpc/samr.c	2007-07-26 03:50:24 UTC (rev 24052)
@@ -3124,30 +3124,213 @@
 	return ret;	
 }
 
+#define STRING_EQUAL_QUERY(s1, s2, user)					\
+	if (s1.string == NULL && s2.string != NULL && s2.string[0] == '\0') { \
+		/* odd, but valid */						\
+	} else if ((s1.string && !s2.string) || (s2.string && !s1.string) || strcmp(s1.string, s2.string)) { \
+			printf("%s mismatch for %s: %s != %s (%s)\n", \
+			       #s1, user.string,  s1.string, s2.string, __location__);   \
+			ret = False; \
+	}
+#define INT_EQUAL_QUERY(s1, s2, user)		\
+		if (s1 != s2) { \
+			printf("%s mismatch for %s: 0x%x != 0x%x (%s)\n", \
+			       #s1, user.string, (unsigned int)s1, (unsigned int)s2, __location__); \
+			ret = False; \
+		}
+
+static BOOL test_each_DisplayInfo_user(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+				       struct samr_QueryDisplayInfo *querydisplayinfo,
+				       bool *seen_testuser) 
+{
+	struct samr_OpenUser r;
+	struct samr_QueryUserInfo q;
+	struct policy_handle user_handle;
+	int i, ret = True;
+	NTSTATUS status;
+	r.in.domain_handle = querydisplayinfo->in.domain_handle;
+	r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+	for (i = 0; ; i++) {
+		switch (querydisplayinfo->in.level) {
+		case 1:
+			if (i >= querydisplayinfo->out.info.info1.count) {
+				return ret;
+			}
+			r.in.rid = querydisplayinfo->out.info.info1.entries[i].rid;
+			break;
+		case 2:
+			if (i >= querydisplayinfo->out.info.info2.count) {
+				return ret;
+			}
+			r.in.rid = querydisplayinfo->out.info.info2.entries[i].rid;
+			break;
+		case 3:
+			/* Groups */
+		case 4:
+		case 5:
+			/* Not interested in validating just the account name */
+			return true;
+		}
+			
+		r.out.user_handle = &user_handle;
+		
+		switch (querydisplayinfo->in.level) {
+		case 1:
+		case 2:
+			status = dcerpc_samr_OpenUser(p, mem_ctx, &r);
+			if (!NT_STATUS_IS_OK(status)) {
+				printf("OpenUser(%u) failed - %s\n", r.in.rid, nt_errstr(status));
+				return False;
+			}
+		}
+		
+		q.in.user_handle = &user_handle;
+		q.in.level = 21;
+		status = dcerpc_samr_QueryUserInfo(p, mem_ctx, &q);
+		if (!NT_STATUS_IS_OK(status)) {
+			printf("QueryUserInfo(%u) failed - %s\n", r.in.rid, nt_errstr(status));
+			return False;
+		}
+		
+		switch (querydisplayinfo->in.level) {
+		case 1:
+			if (seen_testuser && strcmp(q.out.info->info21.account_name.string, TEST_ACCOUNT_NAME) == 0) {
+				*seen_testuser = true;
+			}
+			STRING_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].full_name, 
+					   q.out.info->info21.full_name, q.out.info->info21.account_name);
+			STRING_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].account_name, 
+					   q.out.info->info21.account_name, q.out.info->info21.account_name);
+			STRING_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].description, 
+					   q.out.info->info21.description, q.out.info->info21.account_name);
+			INT_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].rid, 
+					q.out.info->info21.rid, q.out.info->info21.account_name);
+			INT_EQUAL_QUERY(querydisplayinfo->out.info.info1.entries[i].acct_flags, 
+					q.out.info->info21.acct_flags, q.out.info->info21.account_name);
+			
+			break;
+		case 2:
+			STRING_EQUAL_QUERY(querydisplayinfo->out.info.info2.entries[i].account_name, 
+					   q.out.info->info21.account_name, q.out.info->info21.account_name);
+			STRING_EQUAL_QUERY(querydisplayinfo->out.info.info2.entries[i].description, 
+					   q.out.info->info21.description, q.out.info->info21.account_name);
+			INT_EQUAL_QUERY(querydisplayinfo->out.info.info2.entries[i].rid, 
+					q.out.info->info21.rid, q.out.info->info21.account_name);
+			INT_EQUAL_QUERY((querydisplayinfo->out.info.info2.entries[i].acct_flags & ~ACB_NORMAL), 
+					q.out.info->info21.acct_flags, q.out.info->info21.account_name);
+			
+			if (!(querydisplayinfo->out.info.info2.entries[i].acct_flags & ACB_NORMAL)) {
+				printf("Missing ACB_NORMAL in querydisplayinfo->out.info.info2.entries[i].acct_flags on %s\n", 
+				       q.out.info->info21.account_name.string);
+			}
+
+			if (!(q.out.info->info21.acct_flags & (ACB_WSTRUST))) {
+				printf("Found non-trust account %s in trust accoutn listing: 0x%x 0x%x\n",
+				       q.out.info->info21.account_name.string,
+				       querydisplayinfo->out.info.info2.entries[i].acct_flags,
+				       q.out.info->info21.acct_flags);
+				return False;
+			}
+			
+			break;
+		}
+		
+		if (!test_samr_handle_Close(p, mem_ctx, &user_handle)) {
+			return False;
+		}
+	}
+	return ret;
+}
+
 static BOOL test_QueryDisplayInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
 				  struct policy_handle *handle)
 {
 	NTSTATUS status;
 	struct samr_QueryDisplayInfo r;
+	struct samr_QueryDomainInfo dom_info;
 	BOOL ret = True;
 	uint16_t levels[] = {1, 2, 3, 4, 5};
 	int i;
+	bool seen_testuser = false;
 
 	for (i=0;i<ARRAY_SIZE(levels);i++) {
 		printf("Testing QueryDisplayInfo level %u\n", levels[i]);
 
-		r.in.domain_handle = handle;
-		r.in.level = levels[i];
 		r.in.start_idx = 0;
-		r.in.max_entries = 1000;
-		r.in.buf_size = (uint32_t)-1;
-
-		status = dcerpc_samr_QueryDisplayInfo(p, mem_ctx, &r);
+		status = STATUS_MORE_ENTRIES;
+		while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+			r.in.domain_handle = handle;
+			r.in.level = levels[i];
+			r.in.max_entries = 2;
+			r.in.buf_size = (uint32_t)-1;
+			
+			status = dcerpc_samr_QueryDisplayInfo(p, mem_ctx, &r);
+			if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) && !NT_STATUS_IS_OK(status)) {
+				printf("QueryDisplayInfo level %u failed - %s\n", 
+				       levels[i], nt_errstr(status));
+				ret = False;
+			}
+			switch (r.in.level) {
+			case 1:
+				if (!test_each_DisplayInfo_user(p, mem_ctx, &r, &seen_testuser)) {
+					ret = False;
+				}
+				r.in.start_idx += r.out.info.info1.count;
+				break;
+			case 2:
+				if (!test_each_DisplayInfo_user(p, mem_ctx, &r, NULL)) {
+					ret = False;
+				}
+				r.in.start_idx += r.out.info.info2.count;
+				break;
+			case 3:
+				r.in.start_idx += r.out.info.info3.count;
+				break;
+			case 4:
+				r.in.start_idx += r.out.info.info4.count;
+				break;
+			case 5:
+				r.in.start_idx += r.out.info.info5.count;
+				break;
+			}
+		}
+		dom_info.in.domain_handle = handle;
+		dom_info.in.level = 2;
+		/* Check number of users returned is correct */
+		status = dcerpc_samr_QueryDomainInfo(p, mem_ctx, &dom_info);
 		if (!NT_STATUS_IS_OK(status)) {
-			printf("QueryDisplayInfo level %u failed - %s\n", 
-			       levels[i], nt_errstr(status));
-			ret = False;
+			printf("QueryDomainInfo level %u failed - %s\n", 
+			       r.in.level, nt_errstr(status));
+				ret = False;
+				break;
 		}
+		switch (r.in.level) {
+		case 1:
+		case 4:
+			if (dom_info.out.info->info2.num_users < r.in.start_idx) {
+				printf("QueryDomainInfo indicates that QueryDisplayInfo returned more users (%d/%d) than the domain %s is said to contain!\n",
+				       r.in.start_idx, dom_info.out.info->info2.num_groups,
+				       dom_info.out.info->info2.domain_name.string);
+				ret = False;
+			}
+			if (!seen_testuser) {
+				printf("Didn't find test user " TEST_ACCOUNT_NAME " in enumeration of %s\n", 
+				       dom_info.out.info->info2.domain_name.string);
+				ret = False;
+			}
+			break;
+		case 3:
+		case 5:
+			if (dom_info.out.info->info2.num_groups != r.in.start_idx) {
+				printf("QueryDomainInfo indicates that QueryDisplayInfo didn't return all (%d/%d) the groups in %s\n",
+				       r.in.start_idx, dom_info.out.info->info2.num_groups,
+				       dom_info.out.info->info2.domain_name.string);
+				ret = False;
+			}
+			
+			break;
+		}
+
 	}
 	
 	return ret;	
@@ -3811,8 +3994,10 @@
 	switch (which_ops) {
 	case TORTURE_SAMR_USER_ATTRIBUTES:
 	case TORTURE_SAMR_PASSWORDS:
-		ret &= test_CreateUser(p, mem_ctx, &domain_handle, NULL, which_ops);
 		ret &= test_CreateUser2(p, mem_ctx, &domain_handle, which_ops);
+		ret &= test_CreateUser(p, mem_ctx, &domain_handle, &user_handle, which_ops);
+		/* This test needs 'complex' users to validate */
+		ret &= test_QueryDisplayInfo(p, mem_ctx, &domain_handle);
 		break;
 	case TORTURE_SAMR_OTHER:
 		ret &= test_CreateUser(p, mem_ctx, &domain_handle, &user_handle, which_ops);
@@ -3826,7 +4011,6 @@
 		ret &= test_EnumDomainUsers_async(p, mem_ctx, &domain_handle);
 		ret &= test_EnumDomainGroups(p, mem_ctx, &domain_handle);
 		ret &= test_EnumDomainAliases(p, mem_ctx, &domain_handle);
-		ret &= test_QueryDisplayInfo(p, mem_ctx, &domain_handle);
 		ret &= test_QueryDisplayInfo2(p, mem_ctx, &domain_handle);
 		ret &= test_QueryDisplayInfo3(p, mem_ctx, &domain_handle);
 		ret &= test_QueryDisplayInfo_continue(p, mem_ctx, &domain_handle);



More information about the samba-cvs mailing list