]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
librpc/ndr: Use libndr compression for claims
authorAndrew Bartlett <abartlet@samba.org>
Thu, 16 Mar 2023 06:06:04 +0000 (19:06 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 31 Mar 2023 01:48:30 +0000 (01:48 +0000)
This ensures our python layer and C layer (in the KDC, when implementated)
use the same compression logic and so allows us to test the production
compression via the IDL-generated interfaces.

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
librpc/idl/claims.idl
librpc/ndr/ndr_claims.c [new file with mode: 0644]
librpc/ndr/ndr_claims.h [new file with mode: 0644]
librpc/wscript_build
python/samba/tests/krb5/raw_testcase.py

index ed84cd772c1db3718f6083ed5f09a3b17460f50a..388965a42397f39523c2d2071d065ca18799599a 100644 (file)
   uuid("bba9cb76-eb0c-462c-aa1b-5d8c34415701"),
   version(1.0),
   pointer_default(unique),
-  helpstring("Active Directory Claims")
+  helpstring("Active Directory Claims"),
+  helper("../librpc/ndr/ndr_claims.h")
 ]
 interface claims
 {
 #define wchar_t uint16
 #define CLAIM_ID [string, charset(UTF16)] wchar_t *
 
+       const int CLAIM_MINIMUM_BYTES_TO_COMPRESS = 384;
+
        typedef enum {
                CLAIM_TYPE_INT64 = 1,
                CLAIM_TYPE_UINT64 = 2,
@@ -98,7 +101,7 @@ interface claims
                [size_is(reserved_field_size)] uint8 *reserved_field;
        } CLAIMS_SET;
 
-       typedef [public] struct {
+       typedef [public, gensize] struct {
                [subcontext(0xFFFFFC01)] CLAIMS_SET_CTR claims;
        } CLAIMS_SET_NDR;
 
@@ -107,10 +110,37 @@ interface claims
        } CLAIMS_SET_METADATA_NDR;
 
        typedef [public] struct {
-               uint32 claims_set_size;
-               [size_is(claims_set_size)] uint8 *claims_set;
-               CLAIMS_COMPRESSION_FORMAT compression_format;
-               uint32 uncompressed_claims_set_size;
+               [value(ndr_claims_compressed_size(claims_set,
+                                                 r->compression_format,
+                                                 ndr->flags))] uint32 claims_set_size;
+               [subcontext(4),
+                compression(ndr_claims_compression_alg(compression_format),
+                            claims_set_size,
+                            uncompressed_claims_set_size)
+                       ] CLAIMS_SET_NDR *claims_set;
+               /*
+                * The second argument to
+                * ndr_claims_actual_wire_compression_alg() in the
+                * value() below should be
+                * uncompressed_claims_set_size but the value()
+                * handling isn't recursive (enough) so we have to
+                * specify that manually otherwise the
+                * compression_format in the above includes the struct
+                * member, not the value()
+                *
+                * The caller should set compression_format to
+                * CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF and this will
+                * be reset to CLAIMS_COMPRESSION_FORMAT_NONE if the
+                * buffer is not large enough to compress.
+                *
+                * Otherwise setting CLAIMS_COMPRESSION_FORMAT_NONE
+                * disabled compression entirely.
+                */
+               [value(ndr_claims_actual_wire_compression_alg(r->compression_format,
+                                                             ndr_size_CLAIMS_SET_NDR(claims_set,
+                                                                                     ndr->flags)))] CLAIMS_COMPRESSION_FORMAT compression_format;
+               [value(ndr_size_CLAIMS_SET_NDR(claims_set,
+                                              ndr->flags))] uint32 uncompressed_claims_set_size;
                uint16 reserved_type;
                uint32 reserved_field_size;
                [size_is(reserved_field_size)] uint8 *reserved_field;
diff --git a/librpc/ndr/ndr_claims.c b/librpc/ndr/ndr_claims.c
new file mode 100644 (file)
index 0000000..fbfe612
--- /dev/null
@@ -0,0 +1,84 @@
+#include "includes.h"
+#include "bin/default/librpc/gen_ndr/ndr_claims.h"
+#include "librpc/ndr/ndr_claims.h"
+
+#include "librpc/ndr/ndr_compression.h"
+#include "lib/compression/lzxpress_huffman.h"
+
+enum ndr_compression_alg ndr_claims_compression_alg(enum CLAIMS_COMPRESSION_FORMAT wire_alg)
+{
+       switch (wire_alg) {
+       case CLAIMS_COMPRESSION_FORMAT_NONE:
+               return NDR_COMPRESSION_NONE;
+
+       case CLAIMS_COMPRESSION_FORMAT_LZNT1:
+               return NDR_COMPRESSION_INVALID;
+
+       case CLAIMS_COMPRESSION_FORMAT_XPRESS:
+               return NDR_COMPRESSION_INVALID;
+
+       case CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF:
+               return NDR_COMPRESSION_XPRESS_HUFF_RAW;
+       }
+       return NDR_COMPRESSION_INVALID;
+}
+
+
+enum CLAIMS_COMPRESSION_FORMAT ndr_claims_actual_wire_compression_alg(enum CLAIMS_COMPRESSION_FORMAT specified_compression,
+                                                                     size_t uncompressed_claims_size) {
+       if (uncompressed_claims_size < CLAIM_MINIMUM_BYTES_TO_COMPRESS) {
+               return CLAIMS_COMPRESSION_FORMAT_NONE;
+       }
+
+       return specified_compression;
+}
+
+size_t ndr_claims_compressed_size(struct CLAIMS_SET_NDR *claims_set,
+                                 enum CLAIMS_COMPRESSION_FORMAT wire_alg,
+                                 int flags)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       DATA_BLOB tmp_blob;
+       uint8_t * tmp_compressed;
+       ssize_t compressed_size;
+       enum ndr_err_code ndr_err;
+       enum CLAIMS_COMPRESSION_FORMAT actual_wire_alg;
+
+       ndr_err = ndr_push_struct_blob(&tmp_blob,
+                                      frame,
+                                      claims_set,
+                                      (ndr_push_flags_fn_t)ndr_push_CLAIMS_SET_NDR);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DBG_ERR("Failed to push claims while determining compressed size");
+               TALLOC_FREE(frame);
+               return 0;
+       }
+
+       actual_wire_alg = ndr_claims_actual_wire_compression_alg(wire_alg,
+                                                                tmp_blob.length);
+
+       switch (actual_wire_alg) {
+       case CLAIMS_COMPRESSION_FORMAT_NONE:
+               TALLOC_FREE(frame);
+               return tmp_blob.length;
+
+       case CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF:
+               compressed_size = lzxpress_huffman_compress_talloc(frame,
+                                                                  tmp_blob.data,
+                                                                  tmp_blob.length,
+                                                                  &tmp_compressed);
+
+               TALLOC_FREE(frame);
+
+               if (compressed_size < 0) {
+                       DBG_ERR("Failed to compress claims (for determining compressed size)");
+                       return 0;
+               }
+               return compressed_size;
+
+       default:
+               TALLOC_FREE(frame);
+               DBG_ERR("Invalid chosen compression algorithm while determining compressed claim size");
+               return 0;
+       }
+}
diff --git a/librpc/ndr/ndr_claims.h b/librpc/ndr/ndr_claims.h
new file mode 100644 (file)
index 0000000..03f4046
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   routines for helping the compression in claims
+
+   Copyright (C) Andrew Bartlett 2023
+
+   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/>.
+*/
+
+#ifndef _LIBRPC_NDR_NDR_CLAIMS_H
+#define _LIBRPC_NDR_NDR_CLAIMS_H
+
+enum ndr_compression_alg ndr_claims_compression_alg(enum CLAIMS_COMPRESSION_FORMAT wire_alg);
+enum CLAIMS_COMPRESSION_FORMAT ndr_claims_actual_wire_compression_alg(enum CLAIMS_COMPRESSION_FORMAT specified_compression,
+                                                                     size_t uncompressed_claims_size);
+
+size_t ndr_claims_compressed_size(struct CLAIMS_SET_NDR *claims_set,
+                                enum CLAIMS_COMPRESSION_FORMAT wire_alg,
+                                int flags);
+
+
+#endif /* _LIBRPC_NDR_NDR_CLAIMS_H */
index b474646be446f5c2fa17be0474f9274cbefed21a..cd1988033d2953c8512511ac3ead3d8d484650ee 100644 (file)
@@ -385,8 +385,8 @@ bld.SAMBA_SUBSYSTEM('NDR_KRB5CCACHE',
     )
 
 bld.SAMBA_SUBSYSTEM('NDR_CLAIMS',
-    source='gen_ndr/ndr_claims.c',
-    deps='ndr')
+    source='gen_ndr/ndr_claims.c ndr/ndr_claims.c',
+    deps='ndr NDR_COMPRESSION LZXPRESS')
 
 bld.SAMBA_LIBRARY('ndr-standard',
     source='',
index 1d117c7e21e83db164e44359675c36135fbf82c3..8e85647880314673be2abeadf13e3d00a3c94dae 100644 (file)
@@ -3669,21 +3669,14 @@ class RawKerberosTest(TestCaseInTempDir):
                                      f'got empty CLAIMS_SET_METADATA_NDR '
                                      f'inner structure {empty_msg}')
 
-                claims_data = bytes(client_claims.claims_set)
-                self.assertIsNotNone(claims_data,
+                self.assertIsNotNone(client_claims.claims_set,
                                      f'got empty CLAIMS_SET_METADATA '
                                      f'structure {empty_msg}')
-                self.assertGreater(len(claims_data), 0,
-                                   f'got empty encoded claims data '
-                                   f'{empty_msg}')
-                self.assertEqual(len(claims_data),
-                                 client_claims.claims_set_size,
-                                 f'encoded {claims_type} data size mismatch')
 
                 uncompressed_size = client_claims.uncompressed_claims_set_size
                 compression_format = client_claims.compression_format
 
-                if uncompressed_size < 384:
+                if uncompressed_size < claims.CLAIM_MINIMUM_BYTES_TO_COMPRESS:
                     self.assertEqual(claims.CLAIMS_COMPRESSION_FORMAT_NONE,
                                      compression_format,
                                      f'{claims_type} unexpectedly '
@@ -3696,12 +3689,7 @@ class RawKerberosTest(TestCaseInTempDir):
                         f'{claims_type} unexpectedly not compressed '
                         f'({uncompressed_size} bytes uncompressed)')
 
-                    claims_data = huffman_decompress(claims_data,
-                                                     uncompressed_size)
-
-                claims_set = ndr_unpack(claims.CLAIMS_SET_NDR,
-                                        claims_data)
-                claims_set = claims_set.claims.claims
+                claims_set = client_claims.claims_set.claims.claims
                 self.assertIsNotNone(claims_set,
                                      f'got empty CLAIMS_SET_NDR inner '
                                      f'structure {empty_msg}')