]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
librpc/security.idl: adjust size calculations for upcoming ace types
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Thu, 13 Jul 2023 09:31:50 +0000 (21:31 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 24 Aug 2023 02:53:31 +0000 (02:53 +0000)
Soon we will get Conditional ACEs and Resource Attribute ACES, each of
which have trailing bytes at the end of the ACE. Here's a diagram:

              ____      The ACE size field may indicate a size bigger
  .type      /    |     than the known parts, even when you take
  .flags    /     |     rounding to a multiple of four into account.
  .size  --'      |     This extra data is meaningful in some ACEs.
  .access_mask    |
  .trustee (sid) _|  <- known data ends here.
                  :
   "coda"      ___:  <- the trailing part, Zero size unless the size
                        field points beyond the end of the known data.
Probably empty for ordinary ACE types.

Until now we have thrown away these extra bytes, because they have no
meaning in the ACE types we recognise. But with conditional and
resource attribute ACEs we need to catch and process these bytes, so
we add an extra field for that.

Thus we can drop the manually written ndr_pull_security_ace() that
discarded the trailing bytes, because we just allow it to be pulled
into an unused blob. In the very common case, the blob will be empty.

Microsoft does not use a common name across different ACE types to
describe this end-data -- "coda" is a Samba term.

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
libcli/security/secace.c
libcli/security/secace.h
librpc/idl/security.idl
librpc/ndr/ndr_sec_helper.c
selftest/knownfail.d/ndrdump [new file with mode: 0644]

index 2452da24b0f663643c7692b9e73d6820ea87f1f7..70c991d6c25ff818c3d9b5916767478ee08c2bdf 100644 (file)
@@ -67,6 +67,8 @@ void init_sec_ace(struct security_ace *t, const struct dom_sid *sid, enum securi
        t->access_mask = mask;
 
        t->trustee = *sid;
+       t->coda.ignored.data = NULL;
+       t->coda.ignored.length = 0;
 }
 
 int nt_ace_inherit_comp(const struct security_ace *a1, const struct security_ace *a2)
index 16c495dd2aeb08bf804b32ddfb1bbb533201604f..0d326f5fb6525b7cc5e6f651ae2c32bf7ba17d3a 100644 (file)
@@ -25,6 +25,8 @@
 
 bool sec_ace_object(uint8_t type);
 void sec_ace_copy(struct security_ace *ace_dest, const struct security_ace *ace_src);
+size_t ndr_subcontext_size_of_ace_coda(const struct security_ace *ace, size_t ace_size, int flags);
+
 void init_sec_ace(struct security_ace *t, const struct dom_sid *sid, enum security_ace_type type,
                  uint32_t mask, uint8_t flag);
 int nt_ace_inherit_comp( const struct security_ace *a1, const struct security_ace *a2);
index b699355d77690181c4c79212ad2af4c5265fdb2c..e3e7e9c35cb30d3970f53fb4a98344d1d37d71e3 100644 (file)
@@ -31,6 +31,7 @@ cpp_quote("#define dom_sid0 dom_sid")
         */
        uuid("cbf7d408-2d6c-11e2-ae5b-0b5692790e18"),
        version(0.0),
+       helper("../libcli/security/security.h"),
        pyhelper("librpc/ndr/py_security.c"),
        pointer_default(unique)
 ]
@@ -588,13 +589,18 @@ interface security
                [default];
        } security_ace_object_ctr;
 
-       typedef [public,nopull,gensize,nosize] struct {
+       typedef [public,nodiscriminant,gensize] union {
+               [default][flag(NDR_REMAINING)] DATA_BLOB ignored;
+       } security_ace_coda;
+
+       typedef [public,gensize,nosize] struct {
                security_ace_type type;  /* SEC_ACE_TYPE_* */
                security_ace_flags flags; /* SEC_ACE_FLAG_* */
                [value(ndr_size_security_ace(r,ndr->flags))] uint16 size;
                uint32 access_mask;
                [switch_is(type)] security_ace_object_ctr object;
                dom_sid trustee;
+               [switch_is(type), subcontext(0), subcontext_size(ndr_subcontext_size_of_ace_coda(r, size, ndr->flags))] security_ace_coda coda;
        } security_ace;
 
        typedef enum {
index 0384626e827341c96415e2aa6545785934d25d43..264184e69d6e3b0eba31c9cdc5a812051a67d93e 100644 (file)
@@ -1,21 +1,21 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
 
    fast routines for getting the wire size of security objects
 
    Copyright (C) Andrew Tridgell 2003
    Copyright (C) Stefan Metzmacher 2006-2008
-   
+
    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/>.
 */
 #include "librpc/gen_ndr/ndr_security.h"
 #include "../libcli/security/security.h"
 
+
 /*
-  return the wire size of a security_ace
-*/
-size_t ndr_size_security_ace(const struct security_ace *ace, int flags)
+ * Find the wire size of a security_ace that has no trailing coda.
+ * This is used in ndr_pull_security_ace() generated from security.idl
+ * to work out where the coda starts (and in ndr_size_security_ace()
+ * just below).
+ */
+static size_t ndr_size_security_ace_core(const struct security_ace *ace, int flags)
 {
        size_t ret;
 
@@ -56,35 +60,41 @@ size_t ndr_size_security_ace(const struct security_ace *ace, int flags)
        return ret;
 }
 
-enum ndr_err_code ndr_pull_security_ace(struct ndr_pull *ndr, int ndr_flags, struct security_ace *r)
+/*
+  return the wire size of a security_ace
+*/
+size_t ndr_size_security_ace(const struct security_ace *ace, int flags)
 {
-       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;
+       size_t ret = ndr_size_security_ace_core(ace, flags);
+
+       ret += ndr_size_security_ace_coda(&ace->coda, ace->type, flags);
+
+       return ret;
+}
+
+/*
+ * An ACE coda can't be bigger than the space allowed for by
+ * ace->size, so we need to check this from the context of the ACE.
+ *
+ * Usually the coda also can't be any smaller than the remaining
+ * space, because it is defined as a blob consuming everything it can.
+ *
+ * This is only used to find the size for the coda subcontext in
+ * security.idl.
+ */
+size_t ndr_subcontext_size_of_ace_coda(const struct security_ace *ace,
+                                      size_t ace_size,
+                                      int flags)
+{
+       size_t core_size;
+       if (ace_size == 0) {
+               return 0;
        }
-       if (ndr_flags & NDR_BUFFERS) {
-               NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, r->type));
-               NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr, NDR_BUFFERS, &r->object));
+       core_size = ndr_size_security_ace_core(ace, flags);
+       if (ace_size < core_size) {
+               return 0;
        }
-       return NDR_ERR_SUCCESS;
+       return ace_size - core_size;
 }
 
 /*
@@ -109,7 +119,7 @@ size_t ndr_size_security_descriptor(const struct security_descriptor *sd, int fl
 {
        size_t ret;
        if (!sd) return 0;
-       
+
        ret = 20;
        ret += ndr_size_dom_sid(sd->owner_sid, flags);
        ret += ndr_size_dom_sid(sd->group_sid, flags);
@@ -177,7 +187,7 @@ enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct
        NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &num_auths));
        NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid));
        if (sid->num_auths != num_auths) {
-               return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
+               return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
                                      "Bad num_auths %u; should equal %u",
                                      num_auths, sid->num_auths);
        }
@@ -248,8 +258,8 @@ enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const
        }
 
        if (sid->num_auths > 5) {
-               return ndr_push_error(ndr, NDR_ERR_RANGE, 
-                                     "dom_sid28 allows only up to 5 sub auth [%u]", 
+               return ndr_push_error(ndr, NDR_ERR_RANGE,
+                                     "dom_sid28 allows only up to 5 sub auth [%u]",
                                      sid->num_auths);
        }
 
diff --git a/selftest/knownfail.d/ndrdump b/selftest/knownfail.d/ndrdump
new file mode 100644 (file)
index 0000000..b8e1dea
--- /dev/null
@@ -0,0 +1 @@
+^samba.tests.blackbox.ndrdump.+.NdrDumpTests.test_ndrdump_xattr_NTACL