r23792: convert Samba4 to GPLv3
[tprouty/samba.git] / source4 / rpc_server / winreg / rpc_winreg.c
index 0a071ef7413e3eda80b1086833c008d9373c3b19..a71439e7c9496e5d0994dbb8cca171c5e93bc9e2 100644 (file)
@@ -7,7 +7,7 @@
    
    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 2 of the License, or
+   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,
    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, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "rpc_server/dcerpc_server.h"
+#include "lib/registry/registry.h"
+#include "librpc/gen_ndr/ndr_winreg.h"
 #include "rpc_server/common/common.h"
+#include "librpc/gen_ndr/ndr_security.h"
 
 enum handle_types { HTYPE_REGVAL, HTYPE_REGKEY };
 
-static void winreg_destroy_hive(struct dcesrv_connection *c, struct dcesrv_handle *h)
+static NTSTATUS dcerpc_winreg_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
 {
-       reg_close(((struct registry_key *)h->data)->hive->reg_ctx);
+       struct registry_context *ctx;
+       WERROR err;
+
+       err = reg_open_local(dce_call->context,
+                            &ctx, dce_call->conn->auth_state.session_info, NULL);
+
+       dce_call->context->private = ctx;
+
+       return NT_STATUS_OK;
 }
 
-static WERROR winreg_openhive (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, const char *hivename, struct policy_handle **outh)
+#define DCESRV_INTERFACE_WINREG_BIND dcerpc_winreg_bind
+
+static WERROR dcesrv_winreg_openhive (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, uint32_t hkey, struct policy_handle **outh)
 {
-       struct registry_context *ctx;
+       struct registry_context *ctx = dce_call->context->private;
        struct dcesrv_handle *h; 
        WERROR error;
-       const char *conf = lp_parm_string(-1, "registry", hivename);
-       char *backend, *location;
-       
-       if (!conf) {
-               return WERR_NOT_SUPPORTED;
-       }
 
-       backend = talloc_strdup(mem_ctx, conf);
-       location = strchr(backend, ':');
+       h = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY); 
 
-       if (location) {
-               *location = '\0';
-               location++;
+       error = reg_get_predefined_key(ctx, hkey, (struct registry_key **)&h->data);
+       if (!W_ERROR_IS_OK(error)) {
+               return error;
        }
-
-       error = reg_open(&ctx, backend, location, NULL); 
-       if(!W_ERROR_IS_OK(error)) return error; 
        
-       h = dcesrv_handle_new(dce_call->conn, HTYPE_REGKEY); 
-       h->data = ctx->hives[0]->root; 
-       SMB_ASSERT(h->data);
-       h->destroy = winreg_destroy_hive;
        *outh = &h->wire_handle; 
-       return WERR_OK; 
+
+       return error; 
 }
 
-#define func_winreg_OpenHive(k,n) static WERROR winreg_Open ## k (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_Open ## k *r) \
+#define func_winreg_OpenHive(k,n) static WERROR dcesrv_winreg_Open ## k (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_Open ## k *r) \
 { \
-       return winreg_openhive (dce_call, mem_ctx, n, &r->out.handle);\
+       return dcesrv_winreg_openhive (dce_call, mem_ctx, n, &r->out.handle);\
 }
 
-func_winreg_OpenHive(HKCR,"HKEY_CLASSES_ROOT")
-func_winreg_OpenHive(HKCU,"HKEY_CURRENT_USER")
-func_winreg_OpenHive(HKLM,"HKEY_LOCAL_MACHINE")
-func_winreg_OpenHive(HKPD,"HKEY_PERFORMANCE_DATA")
-func_winreg_OpenHive(HKU,"HKEY_USERS")
-func_winreg_OpenHive(HKCC,"HKEY_CC")
-func_winreg_OpenHive(HKDD,"HKEY_DD")
-func_winreg_OpenHive(HKPT,"HKEY_PT")
-func_winreg_OpenHive(HKPN,"HKEY_PN")
+func_winreg_OpenHive(HKCR,HKEY_CLASSES_ROOT)
+func_winreg_OpenHive(HKCU,HKEY_CURRENT_USER)
+func_winreg_OpenHive(HKLM,HKEY_LOCAL_MACHINE)
+func_winreg_OpenHive(HKPD,HKEY_PERFORMANCE_DATA)
+func_winreg_OpenHive(HKU,HKEY_USERS)
+func_winreg_OpenHive(HKCC,HKEY_CURRENT_CONFIG)
+func_winreg_OpenHive(HKDD,HKEY_DYN_DATA)
+func_winreg_OpenHive(HKPT,HKEY_PERFORMANCE_TEXT)
+func_winreg_OpenHive(HKPN,HKEY_PERFORMANCE_NLSTEXT)
 
 /* 
   winreg_CloseKey 
 */
-static WERROR winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_CloseKey *r)
+static WERROR dcesrv_winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                             struct winreg_CloseKey *r)
 {
        struct dcesrv_handle *h; 
 
-       h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       DCESRV_CHECK_HANDLE(h);
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
+       talloc_free(h);
 
-       dcesrv_handle_destroy(dce_call->conn, h);
+       ZERO_STRUCTP(r->out.handle);
 
        return WERR_OK;
 }
@@ -96,26 +97,41 @@ static WERROR winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *me
 /* 
   winreg_CreateKey 
 */
-static WERROR winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_CreateKey *r)
+static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                              struct winreg_CreateKey *r)
 {
        struct dcesrv_handle *h, *newh;
        WERROR error;
+       struct security_descriptor sd;
 
-       h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       DCESRV_CHECK_HANDLE(h);
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
        
-       newh = dcesrv_handle_new(dce_call->conn, HTYPE_REGKEY);
-
-       error = reg_key_add_name(newh, (struct registry_key *)h->data, r->in.key.name, 
-                                                        r->in.access_mask, 
-                                                        r->in.sec_desc?r->in.sec_desc->sd:NULL, 
-                                                        (struct registry_key **)&newh->data);
+       newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);
+
+       /* the security descriptor is optional */
+       if (r->in.secdesc != NULL) {
+               DATA_BLOB sdblob;
+               NTSTATUS status;
+               sdblob.data = r->in.secdesc->sd.data;
+               sdblob.length = r->in.secdesc->sd.len;
+               if (sdblob.data == NULL) {
+                       return WERR_INVALID_PARAM;
+               }
+               status = ndr_pull_struct_blob_all(&sdblob, mem_ctx, &sd, 
+                                                 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return WERR_INVALID_PARAM;
+               }
+       }
 
-       if(W_ERROR_IS_OK(error)) {
-               r->out.handle = &newh->wire_handle;
+       error = reg_key_add_name(newh, (struct registry_key *)h->data, r->in.name.name, 
+                                r->in.access_mask, 
+                                r->in.secdesc?&sd:NULL, 
+                                (struct registry_key **)&newh->data);
+       if (W_ERROR_IS_OK(error)) {
+               r->out.new_handle = &newh->wire_handle;
        } else {
-               dcesrv_handle_destroy(dce_call->conn, newh);
+               talloc_free(newh);
        }
 
        return error;
@@ -125,66 +141,57 @@ static WERROR winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *m
 /* 
   winreg_DeleteKey 
 */
-static WERROR winreg_DeleteKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_DeleteKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_DeleteKey *r)
 {
        struct dcesrv_handle *h;
-       struct registry_key *key;
-       WERROR result;
-
-       h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       DCESRV_CHECK_HANDLE(h);
 
-       result = reg_open_key(mem_ctx, (struct registry_key *)h->data, r->in.key.name, &key);
-
-       if (W_ERROR_IS_OK(result)) {
-               return reg_key_del(key);
-       }
-
-       return result;
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+       
+       return reg_key_del((struct registry_key *)h->data, r->in.key.name);
 }
 
 
 /* 
   winreg_DeleteValue 
 */
-static WERROR winreg_DeleteValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_DeleteValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_DeleteValue *r)
 {
        struct dcesrv_handle *h;
-       struct registry_value *value;
+       struct registry_key *key;
 
-       h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGVAL);
-       DCESRV_CHECK_HANDLE(h);
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 
-       value = h->data;
+       key = h->data;
        
-       /* FIXME */
-
-       return WERR_NOT_SUPPORTED;
+       return reg_del_value(key, r->in.value.name);
 }
 
 
 /* 
   winreg_EnumKey 
 */
-static WERROR winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_EnumKey *r)
 {
        struct dcesrv_handle *h;
        struct registry_key *key;
 
-       h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       DCESRV_CHECK_HANDLE(h);
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 
        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_p(mem_ctx, struct winreg_EnumKeyNameResponse);
-               r->out.out_name->name = key->name;
-               r->out.class = talloc_zero_p(mem_ctx, struct winreg_String);
-               r->out.last_changed_time = talloc_zero_p(mem_ctx, struct winreg_Time);
+               if (2*strlen_m_term(key->name) > r->in.name->size) {
+                       return WERR_MORE_DATA;
+               }
+               r->out.name->length = 2*strlen_m_term(key->name);
+               r->out.name->name = key->name;
+               r->out.keyclass = talloc_zero(mem_ctx, struct winreg_StringBuf);
+               if (r->in.last_changed_time) {
+                       r->out.last_changed_time = &key->last_mod;
+               }
        }
        
        return r->out.result;
@@ -194,24 +201,69 @@ static WERROR winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem
 /* 
   winreg_EnumValue 
 */
-static WERROR winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_EnumValue *r)
+static WERROR dcesrv_winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                              struct winreg_EnumValue *r)
 {
+       struct dcesrv_handle *h;
+       struct registry_key *key;
+       struct registry_value *value;
+       WERROR result;
 
-       return WERR_NOT_SUPPORTED;
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
+       key = h->data;
+
+       result = reg_key_get_value_by_index(mem_ctx, key, r->in.enum_index, &value);
+       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, enum winreg_Type);
+               *r->out.type = value->data_type;
+       }
+
+       /* check the client has enough room for the value */
+       if (r->in.value != NULL &&
+           r->in.size != NULL && 
+           value->data.length > *r->in.size) {
+               return WERR_MORE_DATA;
+       }
+       
+       /* and enough room for the name */
+       if (r->in.name->size < 2*strlen_m_term(value->name)) {
+               return WERR_MORE_DATA;          
+       }
+
+       r->out.name->name = value->name;
+       r->out.name->length = 2*strlen_m_term(value->name);
+       r->out.name->size = 2*strlen_m_term(value->name);
+
+       if (r->in.value) {
+               r->out.value = value->data.data;
+       }
+
+       if (r->in.size) {
+               r->out.size = talloc(mem_ctx, uint32_t);
+               *r->out.size = value->data.length;
+               r->out.length = r->out.size;
+       }
+       
+       return WERR_OK;
 }
 
 
 /* 
   winreg_FlushKey 
 */
-static WERROR winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_FlushKey *r)
 {
        struct dcesrv_handle *h;
 
-       h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       DCESRV_CHECK_HANDLE(h);
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 
        return reg_key_flush(h->data);
 }
@@ -220,9 +272,13 @@ static WERROR winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *me
 /* 
   winreg_GetKeySecurity 
 */
-static WERROR winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_GetKeySecurity *r)
 {
+       struct dcesrv_handle *h;
+
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
        return WERR_NOT_SUPPORTED;
 }
 
@@ -230,7 +286,7 @@ static WERROR winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_C
 /* 
   winreg_LoadKey 
 */
-static WERROR winreg_LoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_LoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_LoadKey *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -240,7 +296,7 @@ static WERROR winreg_LoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem
 /* 
   winreg_NotifyChangeKeyValue 
 */
-static WERROR winreg_NotifyChangeKeyValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_NotifyChangeKeyValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_NotifyChangeKeyValue *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -250,24 +306,27 @@ static WERROR winreg_NotifyChangeKeyValue(struct dcesrv_call_state *dce_call, TA
 /* 
   winreg_OpenKey 
 */
-static WERROR winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_OpenKey *r)
 {
        struct dcesrv_handle *h, *newh;
        WERROR result;
 
-       h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       DCESRV_CHECK_HANDLE(h);
-
-       newh = dcesrv_handle_new(dce_call->conn, HTYPE_REGKEY);
-
-       result = reg_open_key(newh, (struct registry_key *)h->data, 
-                               r->in.keyname.name, (struct registry_key **)&newh->data);
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.parent_handle, HTYPE_REGKEY);
 
+       if (r->in.keyname.name && strcmp(r->in.keyname.name, "") == 0) {
+               newh = talloc_reference(dce_call->context, h);
+               result = WERR_OK;
+       } else {
+               newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);
+               result = reg_open_key(newh, (struct registry_key *)h->data, 
+                                     r->in.keyname.name, (struct registry_key **)&newh->data);
+       }
+       
        if (W_ERROR_IS_OK(result)) {
                r->out.handle = &newh->wire_handle; 
        } else {
-               dcesrv_handle_destroy(dce_call->conn, newh);
+               talloc_free(newh);
        }
        
        return result;
@@ -277,27 +336,92 @@ static WERROR winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem
 /* 
   winreg_QueryInfoKey 
 */
-static WERROR winreg_QueryInfoKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_QueryInfoKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_QueryInfoKey *r)
 {
-       return WERR_NOT_SUPPORTED;
+       struct dcesrv_handle *h;
+       struct registry_key *k;
+       WERROR ret;
+
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
+       k = h->data;
+
+       ret = reg_key_num_subkeys(k, r->out.num_subkeys);
+       if (!W_ERROR_IS_OK(ret)) { 
+               return ret;
+       }
+
+       ret = reg_key_num_values(k, r->out.num_values);
+       if (!W_ERROR_IS_OK(ret)) { 
+               return ret;
+       }
+
+       ret = reg_key_subkeysizes(k, r->out.max_subkeysize, r->out.max_subkeylen);
+       if (!W_ERROR_IS_OK(ret)) { 
+               return ret;
+       }
+
+       ret = reg_key_valuesizes(k, r->out.max_valnamelen, r->out.max_valbufsize);
+       if (!W_ERROR_IS_OK(ret)) { 
+               return ret;
+       }
+
+       r->out.secdescsize = 0; /* FIXME */
+       ZERO_STRUCT(r->out.last_changed_time); /* FIXME */
+       if (!W_ERROR_IS_OK(ret)) { 
+               return ret;
+       }
+
+
+       return WERR_OK;
 }
 
 
 /* 
   winreg_QueryValue 
 */
-static WERROR winreg_QueryValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_QueryValue *r)
 {
-       return WERR_NOT_SUPPORTED;
+       struct dcesrv_handle *h;
+       struct registry_key *key;
+       struct registry_value *val;
+       WERROR result;
+
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
+       key = h->data;
+       
+       result = reg_key_get_value_by_name(mem_ctx, key, r->in.value_name.name, &val);
+
+       if (!W_ERROR_IS_OK(result)) { 
+               return result;
+       }
+
+       /* Just asking for the size of the buffer */
+       r->out.type = (enum winreg_Type *)&val->data_type;
+       r->out.length = talloc(mem_ctx, uint32_t);
+       if (!r->out.length) {
+               return WERR_NOMEM;
+       }
+       *r->out.length = val->data.length;
+       if (!r->in.data) {
+               r->out.size = talloc(mem_ctx, uint32_t);
+               *r->out.size = val->data.length;
+       } else {
+               r->out.size = r->in.size;
+               r->out.data = val->data.data;
+       }
+
+       return WERR_OK;
 }
 
 
 /* 
   winreg_ReplaceKey 
 */
-static WERROR winreg_ReplaceKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_ReplaceKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_ReplaceKey *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -307,7 +431,7 @@ static WERROR winreg_ReplaceKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *
 /* 
   winreg_RestoreKey 
 */
-static WERROR winreg_RestoreKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_RestoreKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_RestoreKey *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -317,7 +441,7 @@ static WERROR winreg_RestoreKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *
 /* 
   winreg_SaveKey 
 */
-static WERROR winreg_SaveKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_SaveKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_SaveKey *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -327,7 +451,7 @@ static WERROR winreg_SaveKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem
 /* 
   winreg_SetKeySecurity 
 */
-static WERROR winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_SetKeySecurity *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -337,17 +461,34 @@ static WERROR winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_C
 /* 
   winreg_SetValue 
 */
-static WERROR winreg_SetValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_SetValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_SetValue *r)
 {
-       return WERR_NOT_SUPPORTED;
+       struct dcesrv_handle *h;
+       struct registry_key *key;
+       WERROR result;
+       DATA_BLOB data;
+
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
+       key = h->data;
+       
+       data.data = r->in.data;
+       data.length = r->in.size;
+       result = reg_val_set(key, r->in.name.name, r->in.type, data);
+
+       if (!W_ERROR_IS_OK(result)) { 
+               return result;
+       }
+
+       return WERR_OK;
 }
 
 
 /* 
   winreg_UnLoadKey 
 */
-static WERROR winreg_UnLoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_UnLoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_UnLoadKey *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -357,7 +498,7 @@ static WERROR winreg_UnLoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *m
 /* 
   winreg_InitiateSystemShutdown 
 */
-static WERROR winreg_InitiateSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_InitiateSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_InitiateSystemShutdown *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -367,7 +508,7 @@ static WERROR winreg_InitiateSystemShutdown(struct dcesrv_call_state *dce_call,
 /* 
   winreg_AbortSystemShutdown 
 */
-static WERROR winreg_AbortSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_AbortSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_AbortSystemShutdown *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -377,17 +518,26 @@ static WERROR winreg_AbortSystemShutdown(struct dcesrv_call_state *dce_call, TAL
 /* 
   winreg_GetVersion 
 */
-static WERROR winreg_GetVersion(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_GetVersion *r)
+static WERROR dcesrv_winreg_GetVersion(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                               struct winreg_GetVersion *r)
 {
-       return WERR_NOT_SUPPORTED;
+       struct dcesrv_handle *h;
+
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
+       r->out.version = talloc(mem_ctx, uint32_t);
+       W_ERROR_HAVE_NO_MEMORY(r->out.version);
+
+       *r->out.version = 5;
+
+       return WERR_OK;
 }
 
 
 /* 
   winreg_QueryMultipleValues 
 */
-static WERROR winreg_QueryMultipleValues(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_QueryMultipleValues(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_QueryMultipleValues *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -397,7 +547,7 @@ static WERROR winreg_QueryMultipleValues(struct dcesrv_call_state *dce_call, TAL
 /* 
   winreg_InitiateSystemShutdownEx 
 */
-static WERROR winreg_InitiateSystemShutdownEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_InitiateSystemShutdownEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_InitiateSystemShutdownEx *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -407,7 +557,7 @@ static WERROR winreg_InitiateSystemShutdownEx(struct dcesrv_call_state *dce_call
 /* 
   winreg_SaveKeyEx 
 */
-static WERROR winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_SaveKeyEx *r)
 {
        return WERR_NOT_SUPPORTED;
@@ -417,7 +567,7 @@ static WERROR winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *m
 /* 
   winreg_QueryMultipleValues2 
 */
-static WERROR winreg_QueryMultipleValues2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_winreg_QueryMultipleValues2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct winreg_QueryMultipleValues2 *r)
 {
        return WERR_NOT_SUPPORTED;