From 771abee93aa4e7711090a41862559aebd876a0e7 Mon Sep 17 00:00:00 2001
From: Yassir Elley <yelley@redhat.com>
Date: Tue, 6 May 2014 12:28:04 -0400
Subject: [PATCH] AD-GPO: Remove dependency on libsamba-security

---
 Makefile.am                   |   1 +
 src/providers/ad/ad_gpo.c     | 102 ++++++---
 src/providers/ad/ad_gpo.h     |   2 -
 src/providers/ad/ad_gpo_ndr.c | 508 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 586 insertions(+), 27 deletions(-)
 create mode 100644 src/providers/ad/ad_gpo_ndr.c

diff --git a/Makefile.am b/Makefile.am
index 483584e5320bfcd8e262ed03d9be7fa670a38932..510cfc78ba59f08fc73ed0f971e77ce6f2288461 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2118,6 +2118,7 @@ libsss_ad_la_SOURCES = \
     src/providers/ad/ad_access.h \
     src/providers/ad/ad_gpo.c \
     src/providers/ad/ad_gpo.h \
+    src/providers/ad/ad_gpo_ndr.c \
     src/providers/ad/ad_opts.h \
     src/providers/ad/ad_srv.c \
     src/providers/ad/ad_subdomains.c \
diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index ca8a5f66c9e177585b8e0f964be03ed5e1911a34..168ed2d7e8657799a7c773ec8b24897cdd303ec4 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -42,6 +42,8 @@
 #include "providers/ldap/sdap_access.h"
 #include "providers/ldap/sdap_async.h"
 #include "providers/ldap/sdap.h"
+#include "providers/ldap/sdap_idmap.h"
+#include "util/util_sss_idmap.h"
 #include <ndr.h>
 #include <gen_ndr/security.h>
 
@@ -63,7 +65,6 @@
 #define UAC_WORKSTATION_TRUST_ACCOUNT 0x00001000
 #define AD_AGP_GUID "edacfd8f-ffb3-11d1-b41d-00a0c968f939"
 #define AD_AUTHENTICATED_USERS_SID "S-1-5-11"
-#define SID_MAX_LEN 1024
 
 /* == common data structures and declarations ============================= */
 
@@ -123,6 +124,43 @@ int ad_gpo_process_gpo_recv(struct tevent_req *req,
 
 /* == ad_gpo_access_send/recv helpers =======================================*/
 
+static bool
+ad_gpo_dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
+{
+    int i;
+
+    if (sid1 == sid2) {
+        return true;
+    }
+
+    if (!sid1 || !sid2) {
+        return false;
+    }
+
+    if (sid1->sid_rev_num != sid2->sid_rev_num) {
+        return false;
+    }
+
+    for (i = 0; i < 6; i++) {
+        if (sid1->id_auth[i] != sid2->id_auth[i]) {
+            return false;
+        }
+    }
+
+    if (sid1->num_auths != sid2->num_auths) {
+        return false;
+    }
+
+    for (i = 0; i < sid1->num_auths; i++) {
+        if (sid1->sub_auths[i] != sid2->sub_auths[i]) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
 /*
  * This function retrieves the SIDs corresponding to the input user and returns
  * the user_sid, group_sids, and group_size in their respective output params.
@@ -207,10 +245,6 @@ ad_gpo_get_sids(TALLOC_CTX *mem_ctx,
     return ret;
 }
 
-bool string_to_sid(struct dom_sid *sidout, const char *sidstr);
-int dom_sid_string_buf(const struct dom_sid *sid, char *buf, int buflen);
-bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2);
-
 /*
  * This function determines whether the input ACE includes any of the
  * client's SIDs. The boolean result is assigned to the _included output param.
@@ -220,34 +254,40 @@ ad_gpo_ace_includes_client_sid(const char *user_sid,
                                const char **group_sids,
                                int group_size,
                                struct security_ace *ace,
+                               struct sss_idmap_ctx *idmap_ctx,
                                bool *_included)
 {
     int i = 0;
     struct dom_sid ace_dom_sid;
-    struct dom_sid user_dom_sid;
-    struct dom_sid group_dom_sid;
-    char buf[SID_MAX_LEN + 1];
+    struct dom_sid *user_dom_sid;
+    struct dom_sid *group_dom_sid;
+    enum idmap_error_code err;
+    bool included = false;
 
     ace_dom_sid = ace->trustee;
 
-    dom_sid_string_buf(&ace_dom_sid, buf, SID_MAX_LEN);
-
-    if (!string_to_sid(&user_dom_sid, user_sid)) {
-        DEBUG(SSSDBG_OP_FAILURE, "string_to_sid failed\n");
-        return EINVAL;
+    err = sss_idmap_sid_to_smb_sid(idmap_ctx, user_sid, &user_dom_sid);
+    if (err != IDMAP_SUCCESS) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n");
+        return EFAULT;
     }
 
-    if (dom_sid_equal(&ace_dom_sid, &user_dom_sid)) {
+    included = ad_gpo_dom_sid_equal(&ace_dom_sid, user_dom_sid);
+    sss_idmap_free_smb_sid(idmap_ctx, user_dom_sid);
+    if (included) {
         *_included = true;
         return EOK;
     }
 
     for (i = 0; i < group_size; i++) {
-        if (!string_to_sid(&group_dom_sid, group_sids[i])) {
-            DEBUG(SSSDBG_OP_FAILURE, "string_to_sid failed\n");
-            return EINVAL;
+        err = sss_idmap_sid_to_smb_sid(idmap_ctx, group_sids[i], &group_dom_sid);
+        if (err != IDMAP_SUCCESS) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n");
+            return EFAULT;
         }
-        if (dom_sid_equal(&ace_dom_sid, &group_dom_sid)) {
+        included = ad_gpo_dom_sid_equal(&ace_dom_sid, group_dom_sid);
+        sss_idmap_free_smb_sid(idmap_ctx, group_dom_sid);
+        if (included) {
             *_included = true;
             return EOK;
         }
@@ -286,6 +326,7 @@ ad_gpo_ace_includes_client_sid(const char *user_sid,
  *   AGP, then deny the requested control access right. Stop access checking.
  */
 static enum ace_eval_status ad_gpo_evaluate_ace(struct security_ace *ace,
+                                                struct sss_idmap_ctx *idmap_ctx,
                                                 const char *user_sid,
                                                 const char **group_sids,
                                                 int group_size)
@@ -301,7 +342,7 @@ static enum ace_eval_status ad_gpo_evaluate_ace(struct security_ace *ace,
     }
 
     ret = ad_gpo_ace_includes_client_sid(user_sid, group_sids, group_size, ace,
-                                         &included);
+                                         idmap_ctx, &included);
     if (ret != EOK) {
         return AD_GPO_ACE_DENIED;
     }
@@ -342,6 +383,7 @@ static enum ace_eval_status ad_gpo_evaluate_ace(struct security_ace *ace,
  * The boolean result is assigned to the _access_allowed output parameter.
  */
 static errno_t ad_gpo_evaluate_dacl(struct security_acl *dacl,
+                                    struct sss_idmap_ctx *idmap_ctx,
                                     const char *user_sid,
                                     const char **group_sids,
                                     int group_size,
@@ -367,7 +409,8 @@ static errno_t ad_gpo_evaluate_dacl(struct security_acl *dacl,
     for (i = 0; i < dacl->num_aces; i ++) {
         ace = &dacl->aces[i];
 
-        ace_status = ad_gpo_evaluate_ace(ace, user_sid, group_sids, group_size);
+        ace_status = ad_gpo_evaluate_ace(ace, idmap_ctx, user_sid,
+                                         group_sids, group_size);
 
         switch (ace_status) {
         case AD_GPO_ACE_NEUTRAL:
@@ -396,6 +439,7 @@ static errno_t
 ad_gpo_filter_gpos_by_dacl(TALLOC_CTX *mem_ctx,
                            const char *user,
                            struct sss_domain_info *domain,
+                           struct sss_idmap_ctx *idmap_ctx,
                            struct gp_gpo **candidate_gpos,
                            int num_candidate_gpos,
                            struct gp_gpo ***_dacl_filtered_gpos,
@@ -474,7 +518,7 @@ ad_gpo_filter_gpos_by_dacl(TALLOC_CTX *mem_ctx,
             break;
         }
 
-        ad_gpo_evaluate_dacl(dacl, user_sid, group_sids,
+        ad_gpo_evaluate_dacl(dacl, idmap_ctx, user_sid, group_sids,
                              group_size, &access_allowed);
         if (access_allowed) {
             DEBUG(SSSDBG_TRACE_ALL,
@@ -707,7 +751,6 @@ ad_gpo_target_dn_retrieval_done(struct tevent_req *subreq)
                ret, sss_strerror(ret));
         goto done;
     }
-
     state->target_dn = talloc_steal(state, target_dn);
     if (state->target_dn == NULL) {
         ret = ENOMEM;
@@ -831,6 +874,7 @@ ad_gpo_process_gpo_done(struct tevent_req *subreq)
     }
 
     ret = ad_gpo_filter_gpos_by_dacl(state, state->user, state->domain,
+                                     state->opts->idmap_ctx->map,
                                      candidate_gpos, num_candidate_gpos,
                                      &state->dacl_filtered_gpos,
                                      &state->num_dacl_filtered_gpos);
@@ -1878,8 +1922,8 @@ ad_gpo_parse_machine_ext_names(TALLOC_CTX *mem_ctx,
 }
 
 enum ndr_err_code
-ndr_pull_security_descriptor(struct ndr_pull *ndr, int ndr_flags,
-                             struct security_descriptor *r);
+ad_gpo_ndr_pull_security_descriptor(struct ndr_pull *ndr, int ndr_flags,
+                                    struct security_descriptor *r);
 
 /*
  * This function parses the input data blob and assigns the resulting
@@ -1894,6 +1938,7 @@ static errno_t ad_gpo_parse_sd(TALLOC_CTX *mem_ctx,
     struct ndr_pull *ndr_pull = NULL;
     struct security_descriptor sd;
     DATA_BLOB blob;
+    enum ndr_err_code ndr_err;
 
     blob.data = data;
     blob.length = length;
@@ -1904,7 +1949,14 @@ static errno_t ad_gpo_parse_sd(TALLOC_CTX *mem_ctx,
         return EINVAL;
     }
 
-    ndr_pull_security_descriptor(ndr_pull, NDR_SCALARS|NDR_BUFFERS, &sd);
+    ndr_err = ad_gpo_ndr_pull_security_descriptor(ndr_pull,
+                                                  NDR_SCALARS|NDR_BUFFERS,
+                                                  &sd);
+
+    if (ndr_err != NDR_ERR_SUCCESS) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to pull security descriptor\n");
+        return EINVAL;
+    }
 
     *_gpo_sd = talloc_memdup(mem_ctx, &sd, sizeof(struct security_descriptor));
 
diff --git a/src/providers/ad/ad_gpo.h b/src/providers/ad/ad_gpo.h
index 856013e43688bb8098f900184616ac33acb72438..851195d11e56df08ce8bc2619ee0e05dda390b30 100644
--- a/src/providers/ad/ad_gpo.h
+++ b/src/providers/ad/ad_gpo.h
@@ -50,6 +50,4 @@ ad_gpo_access_send(TALLOC_CTX *mem_ctx,
 
 errno_t ad_gpo_access_recv(struct tevent_req *req);
 
-struct security_descriptor;
-
 #endif /* AD_GPO_H_ */
diff --git a/src/providers/ad/ad_gpo_ndr.c b/src/providers/ad/ad_gpo_ndr.c
new file mode 100644
index 0000000000000000000000000000000000000000..0ee28f0972ce9d8e0c651fc2a03b2c0641f7ad58
--- /dev/null
+++ b/src/providers/ad/ad_gpo_ndr.c
@@ -0,0 +1,508 @@
+/*
+    SSSD
+
+    ad_gpo_ndr.c
+
+    Authors:
+    Yassir Elley <yelley@redhat.com>
+
+    Copyright (C) 2014 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This file contains a copy of samba's ndr_pull_* functions needed
+ * to parse a security_descriptor. We are copying them here so that we don't
+ * have to link against libsamba-security, which is a private samba library
+ * These functions are taken from:
+ *  librpc/ndr/gen_ndr/ndr_security.c
+ *  librpc/ndr/ndr_misc.c
+ *  librpc/ndr/ndr_sec_helper.c
+ */
+
+#include "util/util.h"
+#include <ndr.h>
+#include <gen_ndr/security.h>
+
+static enum ndr_err_code
+ndr_pull_GUID(struct ndr_pull *ndr,
+              int ndr_flags,
+              struct GUID *r)
+{
+    uint32_t size_clock_seq_0 = 0;
+    uint32_t size_node_0 = 0;
+    NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+    if (ndr_flags & NDR_SCALARS) {
+        NDR_CHECK(ndr_pull_align(ndr, 4));
+        NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time_low));
+        NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->time_mid));
+        NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->time_hi_and_version));
+        size_clock_seq_0 = 2;
+        NDR_CHECK(ndr_pull_array_uint8(ndr,
+                                       NDR_SCALARS,
+                                       r->clock_seq,
+                                       size_clock_seq_0));
+        size_node_0 = 6;
+        NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->node, size_node_0));
+        NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+    }
+    if (ndr_flags & NDR_BUFFERS) {
+    }
+    return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code
+ndr_pull_security_ace_flags(struct ndr_pull *ndr,
+                            int ndr_flags,
+                            uint8_t *r)
+{
+    uint8_t v;
+    NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+    *r = v;
+    return NDR_ERR_SUCCESS;
+}
+
+
+static enum ndr_err_code
+ndr_pull_security_ace_type(struct ndr_pull *ndr,
+                           int ndr_flags,
+                           enum security_ace_type *r)
+{
+    uint8_t v;
+    NDR_CHECK(ndr_pull_enum_uint8(ndr, NDR_SCALARS, &v));
+    *r = v;
+    return NDR_ERR_SUCCESS;
+}
+
+
+static enum ndr_err_code
+ndr_pull_security_ace_object_flags(struct ndr_pull *ndr,
+                                   int ndr_flags,
+                                   uint32_t *r)
+{
+    uint32_t v;
+    NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+    *r = v;
+    return NDR_ERR_SUCCESS;
+}
+
+
+static enum ndr_err_code
+ndr_pull_security_ace_object_type(struct ndr_pull *ndr,
+                                  int ndr_flags,
+                                  union security_ace_object_type *r)
+{
+    uint32_t level;
+    level = ndr_pull_get_switch_value(ndr, r);
+    NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+    if (ndr_flags & NDR_SCALARS) {
+        NDR_CHECK(ndr_pull_union_align(ndr, 4));
+        switch (level) {
+        case SEC_ACE_OBJECT_TYPE_PRESENT: {
+            NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->type));
+            break; }
+        default: {
+            break; }
+        }
+    }
+    if (ndr_flags & NDR_BUFFERS) {
+        switch (level) {
+        case SEC_ACE_OBJECT_TYPE_PRESENT:
+            break;
+        default:
+            break;
+        }
+    }
+    return NDR_ERR_SUCCESS;
+}
+
+
+static enum ndr_err_code
+ndr_pull_security_ace_object_inherited_type(struct ndr_pull *ndr,
+                                            int ndr_flags,
+                                            union security_ace_object_inherited_type *r)
+{
+    uint32_t level;
+    level = ndr_pull_get_switch_value(ndr, r);
+    NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+    if (ndr_flags & NDR_SCALARS) {
+        NDR_CHECK(ndr_pull_union_align(ndr, 4));
+        switch (level) {
+        case SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT: {
+            NDR_CHECK(ndr_pull_GUID(ndr,
+                                    NDR_SCALARS,
+                                    &r->inherited_type));
+            break; }
+        default: {
+            break; }
+        }
+    }
+    if (ndr_flags & NDR_BUFFERS) {
+        switch (level) {
+        case SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT:
+            break;
+        default:
+            break;
+        }
+    }
+    return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code
+ndr_pull_security_ace_object(struct ndr_pull *ndr,
+                             int ndr_flags,
+                             struct security_ace_object *r)
+{
+    NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+    if (ndr_flags & NDR_SCALARS) {
+        NDR_CHECK(ndr_pull_align(ndr, 4));
+        NDR_CHECK(ndr_pull_security_ace_object_flags
+                  (ndr, NDR_SCALARS, &r->flags));
+        NDR_CHECK(ndr_pull_set_switch_value
+                  (ndr, &r->type, r->flags & SEC_ACE_OBJECT_TYPE_PRESENT));
+        NDR_CHECK(ndr_pull_security_ace_object_type
+                  (ndr, NDR_SCALARS, &r->type));
+        NDR_CHECK(ndr_pull_set_switch_value
+                  (ndr,
+                   &r->inherited_type,
+                   r->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT));
+        NDR_CHECK(ndr_pull_security_ace_object_inherited_type
+                  (ndr, NDR_SCALARS, &r->inherited_type));
+        NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+    }
+    if (ndr_flags & NDR_BUFFERS) {
+        NDR_CHECK(ndr_pull_security_ace_object_type
+                  (ndr, NDR_BUFFERS, &r->type));
+        NDR_CHECK(ndr_pull_security_ace_object_inherited_type
+                  (ndr, NDR_BUFFERS, &r->inherited_type));
+    }
+    return NDR_ERR_SUCCESS;
+}
+
+
+static enum ndr_err_code
+ndr_pull_security_ace_object_ctr(struct ndr_pull *ndr,
+                                 int ndr_flags,
+                                 union security_ace_object_ctr *r)
+{
+    uint32_t level;
+    level = ndr_pull_get_switch_value(ndr, r);
+    NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+    if (ndr_flags & NDR_SCALARS) {
+        NDR_CHECK(ndr_pull_union_align(ndr, 4));
+        switch (level) {
+        case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: {
+            NDR_CHECK(ndr_pull_security_ace_object
+                      (ndr, NDR_SCALARS, &r->object));
+            break; }
+        case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: {
+            NDR_CHECK(ndr_pull_security_ace_object
+                      (ndr, NDR_SCALARS, &r->object));
+            break; }
+        case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT: {
+            NDR_CHECK(ndr_pull_security_ace_object
+                      (ndr, NDR_SCALARS, &r->object));
+            break; }
+        case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT: {
+            NDR_CHECK(ndr_pull_security_ace_object
+                      (ndr, NDR_SCALARS, &r->object));
+            break; }
+        default: {
+            break; }
+        }
+    }
+    if (ndr_flags & NDR_BUFFERS) {
+        switch (level) {
+        case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+            NDR_CHECK(ndr_pull_security_ace_object
+                      (ndr, NDR_BUFFERS, &r->object));
+            break;
+        case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+            NDR_CHECK(ndr_pull_security_ace_object
+                      (ndr, NDR_BUFFERS, &r->object));
+            break;
+        case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+            NDR_CHECK(ndr_pull_security_ace_object
+                      (ndr, NDR_BUFFERS, &r->object));
+            break;
+        case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+            NDR_CHECK(ndr_pull_security_ace_object
+                      (ndr, NDR_BUFFERS, &r->object));
+            break;
+        default:
+            break;
+        }
+    }
+    return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code
+ndr_pull_dom_sid(struct ndr_pull *ndr,
+                 int ndr_flags,
+                 struct dom_sid *r)
+{
+    uint32_t cntr_sub_auths_0;
+    if (ndr_flags & NDR_SCALARS) {
+        NDR_CHECK(ndr_pull_align(ndr, 4));
+        NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sid_rev_num));
+        NDR_CHECK(ndr_pull_int8(ndr, NDR_SCALARS, &r->num_auths));
+        if (r->num_auths < 0 || r->num_auths > ARRAY_SIZE(r->sub_auths)) {
+            return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+        }
+        NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
+        ZERO_STRUCT(r->sub_auths);
+        for (cntr_sub_auths_0 = 0;
+             cntr_sub_auths_0 < r->num_auths;
+             cntr_sub_auths_0++) {
+            NDR_CHECK(ndr_pull_uint32
+                      (ndr, NDR_SCALARS, &r->sub_auths[cntr_sub_auths_0]));
+        }
+    }
+    return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code
+ndr_pull_security_ace(struct ndr_pull *ndr,
+                      int ndr_flags,
+                      struct security_ace *r)
+{
+    if (ndr_flags & NDR_SCALARS) {
+        uint32_t start_ofs = ndr->offset;
+        uint32_t size = 0;
+        uint32_t pad = 0;
+        NDR_CHECK(ndr_pull_align(ndr, 4));
+        NDR_CHECK(ndr_pull_security_ace_type(ndr, NDR_SCALARS, &r->type));
+        NDR_CHECK(ndr_pull_security_ace_flags(ndr, NDR_SCALARS, &r->flags));
+        NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+        NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->access_mask));
+        NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, r->type));
+        NDR_CHECK(ndr_pull_security_ace_object_ctr
+                  (ndr, NDR_SCALARS, &r->object));
+        NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->trustee));
+        size = ndr->offset - start_ofs;
+        if (r->size < size) {
+            return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+                                  "ndr_pull_security_ace: r->size %u < size %u",
+                                  (unsigned)r->size, size);
+        }
+        pad = r->size - size;
+        NDR_PULL_NEED_BYTES(ndr, pad);
+        ndr->offset += pad;
+    }
+    if (ndr_flags & NDR_BUFFERS) {
+        NDR_CHECK(ndr_pull_security_ace_object_ctr
+                  (ndr, NDR_BUFFERS, &r->object));
+    }
+    return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code
+ndr_pull_security_acl_revision(struct ndr_pull *ndr,
+                               int ndr_flags,
+                               enum security_acl_revision *r)
+{
+    uint16_t v;
+    NDR_CHECK(ndr_pull_enum_uint1632(ndr, NDR_SCALARS, &v));
+    *r = v;
+    return NDR_ERR_SUCCESS;
+}
+
+
+static enum ndr_err_code
+ndr_pull_security_acl(struct ndr_pull *ndr,
+                      int ndr_flags,
+                      struct security_acl *r)
+{
+    uint32_t size_aces_0 = 0;
+    uint32_t cntr_aces_0;
+    TALLOC_CTX *_mem_save_aces_0;
+    NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+    if (ndr_flags & NDR_SCALARS) {
+        NDR_CHECK(ndr_pull_align(ndr, 4));
+        NDR_CHECK(ndr_pull_security_acl_revision
+                  (ndr, NDR_SCALARS, &r->revision));
+        NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+        NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_aces));
+        if (r->num_aces > 1000) {
+            return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
+        }
+        size_aces_0 = r->num_aces;
+        NDR_PULL_ALLOC_N(ndr, r->aces, size_aces_0);
+        _mem_save_aces_0 = NDR_PULL_GET_MEM_CTX(ndr);
+        NDR_PULL_SET_MEM_CTX(ndr, r->aces, 0);
+        for (cntr_aces_0 = 0; cntr_aces_0 < size_aces_0; cntr_aces_0++) {
+            NDR_CHECK(ndr_pull_security_ace
+                      (ndr, NDR_SCALARS, &r->aces[cntr_aces_0]));
+        }
+        NDR_PULL_SET_MEM_CTX(ndr, _mem_save_aces_0, 0);
+        NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+    }
+    if (ndr_flags & NDR_BUFFERS) {
+        size_aces_0 = r->num_aces;
+        _mem_save_aces_0 = NDR_PULL_GET_MEM_CTX(ndr);
+        NDR_PULL_SET_MEM_CTX(ndr, r->aces, 0);
+        for (cntr_aces_0 = 0; cntr_aces_0 < size_aces_0; cntr_aces_0++) {
+            NDR_CHECK(ndr_pull_security_ace
+                      (ndr, NDR_BUFFERS, &r->aces[cntr_aces_0]));
+        }
+        NDR_PULL_SET_MEM_CTX(ndr, _mem_save_aces_0, 0);
+    }
+    return NDR_ERR_SUCCESS;
+}
+
+
+static enum ndr_err_code
+ndr_pull_security_descriptor_revision(struct ndr_pull *ndr,
+                                      int ndr_flags,
+                                      enum security_descriptor_revision *r)
+{
+    uint8_t v;
+    NDR_CHECK(ndr_pull_enum_uint8(ndr, NDR_SCALARS, &v));
+    *r = v;
+    return NDR_ERR_SUCCESS;
+}
+
+
+
+static enum ndr_err_code
+ndr_pull_security_descriptor_type(struct ndr_pull *ndr,
+                                  int ndr_flags,
+                                  uint16_t *r)
+{
+    uint16_t v;
+    NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v));
+    *r = v;
+    return NDR_ERR_SUCCESS;
+}
+
+
+enum ndr_err_code
+ad_gpo_ndr_pull_security_descriptor(struct ndr_pull *ndr,
+                                    int ndr_flags,
+                                    struct security_descriptor *r)
+{
+    uint32_t _ptr_owner_sid;
+    TALLOC_CTX *_mem_save_owner_sid_0;
+    uint32_t _ptr_group_sid;
+    TALLOC_CTX *_mem_save_group_sid_0;
+    uint32_t _ptr_sacl;
+    TALLOC_CTX *_mem_save_sacl_0;
+    uint32_t _ptr_dacl;
+    TALLOC_CTX *_mem_save_dacl_0;
+    uint32_t _flags_save_STRUCT = ndr->flags;
+    uint32_t _relative_save_offset;
+
+    ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
+    NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+    if (ndr_flags & NDR_SCALARS) {
+        NDR_CHECK(ndr_pull_align(ndr, 5));
+        NDR_CHECK(ndr_pull_security_descriptor_revision(ndr,
+                                                        NDR_SCALARS,
+                                                        &r->revision));
+        NDR_CHECK(ndr_pull_security_descriptor_type(ndr,
+                                                    NDR_SCALARS,
+                                                    &r->type));
+        NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_owner_sid));
+        if (_ptr_owner_sid) {
+            NDR_PULL_ALLOC(ndr, r->owner_sid);
+            NDR_CHECK(ndr_pull_relative_ptr1(ndr,
+                                             r->owner_sid,
+                                             _ptr_owner_sid));
+        } else {
+            r->owner_sid = NULL;
+        }
+        NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_group_sid));
+        if (_ptr_group_sid) {
+            NDR_PULL_ALLOC(ndr, r->group_sid);
+            NDR_CHECK(ndr_pull_relative_ptr1(ndr,
+                                             r->group_sid,
+                                             _ptr_group_sid));
+        } else {
+            r->group_sid = NULL;
+        }
+        NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sacl));
+        if (_ptr_sacl) {
+            NDR_PULL_ALLOC(ndr, r->sacl);
+            NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->sacl, _ptr_sacl));
+        } else {
+            r->sacl = NULL;
+        }
+        NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dacl));
+        if (_ptr_dacl) {
+            NDR_PULL_ALLOC(ndr, r->dacl);
+            NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->dacl, _ptr_dacl));
+        } else {
+            r->dacl = NULL;
+        }
+        NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+    }
+    if (ndr_flags & NDR_BUFFERS) {
+        if (r->owner_sid) {
+            _relative_save_offset = ndr->offset;
+            NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->owner_sid));
+            _mem_save_owner_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+            NDR_PULL_SET_MEM_CTX(ndr, r->owner_sid, 0);
+            NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, r->owner_sid));
+            NDR_PULL_SET_MEM_CTX(ndr, _mem_save_owner_sid_0, 0);
+            if (ndr->offset > ndr->relative_highest_offset) {
+                ndr->relative_highest_offset = ndr->offset;
+            }
+            ndr->offset = _relative_save_offset;
+        }
+        if (r->group_sid) {
+            _relative_save_offset = ndr->offset;
+            NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->group_sid));
+            _mem_save_group_sid_0 = NDR_PULL_GET_MEM_CTX(ndr);
+            NDR_PULL_SET_MEM_CTX(ndr, r->group_sid, 0);
+            NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, r->group_sid));
+            NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_sid_0, 0);
+            if (ndr->offset > ndr->relative_highest_offset) {
+                ndr->relative_highest_offset = ndr->offset;
+            }
+            ndr->offset = _relative_save_offset;
+        }
+        if (r->sacl) {
+            _relative_save_offset = ndr->offset;
+            NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->sacl));
+            _mem_save_sacl_0 = NDR_PULL_GET_MEM_CTX(ndr);
+            NDR_PULL_SET_MEM_CTX(ndr, r->sacl, 0);
+            NDR_CHECK(ndr_pull_security_acl(ndr,
+                                            NDR_SCALARS|NDR_BUFFERS,
+                                            r->sacl));
+            NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sacl_0, 0);
+            if (ndr->offset > ndr->relative_highest_offset) {
+                ndr->relative_highest_offset = ndr->offset;
+            }
+            ndr->offset = _relative_save_offset;
+        }
+        if (r->dacl) {
+            _relative_save_offset = ndr->offset;
+            NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->dacl));
+            _mem_save_dacl_0 = NDR_PULL_GET_MEM_CTX(ndr);
+            NDR_PULL_SET_MEM_CTX(ndr, r->dacl, 0);
+            NDR_CHECK(ndr_pull_security_acl(ndr,
+                                            NDR_SCALARS|NDR_BUFFERS,
+                                            r->dacl));
+            NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dacl_0, 0);
+            if (ndr->offset > ndr->relative_highest_offset) {
+                ndr->relative_highest_offset = ndr->offset;
+            }
+            ndr->offset = _relative_save_offset;
+        }
+
+        ndr->flags = _flags_save_STRUCT;
+    }
+    return NDR_ERR_SUCCESS;
+}
-- 
1.8.5.3

