s4-smbtorture: test whether an lsa_EnumTrustDom implementation would hang up a client.
authorGünther Deschner <gd@samba.org>
Wed, 21 Oct 2009 00:16:32 +0000 (02:16 +0200)
committerGünther Deschner <gd@samba.org>
Wed, 21 Oct 2009 01:13:24 +0000 (03:13 +0200)
Guenther

source4/torture/rpc/lsa.c

index 9cee4e2f0c9ec1528a3d9b2bb9cae7cd6546fbcc..710f4c53d2f4b403ccaf071b0e100f5a72b9bb48 100644 (file)
@@ -2026,20 +2026,39 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,
 {
        struct lsa_EnumTrustDom r;
        NTSTATUS enum_status;
 {
        struct lsa_EnumTrustDom r;
        NTSTATUS enum_status;
-       uint32_t resume_handle = 0;
+       uint32_t in_resume_handle = 0;
+       uint32_t out_resume_handle;
        struct lsa_DomainList domains;
        bool ret = true;
 
        torture_comment(tctx, "\nTesting EnumTrustDom\n");
 
        r.in.handle = handle;
        struct lsa_DomainList domains;
        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.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);
 
 
        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");
        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");
@@ -2051,17 +2070,35 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,
        }
 
        /* Start from the bottom again */
        }
 
        /* Start from the bottom again */
-       resume_handle = 0;
+       in_resume_handle = 0;
 
        do {
                r.in.handle = handle;
 
        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.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);
 
 
                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) {
                /* NO_MORE_ENTRIES is allowed */
                if (NT_STATUS_EQUAL(enum_status, NT_STATUS_NO_MORE_ENTRIES)) {
                        if (domains.count == 0) {
@@ -2090,6 +2127,8 @@ static bool test_EnumTrustDom(struct dcerpc_pipe *p,
 
                ret &= test_query_each_TrustDom(p, tctx, handle, &domains);
 
 
                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;
        } while ((NT_STATUS_EQUAL(enum_status, STATUS_MORE_ENTRIES)));
 
        return ret;