]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
pidl: Add new ‘u16string’ type
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Sun, 19 Nov 2023 21:07:22 +0000 (10:07 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 20 Nov 2023 21:50:32 +0000 (21:50 +0000)
This type represents a UTF‐16–encoded string. These strings are kept
UTF‐16–encoded rather than converted to the Unix charset to be stored in
memory; this avoids issues regarding NULL termination and conversion
between character sets. We want to be able to handle strings that are
not valid UTF‐16.

Not bumping the NDR ABI version, because there hasn’t been an NDR
release since commit c4f281e9ae36c225b6003e0fa1cb8fb2e67bf543.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
librpc/ABI/ndr-4.0.0.sigs
librpc/ndr/libndr.h
librpc/ndr/ndr_string.c
pidl/lib/Parse/Pidl/NDR.pm
pidl/lib/Parse/Pidl/Samba4/Python.pm
pidl/lib/Parse/Pidl/Typelist.pm
pidl/tests/typelist.pl

index f88ca733aa7499e2eedc33c544b2728607affd02..66a1b64cf600caedd8a4a15a8da49450d546aa44 100644 (file)
@@ -81,6 +81,7 @@ ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
 ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
 ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
 ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_u16string: void (struct ndr_print *, const char *, const uint16_t *)
 ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
 ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
 ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
@@ -157,6 +158,7 @@ ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, time_t *)
 ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, struct timespec *)
 ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, struct timeval *)
 ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_u16string: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, const uint16_t **)
 ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint64_t *)
 ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint64_t *)
 ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uid_t *)
@@ -232,6 +234,7 @@ ndr_push_time_t: enum ndr_err_code (struct ndr_push *, ndr_flags_type, time_t)
 ndr_push_timespec: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const struct timespec *)
 ndr_push_timeval: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const struct timeval *)
 ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_u16string: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const uint16_t *)
 ndr_push_udlong: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint64_t)
 ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint64_t)
 ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uid_t)
index 0ccc0d2c33d9343d061f74eff79ed03003e26925..adcbdf18c0c9e16f7deef7d2954f2c479f5b6c64 100644 (file)
@@ -806,6 +806,7 @@ NDR_SCALAR_PROTO(DATA_BLOB, DATA_BLOB)
 NDR_SCALAR_PROTO(ipv4address, const char *)
 NDR_SCALAR_PROTO(ipv6address, const char *)
 NDR_SCALAR_PROTO(string, const char *)
+NDR_SCALAR_PROTO(u16string, const uint16_t *)
 NDR_SCALAR_PROTO(double, double)
 
 enum ndr_err_code ndr_pull_policy_handle(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct policy_handle *r);
index 64a466552065b649a77e270ebf68eec41637e907..0d18354a5dee1d65f9fe1a676f17cc9ceaa04e78 100644 (file)
@@ -476,6 +476,138 @@ _PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, ndr_flags
        return ret+strlen(*string)+1;
 }
 
+/**
+  pull a UTF‐16 string from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_u16string(struct ndr_pull *ndr,
+                                             ndr_flags_type ndr_flags,
+                                             const uint16_t **s)
+{
+       uint16_t *as = NULL;
+       const char *const src_str = (char *)ndr->data + ndr->offset;
+       size_t src_len = 0;
+
+       if (!(ndr_flags & NDR_SCALARS)) {
+               return NDR_ERR_SUCCESS;
+       }
+
+       if (ndr->flags & LIBNDR_ENCODING_FLAGS) {
+               return ndr_pull_error(
+                       ndr,
+                       NDR_ERR_STRING,
+                       "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS
+                       "passed to ndr_pull_u16string()\n",
+                       ndr->flags & LIBNDR_STRING_FLAGS);
+       }
+
+       switch (ndr->flags & LIBNDR_STRING_FLAGS) {
+       case LIBNDR_FLAG_STR_NULLTERM:
+               /*
+                * We ensure that src_len cannot equal 0 by
+                * requiring that there be enough bytes for at least
+                * the NULL terminator
+                */
+               NDR_PULL_NEED_BYTES(ndr, 2);
+               src_len = utf16_null_terminated_len_n(src_str,
+                                                     ndr->data_size -
+                                                             ndr->offset);
+               break;
+
+       default:
+               return ndr_pull_error(
+                       ndr,
+                       NDR_ERR_STRING,
+                       "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS
+                       "passed to ndr_pull_u16string()\n",
+                       ndr->flags & LIBNDR_STRING_FLAGS);
+       }
+
+       NDR_PULL_NEED_BYTES(ndr, src_len);
+       as = talloc_utf16_strlendup(ndr->current_mem_ctx,
+                                   src_str,
+                                   src_len);
+       if (as == NULL) {
+               return ndr_pull_error(ndr,
+                                     NDR_ERR_ALLOC,
+                                     "Failed to talloc_utf16_strlendup() in "
+                                     "ndr_pull_u16string()");
+       }
+
+       NDR_CHECK(ndr_pull_advance(ndr, src_len));
+       *s = as;
+
+       return NDR_ERR_SUCCESS;
+}
+
+/**
+  push a UTF‐16 string onto the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_u16string(struct ndr_push *ndr,
+                                             ndr_flags_type ndr_flags,
+                                             const uint16_t *s)
+{
+       size_t s_len;
+
+       if (!(ndr_flags & NDR_SCALARS)) {
+               return NDR_ERR_SUCCESS;
+       }
+
+       if (s == NULL) {
+               return ndr_push_error(
+                       ndr,
+                       NDR_ERR_INVALID_POINTER,
+                       "NULL pointer passed to ndr_push_u16string()");
+       }
+
+       s_len = utf16_null_terminated_len(s);
+       if (s_len > UINT32_MAX) {
+               return ndr_push_error(
+                       ndr,
+                       NDR_ERR_LENGTH,
+                       "length overflow in ndr_push_u16string()");
+       }
+
+       if (ndr->flags & LIBNDR_ENCODING_FLAGS) {
+               return ndr_push_error(
+                       ndr,
+                       NDR_ERR_STRING,
+                       "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS
+                       "passed to ndr_push_u16string()\n",
+                       ndr->flags & LIBNDR_STRING_FLAGS);
+       }
+
+       switch (ndr->flags & LIBNDR_STRING_FLAGS) {
+       case LIBNDR_FLAG_STR_NULLTERM:
+               NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)s, s_len));
+               break;
+
+       default:
+               if (ndr->flags & LIBNDR_FLAG_REMAINING) {
+                       NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)s, s_len));
+                       break;
+               }
+
+               return ndr_push_error(
+                       ndr,
+                       NDR_ERR_STRING,
+                       "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS
+                       "passed to ndr_push_u16string()\n",
+                       ndr->flags & LIBNDR_STRING_FLAGS);
+       }
+
+       return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_u16string(struct ndr_print *ndr,
+                                 const char *name,
+                                 const uint16_t *s)
+{
+       return ndr_print_array_uint8(ndr,
+                                    name,
+                                    (const uint8_t *)s,
+                                    utf16_len(s));
+}
+
 static uint32_t guess_string_array_size(struct ndr_pull *ndr, ndr_flags_type ndr_flags)
 {
        /*
index 259950959bde0e5c889ec0f66c1537a15ac6b30e..18db6cfe258a476ef426ce4f9b8fd39ad4997276 100644 (file)
@@ -66,6 +66,7 @@ my $scalar_alignment = {
        'udlongr' => 4,
        'DATA_BLOB' => 4,
        'string' => 4,
+       'u16string' => 4,
        'string_array' => 4, #???
        'time_t' => 4,
        'uid_t' => 8,
index 432f8724ba06a684d7edb7b318e791f308ecd77c..2f2574338595eaa1827bc78aee88706864dda069 100644 (file)
@@ -1700,6 +1700,27 @@ sub ConvertStringFromPythonData($$$$$)
        $self->pidl("}");
 }
 
+sub ConvertU16StringFromPythonData($$$$$)
+{
+       my ($self, $mem_ctx, $py_var, $target, $fail) = @_;
+
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("uint16_t *str = NULL;");
+       $self->pidl("");
+       $self->pidl("str = PyUtf16String_FromBytes(");
+       $self->pidl("   $mem_ctx, $py_var);");
+       $self->pidl("if (str == NULL) {");
+       $self->indent;
+       $self->pidl("$fail");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("$target = str;");
+       $self->deindent;
+       $self->pidl("}");
+}
+
 sub ConvertObjectFromPythonData($$$$$$;$$)
 {
        my ($self, $mem_ctx, $cvar, $ctype, $target, $fail, $location, $switch) = @_;
@@ -1854,6 +1875,12 @@ sub ConvertObjectFromPythonData($$$$$$;$$)
                return;
        }
 
+       if ($actual_ctype->{TYPE} eq "SCALAR" and
+               $actual_ctype->{NAME} eq "u16string") {
+               $self->ConvertU16StringFromPythonData($mem_ctx, $cvar, $target, $fail);
+               return;
+       }
+
        if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "NTSTATUS") {
                $self->pidl("$target = NT_STATUS(PyLong_AsLong($cvar));");
                return;
@@ -2086,6 +2113,10 @@ sub ConvertScalarToPython($$$$)
                return "PyString_FromStringOrNULL($cvar)";
        }
 
+       if ($ctypename eq "u16string") {
+               return "PyBytes_FromUtf16StringOrNULL($cvar)";
+       }
+
        # Not yet supported
        if ($ctypename eq "string_array") {
                return "pytalloc_GenericObject_reference_ex($mem_ctx, $cvar)";
index a0e92a49cf75b865930c4a82dac2b680c4b38b0c..09d416f7b20637d3cb936a245f58f4552162697f 100644 (file)
@@ -24,12 +24,13 @@ my %types = ();
 my @reference_scalars = (
        "string", "string_array", "nbt_string", "dns_string",
        "wrepl_nbt_name", "dnsp_name", "dnsp_string",
-       "ipv4address", "ipv6address"
+       "ipv4address", "ipv6address", "u16string"
 );
 
 my @non_fixed_size_scalars = (
        "string", "string_array", "nbt_string", "dns_string",
-       "wrepl_nbt_name", "dnsp_name", "dnsp_string"
+       "wrepl_nbt_name", "dnsp_name", "dnsp_string",
+       "u16string"
 );
 
 # a list of known scalar types
@@ -55,6 +56,7 @@ my %scalars = (
        "pointer"       => "void*",
        "DATA_BLOB"     => "DATA_BLOB",
        "string"        => "const char *",
+       "u16string"     => "const uint16_t *",
        "string_array"  => "const char **",
        "time_t"        => "time_t",
        "uid_t"         => "uid_t",
@@ -235,7 +237,7 @@ sub is_string_type
 {
        my ($t) = @_;
 
-       return ($t eq "string");
+       return ($t eq "string" or $t eq "u16string");
 }
 
 sub RegisterScalars()
index 5fc3ca25e06b9de0740c8c7c685920343ec09457..e012c8060dfb44f031f015b5dc3325cc32070c01 100755 (executable)
@@ -4,7 +4,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 57;
+use Test::More tests => 58;
 use FindBin qw($RealBin);
 use lib "$RealBin";
 use Util;
@@ -67,6 +67,7 @@ is(1, is_scalar({TYPE => "TYPEDEF", DATA => {TYPE => "ENUM" }}));
 is(1, is_scalar("mytypedef"));
 
 is(1, scalar_is_reference("string"));
+is(1, scalar_is_reference("u16string"));
 is(0, scalar_is_reference("uint32"));
 is(0, scalar_is_reference({TYPE => "STRUCT", NAME => "echo_foobar"}));