Rework our SAMR test and SAMR server.
authorAndrew Bartlett <abartlet@samba.org>
Fri, 14 Mar 2008 01:26:03 +0000 (12:26 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 14 Mar 2008 01:26:03 +0000 (12:26 +1100)
Now that we don't create users/domain groups/aliases in the builtin
domain, we hit some bugs in the server-side implementation of the
enumeration functions.

In essence, it turns out to be: don't treat 0 as a special case.

Also, fix up the PDC name to always be returned.  I'm sure nothing
actually uses it, particularly for BUILTIN...

Andrew Bartlett
(This used to be commit 353bb79f568f20c8469cb9458f7b14c24612ad23)

source4/rpc_server/samr/dcesrv_samr.c
source4/rpc_server/samr/dcesrv_samr.h
source4/torture/rpc/samr.c

index 0a5d7e1bc92c917476cd00d07e46a729d421977d..0aa4d65d8c5ca22973bbed19bfce099b25157c6e 100644 (file)
@@ -475,6 +475,14 @@ static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLO
        }
        d_state->access_mask = r->in.access_mask;
 
+       if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
+               d_state->builtin = true;
+       } else {
+               d_state->builtin = false;
+       }
+
+       d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+
        h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
        if (!h_domain) {
                talloc_free(d_state);
@@ -523,6 +531,10 @@ static NTSTATUS dcesrv_samr_info_DomInfo2(struct samr_domain_state *state,
           string */
        info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
 
+       if (!info->primary.string) {
+               info->primary.string = lp_netbios_name(state->lp_ctx);
+       }
+
        info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
                                                            0x8000000000000000LL);
 
@@ -617,6 +629,10 @@ static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
        info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, 
                                                      dom_msgs[0], "fSMORoleOwner");
 
+       if (!info->primary.string) {
+               info->primary.string = lp_netbios_name(state->lp_ctx);
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -1007,6 +1023,11 @@ static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call
 
        d_state = h->data;
 
+       if (d_state->builtin) {
+               DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        groupname = r->in.name->string;
 
        if (groupname == NULL) {
@@ -1133,9 +1154,6 @@ static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call,
        if (ldb_cnt == -1) {
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
-       if (ldb_cnt == 0 || r->in.max_size == 0) {
-               return NT_STATUS_OK;
-       }
 
        /* convert to SamEntry format */
        entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
@@ -1169,10 +1187,6 @@ static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call,
             first<count && entries[first].idx <= *r->in.resume_handle;
             first++) ;
 
-       if (first == count) {
-               return NT_STATUS_OK;
-       }
-
        /* return the rest, limit by max_size. Note that we 
           use the w2k3 element size value of 54 */
        r->out.num_entries = count - first;
@@ -1237,6 +1251,10 @@ static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALL
 
        d_state = h->data;
 
+       if (d_state->builtin) {
+               DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
+               return NT_STATUS_ACCESS_DENIED;
+       }
        account_name = r->in.account_name->string;
 
        if (account_name == NULL) {
@@ -1321,15 +1339,16 @@ static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALL
        /* create the user */
        ret = ldb_add(d_state->sam_ctx, msg);
        switch (ret) {
-       case  LDB_SUCCESS:
+       case LDB_SUCCESS:
                break;
-       case  LDB_ERR_ENTRY_ALREADY_EXISTS:
+       case LDB_ERR_ENTRY_ALREADY_EXISTS:
                ldb_transaction_cancel(d_state->sam_ctx);
                DEBUG(0,("Failed to create user record %s: %s\n",
                         ldb_dn_get_linearized(msg->dn),
                         ldb_errstring(d_state->sam_ctx)));
                return NT_STATUS_USER_EXISTS;
-       case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+       case LDB_ERR_UNWILLING_TO_PERFORM:
+       case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
                ldb_transaction_cancel(d_state->sam_ctx);
                DEBUG(0,("Failed to create user record %s: %s\n",
                         ldb_dn_get_linearized(msg->dn),
@@ -1469,8 +1488,8 @@ static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call,
 {
        struct dcesrv_handle *h;
        struct samr_domain_state *d_state;
-       struct ldb_message **res;
-       int count, num_filtered_entries, i, first;
+       struct ldb_result *res;
+       int ret, num_filtered_entries, i, first;
        struct samr_SamEntry *entries;
        const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL };
 
@@ -1482,32 +1501,30 @@ static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call,
 
        d_state = h->data;
        
-       /* search for all users in this domain. This could possibly be cached and 
-          resumed based on resume_key */
-       count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
-                            "objectclass=user");
-       if (count == -1) {
+       /* don't have to worry about users in the builtin domain, as there are none */
+       ret = ldb_search_exp_fmt(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(3, ("Failed to search for Domain Users in %s: %s\n", 
+                         ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
-       if (count == 0 || r->in.max_size == 0) {
-               return NT_STATUS_OK;
-       }
 
        /* convert to SamEntry format */
-       entries = talloc_array(mem_ctx, struct samr_SamEntry, count);
+       entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
        if (!entries) {
                return NT_STATUS_NO_MEMORY;
        }
        num_filtered_entries = 0;
-       for (i=0;i<count;i++) {
+       for (i=0;i<res->count;i++) {
                /* Check if a mask has been requested */
                if (r->in.acct_flags
-                   && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res[i], 
+                   && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i], 
                                                 d_state->domain_dn) & r->in.acct_flags) == 0)) {
                        continue;
                }
-               entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
-               entries[num_filtered_entries].name.string = samdb_result_string(res[i], "sAMAccountName", "");
+               entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
+               entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
                num_filtered_entries++;
        }
 
@@ -1569,6 +1586,11 @@ static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, T
 
        d_state = h->data;
 
+       if (d_state->builtin) {
+               DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        alias_name = r->in.alias_name->string;
 
        if (alias_name == NULL) {
index 7a6978344be852911ba2342771d8d6886f8e30a8..a28a4bec437ea88108261e7b245dea2ca079e21e 100644 (file)
@@ -52,6 +52,8 @@ struct samr_domain_state {
        const char *domain_name;
        struct ldb_dn *domain_dn;
        enum server_role role;
+       bool builtin;
+       struct loadparm_context *lp_ctx;
 };
 
 /*
index 1d6ec4339987e3cd0fb60e828efa35f67df2649f..55c75ba270eb415cc0227e8986516ea18e32fbcc 100644 (file)
@@ -2332,9 +2332,15 @@ static bool test_CreateAlias(struct dcerpc_pipe *p, struct torture_context *tctx
 
        status = dcerpc_samr_CreateDomAlias(p, tctx, &r);
 
-       if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
-               printf("Server refused create of '%s'\n", r.in.alias_name->string);
-               return true;
+       if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) {
+               if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+                       printf("Server correctly refused create of '%s'\n", r.in.alias_name->string);
+                       return true;
+               } else {
+                       printf("Server should have refused create of '%s', got %s instead\n", r.in.alias_name->string, 
+                              nt_errstr(status));
+                       return false;
+               }
        }
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_ALIAS_EXISTS)) {
@@ -2515,7 +2521,8 @@ static bool test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
 
 static bool test_CreateUser(struct dcerpc_pipe *p, struct torture_context *tctx,
                            struct policy_handle *domain_handle, 
-                           struct policy_handle *user_handle_out, 
+                           struct policy_handle *user_handle_out,
+                           struct dom_sid *domain_sid, 
                            enum torture_samr_choice which_ops)
 {
 
@@ -2546,10 +2553,15 @@ static bool test_CreateUser(struct dcerpc_pipe *p, struct torture_context *tctx,
 
        status = dcerpc_samr_CreateUser(p, user_ctx, &r);
 
-       if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
-               printf("Server refused create of '%s': %s\n", r.in.account_name->string, nt_errstr(status));
-               talloc_free(user_ctx);
-               return true;
+       if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) {
+               if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+                       printf("Server correctly refused create of '%s'\n", r.in.account_name->string);
+                       return true;
+               } else {
+                       printf("Server should have refused create of '%s', got %s instead\n", r.in.account_name->string, 
+                              nt_errstr(status));
+                       return false;
+               }
        }
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
@@ -2610,7 +2622,9 @@ static bool test_CreateUser(struct dcerpc_pipe *p, struct torture_context *tctx,
 
 
 static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx,
-                            struct policy_handle *domain_handle, enum torture_samr_choice which_ops)
+                            struct policy_handle *domain_handle,
+                            struct dom_sid *domain_sid,
+                            enum torture_samr_choice which_ops)
 {
        NTSTATUS status;
        struct samr_CreateUser2 r;
@@ -2663,12 +2677,19 @@ static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx
                
                status = dcerpc_samr_CreateUser2(p, user_ctx, &r);
                
-               if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
-                       talloc_free(user_ctx);
-                       printf("Server refused create of '%s'\n", r.in.account_name->string);
-                       continue;
+               if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) {
+                       if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+                               printf("Server correctly refused create of '%s'\n", r.in.account_name->string);
+                               continue;
+                       } else {
+                               printf("Server should have refused create of '%s', got %s instead\n", r.in.account_name->string, 
+                                      nt_errstr(status));
+                               ret = false;
+                               continue;
+                       }
+               }
 
-               } else if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
+               if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
                        if (!test_DeleteUser_byname(p, user_ctx, domain_handle, r.in.account_name->string)) {
                                talloc_free(user_ctx);
                                ret = false;
@@ -3893,6 +3914,7 @@ static bool test_GroupList(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        }
        
        if (!q1.out.sam) {
+               printf("EnumDomainGroups failed to return q1.out.sam\n");
                return false;
        }
 
@@ -4138,7 +4160,9 @@ static bool test_AddGroupMember(struct dcerpc_pipe *p, struct torture_context *t
 
 
 static bool test_CreateDomainGroup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
-                                  struct policy_handle *domain_handle, struct policy_handle *group_handle)
+                                  struct policy_handle *domain_handle, 
+                                  struct policy_handle *group_handle,
+                                  struct dom_sid *domain_sid)
 {
        NTSTATUS status;
        struct samr_CreateDomainGroup r;
@@ -4158,15 +4182,19 @@ static bool test_CreateDomainGroup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
 
        status = dcerpc_samr_CreateDomainGroup(p, mem_ctx, &r);
 
-       if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
-               printf("Server refused create of '%s'\n", r.in.name->string);
-               ZERO_STRUCTP(group_handle);
-               return true;
+       if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
+               if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+                       printf("Server correctly refused create of '%s'\n", r.in.name->string);
+                       return true;
+               } else {
+                       printf("Server should have refused create of '%s', got %s instead\n", r.in.name->string, 
+                              nt_errstr(status));
+                       return false;
+               }
        }
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_GROUP_EXISTS)) {
                if (!test_DeleteGroup_byname(p, mem_ctx, domain_handle, r.in.name->string)) {
-                       
                        printf("CreateDomainGroup failed: Could not delete domain group %s - %s\n", r.in.name->string, 
                               nt_errstr(status));
                        return false;
@@ -4244,7 +4272,7 @@ static bool test_OpenDomain(struct dcerpc_pipe *p, struct torture_context *tctx,
        ZERO_STRUCT(group_handle);
        ZERO_STRUCT(domain_handle);
 
-       printf("Testing OpenDomain\n");
+       printf("Testing OpenDomain of %s\n", dom_sid_string(tctx, sid));
 
        r.in.connect_handle = handle;
        r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
@@ -4264,17 +4292,23 @@ static bool test_OpenDomain(struct dcerpc_pipe *p, struct torture_context *tctx,
        switch (which_ops) {
        case TORTURE_SAMR_USER_ATTRIBUTES:
        case TORTURE_SAMR_PASSWORDS:
-               ret &= test_CreateUser2(p, tctx, &domain_handle, which_ops);
-               ret &= test_CreateUser(p, tctx, &domain_handle, &user_handle, which_ops);
+               ret &= test_CreateUser2(p, tctx, &domain_handle, sid, which_ops);
+               ret &= test_CreateUser(p, tctx, &domain_handle, &user_handle, sid, which_ops);
                /* This test needs 'complex' users to validate */
                ret &= test_QueryDisplayInfo(p, tctx, &domain_handle);
+               if (!ret) {
+                       printf("Testing PASSWORDS or ATTRIBUTES on domain %s failed!\n", dom_sid_string(tctx, sid));
+               }
                break;
        case TORTURE_SAMR_OTHER:
-               ret &= test_CreateUser(p, tctx, &domain_handle, &user_handle, which_ops);
+               ret &= test_CreateUser(p, tctx, &domain_handle, &user_handle, sid, which_ops);
+               if (!ret) {
+                       printf("Failed to CreateUser in SAMR-OTHER on domain %s!\n", dom_sid_string(tctx, sid));
+               }
                ret &= test_QuerySecurity(p, tctx, &domain_handle);
                ret &= test_RemoveMemberFromForeignDomain(p, tctx, &domain_handle);
                ret &= test_CreateAlias(p, tctx, &domain_handle, &alias_handle, sid);
-               ret &= test_CreateDomainGroup(p, tctx, &domain_handle, &group_handle);
+               ret &= test_CreateDomainGroup(p, tctx, &domain_handle, &group_handle, sid);
                ret &= test_QueryDomainInfo(p, tctx, &domain_handle);
                ret &= test_QueryDomainInfo2(p, tctx, &domain_handle);
                ret &= test_EnumDomainUsers(p, tctx, &domain_handle);
@@ -4295,6 +4329,9 @@ static bool test_OpenDomain(struct dcerpc_pipe *p, struct torture_context *tctx,
                ret &= test_TestPrivateFunctionsDomain(p, tctx, &domain_handle);
                ret &= test_RidToSid(p, tctx, sid, &domain_handle);
                ret &= test_GetBootKeyInformation(p, tctx, &domain_handle);
+               if (!ret) {
+                       printf("Testing SAMR-OTHER on domain %s failed!\n", dom_sid_string(tctx, sid));
+               }
                break;
        }