r9338: fixed the winreg IDL to be correct for the EnumKey and EnumValue
authorAndrew Tridgell <tridge@samba.org>
Wed, 17 Aug 2005 01:25:58 +0000 (01:25 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:33:25 +0000 (13:33 -0500)
calls. The previous IDL was just a workaround for the limitations of
our older rpc infrastructure. Now that Jelmer has added much improved
string support using the charset keyword we can correctly implemenent
the unusual winreg string buffers.

Jelmer, note the little comment I put on winreg_StringBuf() about why
I couldn't use [value()] for the length field.

This also fixes EnumKey() and EnumValue() to use NTTIME fields for the
last_changed_time. I don't know why we were using a pair of uint32's,
as it is just a NTTIME.

source/lib/registry/reg_backend_rpc.c
source/librpc/idl/winreg.idl
source/rpc_server/winreg/rpc_winreg.c
source/scripting/libjs/winreg.js
source/torture/rpc/winreg.c

index 73d2d546876eac232452515a5acd6155b3f66e04..5734b967704e3e42df59847316d32484d5771459 100644 (file)
@@ -177,8 +177,8 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *p
        struct winreg_EnumValue r;
        uint32_t type, len1, zero = 0;
        NTSTATUS status;
-       uint8_t buf8;
-       uint16_t buf16;
+       struct winreg_StringBuf name;
+       uint8_t u8;
        
        if(mykeydata->num_values == -1) {
                error = rpc_query_key(parent);
@@ -187,17 +187,18 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *p
 
        len1 = mykeydata->max_valdatalen;
        
+       name.length = 0;
+       name.size   = mykeydata->max_valnamelen * 2;
+       name.name   = "";
+
        r.in.handle = &mykeydata->pol;
        r.in.enum_index = n;
-       r.in.name_in.length = 0;
-       r.in.name_in.size = mykeydata->max_valnamelen * 2;
-       r.in.name_in.name = &buf16;
+       r.in.name = &name;
        r.in.type = &type;
-       r.in.value = &buf8;
+       r.in.value = &u8;
        r.in.length = &zero;
        r.in.size = &len1;
-       r.out.type = &type;
-
+       r.out.name = &name;
        
        status = dcerpc_winreg_EnumValue((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
        if(NT_STATUS_IS_ERR(status)) {
@@ -208,7 +209,7 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *p
        if(NT_STATUS_IS_OK(status) && 
           W_ERROR_IS_OK(r.out.result) && r.out.length) {
                *value = talloc(mem_ctx, struct registry_value);
-               (*value)->name = talloc_strdup(mem_ctx, r.out.name_out.name);
+               (*value)->name = talloc_strdup(mem_ctx, r.out.name->name);
                (*value)->data_type = type;
                (*value)->data_len = *r.out.length;
                (*value)->data_blk = talloc_memdup(mem_ctx, r.out.value, *r.out.length);
@@ -221,27 +222,29 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *p
 static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx, struct registry_key *parent, int n, struct registry_key **subkey) 
 {
        struct winreg_EnumKey r;
-       struct winreg_EnumKeyNameRequest keyname;
-       struct winreg_String classname;
-       struct winreg_Time tm;
        struct rpc_key_data *mykeydata = parent->backend_data;
        NTSTATUS status;
+       struct winreg_StringBuf namebuf, classbuf;
+       NTTIME change_time = 0;
 
-       r.in.handle = &mykeydata->pol;
-       keyname.unknown = 0x0000020a;
-       init_winreg_String(&keyname.key_name, NULL);
-       init_winreg_String(&classname, NULL);
-       r.in.in_name = &keyname;
-       r.in.class = &classname;
-       tm.low = tm.high = 0x7fffffff;
-       r.in.last_changed_time = &tm;
+       namebuf.length = 0;
+       namebuf.size   = 1024;
+       namebuf.name   = NULL;
+       classbuf.length = 0;
+       classbuf.size   = 0;
+       classbuf.name   = NULL;
 
+       r.in.handle = &mykeydata->pol;
        r.in.enum_index = n;
-       r.in.unknown = r.out.unknown = 0x0414;
-       r.in.key_name_len = r.out.key_name_len = 0;
+       r.in.name = &namebuf;
+       r.in.class = &classbuf;
+       r.in.last_changed_time = &change_time;
+       r.out.name = &namebuf;
+
        status = dcerpc_winreg_EnumKey((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
        if(NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) {
-                       return rpc_open_key(mem_ctx, parent, talloc_strdup(mem_ctx, r.out.out_name->name), subkey);
+               char *name = talloc_strdup(mem_ctx, r.out.name->name);
+               return rpc_open_key(mem_ctx, parent, name, subkey);
        }
 
        return r.out.result;
index ad77138478fc0c7300cfdcec871419cbbeef4e68..3e29bfcc1c531ce9d55ec22f42128ece9b5213cd 100644 (file)
        } winreg_Time;
 
        typedef struct {
-               uint32 unknown;
-               winreg_String key_name;
-       } winreg_EnumKeyNameRequest;
-
-       typedef struct {
-               uint32 unknown1;
-               uint32 unknown2;
-               lstring name;
-       } winreg_EnumKeyNameResponse;
+               /* we can't use value(strlen_m(name)*2) here as it
+                  doesn't propogate to the length_is() property
+                  below. Jelmer, can this be fixed? */
+               uint16 length; 
+               uint16 size;
+               [size_is(size/2),length_is(length/2),charset(UTF16)] uint16 *name;
+       } winreg_StringBuf;
 
-       /******************/
-       /* Function: 0x09 */
        WERROR winreg_EnumKey(
-               [in,ref]    policy_handle *handle,
-               [in] uint32 enum_index,
-               [in,out]    uint16 key_name_len,
-               [in,out]    uint16 unknown,
-               [in]        winreg_EnumKeyNameRequest *in_name,
-               [out]       winreg_EnumKeyNameResponse *out_name,
-               [in,out]    winreg_String *class,
-               [in,out]    winreg_Time *last_changed_time
+               [in,ref]        policy_handle    *handle,
+               [in]            uint32           enum_index,
+               [in,out,ref]    winreg_StringBuf *name,
+               [in,out,unique] winreg_StringBuf *class,
+               [in,out,unique] NTTIME           *last_changed_time
        );
 
        /******************/
        /* Function: 0x0a */
 
-       /* 
-          this is equivalent IDL to a winreg_String, but we need to
-          have absolute control over the length/size fields as the
-          server looks at those to see what size buffer we have, so
-          we can't use the automatic unistr handing in pidl.
-       */
-       typedef struct {
-               uint16 length;
-               uint16 size;
-               [size_is(size/2),length_is(length/2)] uint16 *name;
-       } winreg_EnumValueString;
-
        WERROR winreg_EnumValue(
-               [in,ref] policy_handle *handle,
-               [in]     uint32 enum_index,
-               [in]     winreg_EnumValueString name_in,
-               [out]    winreg_String name_out,
-               [in,out] uint32 *type,
-               [in,out,size_is(*size),length_is(*length)] uint8 *value,
-               [in,out] uint32 *size,
-               [in,out] uint32 *length
+               [in,ref]        policy_handle *handle,
+               [in]            uint32 enum_index,
+               [in,out,ref]    winreg_StringBuf *name,
+               [in,out,unique] uint32 *type,
+               [in,out,unique,size_is(*size),length_is(*length)] uint8 *value,
+               [in,out,unique] uint32 *size,
+               [in,out,unique] uint32 *length
        );
 
        /******************/
index 050df2972717608ce8320b1c23e18f79a399e670..431323d1b6070d70e6d51fcad820fc1216ba69ae 100644 (file)
@@ -166,11 +166,13 @@ static WERROR winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem
        r->out.result = reg_key_get_subkey_by_index(mem_ctx, (struct registry_key *)h->data, r->in.enum_index, &key);
 
        if (W_ERROR_IS_OK(r->out.result)) {
-               r->out.key_name_len = strlen(key->name);
-               r->out.out_name = talloc_zero(mem_ctx, struct winreg_EnumKeyNameResponse);
-               r->out.out_name->name = key->name;
-               r->out.class = talloc_zero(mem_ctx, struct winreg_String);
-               r->out.last_changed_time = talloc_zero(mem_ctx, struct winreg_Time);
+               if (2*strlen_m(key->name) > r->in.name->size) {
+                       return WERR_MORE_DATA;
+               }
+               r->out.name->length = 2*strlen_m(key->name);
+               r->out.name->name = key->name;
+               r->out.class = talloc_zero(mem_ctx, struct winreg_StringBuf);
+               r->out.last_changed_time = &key->last_mod;
        }
        
        return r->out.result;
@@ -196,14 +198,38 @@ static WERROR winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *m
        if (!W_ERROR_IS_OK(result)) {
                return result;
        }
+
+       /* the client can optionally pass a NULL for type, meaning they don't
+          want that back */
+       if (r->in.type != NULL) {
+               r->out.type = talloc(mem_ctx, uint32_t);
+               *r->out.type = value->data_type;
+       }
+
+       /* check the client has enough room for the value */
+       if (r->in.size != NULL && 
+           value->data_len > *r->in.size) {
+               return WERR_MORE_DATA;
+       }
        
-       r->out.type = talloc(mem_ctx, uint32_t);
-       *r->out.type = value->data_type;
-       r->out.name_out.name = value->name;
-       r->out.value = value->data_blk;
-       r->out.size = talloc(mem_ctx, uint32_t);
-       r->out.length = r->out.size;
-       *r->out.size = value->data_len;
+       /* and enough room for the name */
+       if (r->in.name->size < 2*strlen_m(value->name)) {
+               return WERR_MORE_DATA;          
+       }
+
+       r->out.name->name = value->name;
+       r->out.name->length = 2*strlen_m(value->name);
+       r->out.name->size = 2*strlen_m(value->name);
+
+       if (r->in.value) {
+               r->out.value = value->data_blk;
+       }
+
+       if (r->in.size) {
+               r->out.size = talloc(mem_ctx, uint32_t);
+               *r->out.size = value->data_len;
+               r->out.length = r->out.size;
+       }
        
        return WERR_OK;
 }
index 703b8da2a724b1085e6e9ddbf56209cfce40b802..5323e91ae5c9dc4ec7f784452518b22f4b8d6ae6 100644 (file)
@@ -4,6 +4,18 @@
        released under the GNU GPL v2 or later
 */     
 
+libinclude("base.js");
+
+/*
+  close a handle
+*/
+function winreg_close(reg, handle)
+{
+       var io = irpcObj();
+       io.input.handle = handle;
+       reg.winreg_CloseKey(io);
+}
+
 
 /*
   open a hive
@@ -76,6 +88,9 @@ function winreg_open_path(reg, path)
        io.input.unknown = 0;
        io.input.access_mask = reg.SEC_FLAG_MAXIMUM_ALLOWED;
        var status = reg.winreg_OpenKey(io);
+
+       winreg_close(reg, handle);
+
        if (!status.is_ok) {
                return undefined;
        }
@@ -100,38 +115,116 @@ function winreg_enum_path(reg, path)
                return new Array("HKLM", "HKU");
        }
        
-       handle = winreg_open_path(reg, path);
+       var handle = winreg_open_path(reg, path);
        if (handle == undefined) {
                return undefined;
        }
 
        var io = irpcObj();
-       var wtime = new Object();
-       wtime.low  = 2147483647;
-       wtime.high = 2147483647;
-       var keyname = new Object();
-       keyname.unknown  = 522;
-       keyname.key_name = NULL;
-
        io.input.handle            = handle;
-       io.input.key_name_len      = 0;
-       io.input.unknown           = 1044;
-       io.input.in_name           = keyname;
-       io.input.class             = "";
-       io.input.last_changed_time = wtime;
-       
+       io.input.name = new Object();
+       io.input.name.length = 0;
+       io.input.name.size   = 32;
+       io.input.name.name   = NULL;
+       io.input.class = new Object();
+       io.input.class.length = 0;
+       io.input.class.size   = 1024;
+       io.input.class.name   = NULL;
+       io.input.last_changed_time = 0;
+
        var idx = 0;
        for (idx=0;idx >= 0;idx++) {
-               io.input.enum_index        = idx;
+               io.input.enum_index = idx;
                var status = reg.winreg_EnumKey(io);
-               if (!status.is_ok) return;
+               if (!status.is_ok) {
+                       winreg_close(reg, handle);
+                       return;
+               }
+               var out = io.output;
+               if (out.result == "WERR_MORE_DATA") {
+                       io.input.name.size = io.input.name.size * 2;
+                       idx--;
+                       if (io.input.name.size > 32000) {
+                               winreg_close(reg, handle);
+                               return undefined;
+                       }
+                       continue;
+               }
+               if (out.result != "WERR_OK") {
+                       winreg_close(reg, handle);
+                       return list;
+               }
+               list[list.length] = out.name.name;
+               list.length++;
+       }
+
+       winreg_close(reg, handle);
+       return list;
+}
+
+
+/*
+       return a list of values for a winreg server given a path
+       usage:
+          list = winreg_enum_values(reg, path);
+
+       each returned list element is an object containing a name, a
+       type and a value
+*/
+function winreg_enum_values(reg, path)
+{
+       var list = new Object();
+       list.length = 0;
+
+       var handle = winreg_open_path(reg, path);
+       if (handle == undefined) {
+               return undefined;
+       }
+
+       var io = irpcObj();
+       io.input.handle      = handle;
+       io.input.name        = new Object();
+       io.input.name.length = 0;
+       io.input.name.size   = 128;
+       io.input.name.name   = "";
+       io.input.type        = 0;
+       io.input.value       = new Array(0);
+       io.input.size        = 1024;
+       io.input.length      = 0;
+
+       var idx;
+       for (idx=0;idx >= 0;idx++) {
+               io.input.enum_index = idx;
+               var status = reg.winreg_EnumValue(io);
+               if (!status.is_ok) {
+                       winreg_close(reg, handle);
+                       return;
+               }
                var out = io.output;
+               if (out.result == "WERR_MORE_DATA") {
+                       io.input.size = io.input.size * 2;
+                       io.input.name.size = io.input.name.size * 2;
+                       idx--;
+                       /* limit blobs to 1M */
+                       if (io.input.size > 1000000) {
+                               winreg_close(reg, handle);
+                               return undefined;
+                       }
+                       continue;
+               }
                if (out.result != "WERR_OK") {
+                       winreg_close(reg, handle);
                        return list;
                }
-               list[list.length] = out.out_name.name;
+               var el   = new Object();
+               el.name  = out.name.name;
+               el.type  = out.type;
+               el.value = out.value;
+               el.size  = out.size;
+               list[list.length] = el;
                list.length++;
        }
 
+       winreg_close(reg, handle);
        return list;
 }
index 969bba069152ac99d52429feb7afd4f60e4829f9..7d40147a8dbdd39a838b44071c3b0bff84effcad 100644 (file)
@@ -223,7 +223,7 @@ static BOOL test_OpenKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.handle = hive_handle;
        init_winreg_String(&r.in.keyname, keyname);
        r.in.unknown = 0x00000000;
-       r.in.access_mask = 0x02000000;
+       r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        r.out.handle = key_handle;
 
        status = dcerpc_winreg_OpenKey(p, mem_ctx, &r);
@@ -301,35 +301,37 @@ static BOOL test_EnumKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                         struct policy_handle *handle, int depth)
 {
        struct winreg_EnumKey r;
-       struct winreg_EnumKeyNameRequest keyname;
-       struct winreg_String classname;
-       struct winreg_Time tm;
+       struct winreg_StringBuf class, name;
        NTSTATUS status;
+       NTTIME t = 0;
 
        printf("Testing EnumKey\n\n");
 
+       class.length = 0;
+       class.size   = 0;
+       class.name   = NULL;
+
        r.in.handle = handle;
        r.in.enum_index = 0;
-       r.in.key_name_len = r.out.key_name_len = 0;
-       r.in.unknown = r.out.unknown = 0x0414;
-       keyname.unknown = 0x0000020a;
-       init_winreg_String(&keyname.key_name, NULL);
-       init_winreg_String(&classname, NULL);
-       r.in.in_name = &keyname;
-       r.in.class = &classname;
-       tm.low = tm.high = 0x7fffffff;
-       r.in.last_changed_time = &tm;
+       r.in.name = &name;
+       r.in.class = &class;
+       r.out.name = &name;
+       r.in.last_changed_time = &t;
 
        do {
+               name.length = 0;
+               name.size   = 1024;
+               name.name   = NULL;
+
                status = dcerpc_winreg_EnumKey(p, mem_ctx, &r);
 
                if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) {
                        struct policy_handle key_handle;
 
-                       printf("EnumKey: %d: %s\n", r.in.enum_index, r.out.out_name->name);
+                       printf("EnumKey: %d: %s\n", r.in.enum_index, r.out.name->name);
 
                        if (!test_OpenKey(
-                                   p, mem_ctx, handle, r.out.out_name->name,
+                                   p, mem_ctx, handle, r.out.name->name,
                                    &key_handle)) {
                        } else {
                                test_key(p, mem_ctx, &key_handle, depth + 1);
@@ -433,15 +435,18 @@ static BOOL test_EnumValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        uint32_t size = max_valbufsize, zero = 0;
        BOOL ret = True;
        uint8_t buf8;
-       uint16_t buf16;
+       struct winreg_StringBuf name;
 
        printf("testing EnumValue\n");
 
+       name.length = 0;
+       name.size   = 1024;
+       name.name   = "";
+
        r.in.handle = handle;
        r.in.enum_index = 0;
-       r.in.name_in.length = 0;
-       r.in.name_in.size = 0x200;
-       r.in.name_in.name = &buf16;
+       r.in.name = &name;
+       r.out.name = &name;
        r.in.type = &type;
        r.in.value = &buf8;
        r.in.length = &zero;
@@ -455,8 +460,8 @@ static BOOL test_EnumValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                }
 
                if (W_ERROR_IS_OK(r.out.result)) {
-                       ret &= test_QueryValue(p, mem_ctx, handle, r.out.name_out.name);
-                       ret &= test_QueryMultipleValues(p, mem_ctx, handle, r.out.name_out.name);
+                       ret &= test_QueryValue(p, mem_ctx, handle, r.out.name->name);
+                       ret &= test_QueryMultipleValues(p, mem_ctx, handle, r.out.name->name);
                }
 
                r.in.enum_index++;