s4-smbtorture: test whether an lsa_EnumTrustDom implementation would hang up a client.
[ira/wip.git] / source4 / torture / rpc / lsa.c
index 0ce75d8a86bfbb0341b4c25c630e29c97cb1708c..710f4c53d2f4b403ccaf071b0e100f5a72b9bb48 100644 (file)
@@ -202,12 +202,22 @@ static bool test_LookupNames(struct dcerpc_pipe *p,
        }
 
        for (i=0;i< tnames->count;i++) {
-               if (i < count && sids.sids[i].sid_type != tnames->names[i].sid_type) {
-                       torture_comment(tctx, "LookupName of %s got unexpected name type: %s\n",
-                              tnames->names[i].name.string, sid_type_lookup(sids.sids[i].sid_type));
+               if (i < count) {
+                       if (sids.sids[i].sid_type != tnames->names[i].sid_type) {
+                               torture_comment(tctx, "LookupName of %s got unexpected name type: %s\n",
+                                      tnames->names[i].name.string, sid_type_lookup(sids.sids[i].sid_type));
+                               return false;
+                       }
+                       if ((sids.sids[i].sid_type == SID_NAME_DOMAIN) &&
+                           (sids.sids[i].rid != (uint32_t)-1)) {
+                               torture_comment(tctx, "LookupName of %s got unexpected rid: %d\n",
+                                       tnames->names[i].name.string, sids.sids[i].rid);
+                               return false;
+                       }
                } else if (i >=count) {
                        torture_comment(tctx, "LookupName of %s failed to return a result\n",
                               tnames->names[i].name.string);
+                       return false;
                }
        }
        torture_comment(tctx, "\n");
@@ -222,31 +232,19 @@ static bool test_LookupNames_bogus(struct dcerpc_pipe *p,
        struct lsa_LookupNames r;
        struct lsa_TransSidArray sids;
        struct lsa_RefDomainList *domains = NULL;
-       struct lsa_String *names;
+       struct lsa_String names[1];
        uint32_t count = 0;
        NTSTATUS status;
-       int i;
-
-       struct lsa_TranslatedName name[2];
-       struct lsa_TransNameArray tnames;
 
-       tnames.names = name;
-       tnames.count = 2;
-       name[0].name.string = "NT AUTHORITY\\BOGUS";
-       name[1].name.string = NULL;
-
-       torture_comment(tctx, "\nTesting LookupNames with bogus names\n");
+       torture_comment(tctx, "\nTesting LookupNames with bogus name\n");
 
        sids.count = 0;
        sids.sids = NULL;
 
-       names = talloc_array(tctx, struct lsa_String, tnames.count);
-       for (i=0;i<tnames.count;i++) {
-               init_lsa_String(&names[i], tnames.names[i].name.string);
-       }
+       init_lsa_String(&names[0], "NT AUTHORITY\\BOGUS");
 
        r.in.handle = handle;
-       r.in.num_names = tnames.count;
+       r.in.num_names = 1;
        r.in.names = names;
        r.in.sids = &sids;
        r.in.level = 1;
@@ -266,6 +264,48 @@ static bool test_LookupNames_bogus(struct dcerpc_pipe *p,
        return true;
 }
 
+static bool test_LookupNames_NULL(struct dcerpc_pipe *p,
+                                 struct torture_context *tctx,
+                                 struct policy_handle *handle)
+{
+       struct lsa_LookupNames r;
+       struct lsa_TransSidArray sids;
+       struct lsa_RefDomainList *domains = NULL;
+       struct lsa_String names[1];
+       uint32_t count = 0;
+
+       torture_comment(tctx, "\nTesting LookupNames with NULL name\n");
+
+       sids.count = 0;
+       sids.sids = NULL;
+
+       names[0].string = NULL;
+
+       r.in.handle = handle;
+       r.in.num_names = 1;
+       r.in.names = names;
+       r.in.sids = &sids;
+       r.in.level = 1;
+       r.in.count = &count;
+       r.out.count = &count;
+       r.out.sids = &sids;
+       r.out.domains = &domains;
+
+       /* nt4 returns NT_STATUS_NONE_MAPPED with sid_type
+        * SID_NAME_UNKNOWN, rid 0, and sid_index -1;
+        *
+        * w2k3/w2k8 return NT_STATUS_OK with sid_type
+        * SID_NAME_DOMAIN, rid -1 and sid_index 0 and BUILTIN domain
+        */
+
+       torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupNames(p, tctx, &r),
+               "LookupNames with NULL name failed");
+
+       torture_comment(tctx, "\n");
+
+       return true;
+}
+
 static bool test_LookupNames_wellknown(struct dcerpc_pipe *p,
                                       struct torture_context *tctx,
                                       struct policy_handle *handle)
@@ -1985,23 +2025,40 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,
                              struct policy_handle *handle)
 {
        struct lsa_EnumTrustDom r;
-       struct lsa_EnumTrustedDomainsEx r_ex;
        NTSTATUS enum_status;
-       uint32_t resume_handle = 0;
+       uint32_t in_resume_handle = 0;
+       uint32_t out_resume_handle;
        struct lsa_DomainList domains;
-       struct lsa_DomainListEx domains_ex;
        bool ret = true;
 
        torture_comment(tctx, "\nTesting EnumTrustDom\n");
 
        r.in.handle = handle;
-       r.in.resume_handle = &resume_handle;
+       r.in.resume_handle = &in_resume_handle;
        r.in.max_size = 0;
        r.out.domains = &domains;
-       r.out.resume_handle = &resume_handle;
+       r.out.resume_handle = &out_resume_handle;
 
        enum_status = dcerpc_lsa_EnumTrustDom(p, tctx, &r);
 
+       /* according to MS-LSAD 3.1.4.7.8 output resume handle MUST
+        * always be larger than the previous input resume handle, in
+        * particular when hitting the last query it is vital to set the
+        * resume handle correctly to avoid infinite client loops, as
+        * seen e.g.  with Windows XP SP3 when resume handle is 0 and
+        * status is NT_STATUS_OK - gd */
+
+       if (NT_STATUS_IS_OK(enum_status) ||
+           NT_STATUS_EQUAL(enum_status, NT_STATUS_NO_MORE_ENTRIES) ||
+           NT_STATUS_EQUAL(enum_status, STATUS_MORE_ENTRIES))
+       {
+               if (out_resume_handle <= in_resume_handle) {
+                       torture_comment(tctx, "EnumTrustDom failed - should have returned output resume_handle (0x%08x) larger than input resume handle (0x%08x)\n",
+                               out_resume_handle, in_resume_handle);
+                       return false;
+               }
+       }
+
        if (NT_STATUS_IS_OK(enum_status)) {
                if (domains.count == 0) {
                        torture_comment(tctx, "EnumTrustDom failed - should have returned 'NT_STATUS_NO_MORE_ENTRIES' for 0 trusted domains\n");
@@ -2013,17 +2070,35 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,
        }
 
        /* Start from the bottom again */
-       resume_handle = 0;
+       in_resume_handle = 0;
 
        do {
                r.in.handle = handle;
-               r.in.resume_handle = &resume_handle;
+               r.in.resume_handle = &in_resume_handle;
                r.in.max_size = LSA_ENUM_TRUST_DOMAIN_MULTIPLIER * 3;
                r.out.domains = &domains;
-               r.out.resume_handle = &resume_handle;
+               r.out.resume_handle = &out_resume_handle;
 
                enum_status = dcerpc_lsa_EnumTrustDom(p, tctx, &r);
 
+               /* according to MS-LSAD 3.1.4.7.8 output resume handle MUST
+                * always be larger than the previous input resume handle, in
+                * particular when hitting the last query it is vital to set the
+                * resume handle correctly to avoid infinite client loops, as
+                * seen e.g.  with Windows XP SP3 when resume handle is 0 and
+                * status is NT_STATUS_OK - gd */
+
+               if (NT_STATUS_IS_OK(enum_status) ||
+                   NT_STATUS_EQUAL(enum_status, NT_STATUS_NO_MORE_ENTRIES) ||
+                   NT_STATUS_EQUAL(enum_status, STATUS_MORE_ENTRIES))
+               {
+                       if (out_resume_handle <= in_resume_handle) {
+                               torture_comment(tctx, "EnumTrustDom failed - should have returned output resume_handle (0x%08x) larger than input resume handle (0x%08x)\n",
+                                       out_resume_handle, in_resume_handle);
+                               return false;
+                       }
+               }
+
                /* NO_MORE_ENTRIES is allowed */
                if (NT_STATUS_EQUAL(enum_status, NT_STATUS_NO_MORE_ENTRIES)) {
                        if (domains.count == 0) {
@@ -2052,8 +2127,23 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,
 
                ret &= test_query_each_TrustDom(p, tctx, handle, &domains);
 
+               in_resume_handle = out_resume_handle;
+
        } while ((NT_STATUS_EQUAL(enum_status, STATUS_MORE_ENTRIES)));
 
+       return ret;
+}
+
+static bool test_EnumTrustDomEx(struct dcerpc_pipe *p,
+                               struct torture_context *tctx,
+                               struct policy_handle *handle)
+{
+       struct lsa_EnumTrustedDomainsEx r_ex;
+       NTSTATUS enum_status;
+       uint32_t resume_handle = 0;
+       struct lsa_DomainListEx domains_ex;
+       bool ret = true;
+
        torture_comment(tctx, "\nTesting EnumTrustedDomainsEx\n");
 
        r_ex.in.handle = handle;
@@ -2113,27 +2203,36 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,
        return ret;
 }
 
+
 static bool test_CreateTrustedDomain(struct dcerpc_pipe *p,
                                     struct torture_context *tctx,
-                                    struct policy_handle *handle)
+                                    struct policy_handle *handle,
+                                    uint32_t num_trusts)
 {
        NTSTATUS status;
        bool ret = true;
        struct lsa_CreateTrustedDomain r;
        struct lsa_DomainInfo trustinfo;
-       struct dom_sid *domsid[12];
-       struct policy_handle trustdom_handle[12];
+       struct dom_sid **domsid;
+       struct policy_handle *trustdom_handle;
        struct lsa_QueryTrustedDomainInfo q;
        union lsa_TrustedDomainInfo *info = NULL;
        int i;
 
-       torture_comment(tctx, "\nTesting CreateTrustedDomain for 12 domains\n");
+       torture_comment(tctx, "\nTesting CreateTrustedDomain for %d domains\n", num_trusts);
 
        if (!test_EnumTrustDom(p, tctx, handle)) {
                ret = false;
        }
 
-       for (i=0; i< 12; i++) {
+       if (!test_EnumTrustDomEx(p, tctx, handle)) {
+               ret = false;
+       }
+
+       domsid = talloc_array(tctx, struct dom_sid *, num_trusts);
+       trustdom_handle = talloc_array(tctx, struct policy_handle, num_trusts);
+
+       for (i=0; i< num_trusts; i++) {
                char *trust_name = talloc_asprintf(tctx, "torturedom%02d", i);
                char *trust_sid = talloc_asprintf(tctx, "S-1-5-21-97398-379795-100%02d", i);
 
@@ -2162,7 +2261,7 @@ static bool test_CreateTrustedDomain(struct dcerpc_pipe *p,
                        q.out.info = &info;
                        status = dcerpc_lsa_QueryTrustedDomainInfo(p, tctx, &q);
                        if (!NT_STATUS_IS_OK(status)) {
-                               torture_comment(tctx, "QueryTrustedDomainInfo level 1 failed - %s\n", nt_errstr(status));
+                               torture_comment(tctx, "QueryTrustedDomainInfo level %d failed - %s\n", q.in.level, nt_errstr(status));
                                ret = false;
                        } else if (!q.out.info) {
                                ret = false;
@@ -2196,7 +2295,11 @@ static bool test_CreateTrustedDomain(struct dcerpc_pipe *p,
                ret = false;
        }
 
-       for (i=0; i<12; i++) {
+       if (!test_EnumTrustDomEx(p, tctx, handle)) {
+               ret = false;
+       }
+
+       for (i=0; i<num_trusts; i++) {
                if (!test_DeleteTrustedDomainBySid(p, tctx, handle, domsid[i])) {
                        ret = false;
                }
@@ -2207,7 +2310,8 @@ static bool test_CreateTrustedDomain(struct dcerpc_pipe *p,
 
 static bool test_CreateTrustedDomainEx2(struct dcerpc_pipe *p,
                                        struct torture_context *tctx,
-                                       struct policy_handle *handle)
+                                       struct policy_handle *handle,
+                                       uint32_t num_trusts)
 {
        NTSTATUS status;
        bool ret = true;
@@ -2216,15 +2320,18 @@ static bool test_CreateTrustedDomainEx2(struct dcerpc_pipe *p,
        struct lsa_TrustDomainInfoAuthInfoInternal authinfo;
        struct trustDomainPasswords auth_struct;
        DATA_BLOB auth_blob;
-       struct dom_sid *domsid[12];
-       struct policy_handle trustdom_handle[12];
+       struct dom_sid **domsid;
+       struct policy_handle *trustdom_handle;
        struct lsa_QueryTrustedDomainInfo q;
        union lsa_TrustedDomainInfo *info = NULL;
        DATA_BLOB session_key;
        enum ndr_err_code ndr_err;
        int i;
 
-       torture_comment(tctx, "\nTesting CreateTrustedDomainEx2 for 12 domains\n");
+       torture_comment(tctx, "\nTesting CreateTrustedDomainEx2 for %d domains\n", num_trusts);
+
+       domsid = talloc_array(tctx, struct dom_sid *, num_trusts);
+       trustdom_handle = talloc_array(tctx, struct policy_handle, num_trusts);
 
        status = dcerpc_fetch_session_key(p, &session_key);
        if (!NT_STATUS_IS_OK(status)) {
@@ -2232,7 +2339,7 @@ static bool test_CreateTrustedDomainEx2(struct dcerpc_pipe *p,
                return false;
        }
 
-       for (i=0; i< 12; i++) {
+       for (i=0; i< num_trusts; i++) {
                char *trust_name = talloc_asprintf(tctx, "torturedom%02d", i);
                char *trust_name_dns = talloc_asprintf(tctx, "torturedom%02d.samba.example.com", i);
                char *trust_sid = talloc_asprintf(tctx, "S-1-5-21-97398-379795-100%02d", i);
@@ -2331,7 +2438,12 @@ static bool test_CreateTrustedDomainEx2(struct dcerpc_pipe *p,
                ret = false;
        }
 
-       for (i=0; i<12; i++) {
+       if (!test_EnumTrustDomEx(p, tctx, handle)) {
+               torture_comment(tctx, "test_EnumTrustDomEx failed\n");
+               ret = false;
+       }
+
+       for (i=0; i<num_trusts; i++) {
                if (!test_DeleteTrustedDomainBySid(p, tctx, handle, domsid[i])) {
                        torture_comment(tctx, "test_DeleteTrustedDomainBySid failed\n");
                        ret = false;
@@ -2725,6 +2837,10 @@ static bool testcase_LookupNames(struct torture_context *tctx,
                ret = false;
        }
 
+       if (!test_LookupNames_NULL(p, tctx, handle)) {
+               ret = false;
+       }
+
        if (!test_LookupNames_bogus(p, tctx, handle)) {
                ret = false;
        }
@@ -2751,11 +2867,20 @@ struct torture_suite *torture_rpc_lsa_lookup_names(TALLOC_CTX *mem_ctx)
        return suite;
 }
 
+struct lsa_trustdom_state {
+       uint32_t num_trusts;
+};
+
 static bool testcase_TrustedDomains(struct torture_context *tctx,
-                                   struct dcerpc_pipe *p)
+                                   struct dcerpc_pipe *p,
+                                   void *data)
 {
        bool ret = true;
        struct policy_handle *handle;
+       struct lsa_trustdom_state *state =
+               talloc_get_type_abort(data, struct lsa_trustdom_state);
+
+       torture_comment(tctx, "testing %d domains\n", state->num_trusts);
 
        if (!test_OpenPolicy(p, tctx)) {
                ret = false;
@@ -2769,11 +2894,11 @@ static bool testcase_TrustedDomains(struct torture_context *tctx,
                ret = false;
        }
 
-       if (!test_CreateTrustedDomain(p, tctx, handle)) {
+       if (!test_CreateTrustedDomain(p, tctx, handle, state->num_trusts)) {
                ret = false;
        }
 
-       if (!test_CreateTrustedDomainEx2(p, tctx, handle)) {
+       if (!test_CreateTrustedDomainEx2(p, tctx, handle, state->num_trusts)) {
                ret = false;
        }
 
@@ -2788,13 +2913,19 @@ struct torture_suite *torture_rpc_lsa_trusted_domains(TALLOC_CTX *mem_ctx)
 {
        struct torture_suite *suite;
        struct torture_rpc_tcase *tcase;
+       struct lsa_trustdom_state *state;
+
+       state = talloc(mem_ctx, struct lsa_trustdom_state);
+
+       state->num_trusts = 12;
 
        suite = torture_suite_create(mem_ctx, "LSA-TRUSTED-DOMAINS");
 
        tcase = torture_suite_add_rpc_iface_tcase(suite, "lsa",
                                                  &ndr_table_lsarpc);
-       torture_rpc_tcase_add_test(tcase, "TrustedDomains",
-                                  testcase_TrustedDomains);
+       torture_rpc_tcase_add_test_ex(tcase, "TrustedDomains",
+                                     testcase_TrustedDomains,
+                                     state);
 
        return suite;
 }