r23792: convert Samba4 to GPLv3
[tprouty/samba.git] / source4 / rpc_server / winreg / rpc_winreg.c
index d6012c4dd4b2a907e4ef8d14b447d5dffa8cfcba..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"
 
-/**
- * General notes for the current implementation:
- * 
- * - All hives are currently openened as subkeys of one single registry file 
- *   (e.g. HKCR from \HKEY_CURRENT_USER, etc). This might be changed in 
- *   the future and we might want to make it possible to configure 
- *   what registries are behind which hives (e.g. 
- *     \HKEY_CURRENT_USER -> gconf,
- *     \HKEY_LOCAL_MACHINE -> tdb,
- *     etc
- */
+enum handle_types { HTYPE_REGVAL, HTYPE_REGKEY };
 
-enum handle_types { HTYPE_REGKEY, HTYPE_REGVAL };
+static NTSTATUS dcerpc_winreg_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
+{
+       struct registry_context *ctx;
+       WERROR err;
 
-struct _privatedata {
-       REG_HANDLE *registry;
-};
+       err = reg_open_local(dce_call->context,
+                            &ctx, dce_call->conn->auth_state.session_info, NULL);
 
+       dce_call->context->private = ctx;
 
-/* this function is called when the client disconnects the endpoint */
-static void winreg_unbind(struct dcesrv_connection *dc, const struct dcesrv_interface *di) 
-{
-       struct _privatedata *data = dc->private;
-       if (data) reg_free(data->registry);
+       return NT_STATUS_OK;
 }
 
-static NTSTATUS winreg_bind(struct dcesrv_call_state *dc, const struct dcesrv_interface *di) 
+#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 _privatedata *data;
+       struct registry_context *ctx = dce_call->context->private;
+       struct dcesrv_handle *h; 
        WERROR error;
-       data = talloc(dc->conn->mem_ctx, sizeof(struct _privatedata));
-       error = reg_open("dir", "/tmp/reg", "", &data->registry);
-       if(!W_ERROR_IS_OK(error)) return werror_to_ntstatus(error);
-       dc->conn->private = data;
-       return NT_STATUS_OK;
-}
 
-#define DCESRV_INTERFACE_WINREG_BIND winreg_bind
-#define DCESRV_INTERFACE_WINREG_UNBIND winreg_unbind
+       h = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY); 
 
-#define func_winreg_OpenHive(k,n) static NTSTATUS winreg_Open ## k (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_Open ## k *r) \
+       error = reg_get_predefined_key(ctx, hkey, (struct registry_key **)&h->data);
+       if (!W_ERROR_IS_OK(error)) {
+               return error;
+       }
+       
+       *outh = &h->wire_handle; 
+
+       return error; 
+}
+
+#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) \
 { \
-       /*struct _privatedata *data = dce_call->conn->private;*/ \
-       /*REG_KEY *root = reg_get_root(data->registry);*/ \
-       REG_KEY *k /*= reg_open_key(root, n)*/; \
-\
-       if(!k) { \
-               r->out.result = WERR_BADFILE; \
-       } else { \
-               struct dcesrv_handle *h = dcesrv_handle_new(dce_call->conn, HTYPE_REGKEY); \
-               h->data = k; \
-               r->out.handle = &h->wire_handle; \
-       } \
-\
-       r->out.result = WERR_OK; \
-\
-       return NT_STATUS_OK; \
+       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 NTSTATUS 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 = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       if(!h) {
-               return NT_STATUS_INVALID_HANDLE;
-       }
+       struct dcesrv_handle *h; 
 
-       reg_key_free((REG_KEY *)h->data);
-       dcesrv_handle_destroy(dce_call->conn, h);
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 
-       return NT_STATUS_OK;
+       talloc_free(h);
+
+       ZERO_STRUCTP(r->out.handle);
+
+       return WERR_OK;
 }
 
 
 /* 
   winreg_CreateKey 
 */
-static NTSTATUS 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 = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
+       struct dcesrv_handle *h, *newh;
        WERROR error;
-       REG_KEY *parent;
-       if(!h) {
-               return NT_STATUS_INVALID_HANDLE;
-       }
+       struct security_descriptor sd;
 
-       parent = h->data;
-       error = reg_key_add_name_recursive(parent, r->in.key.name);
-       if(W_ERROR_IS_OK(error)) {
-               struct dcesrv_handle *newh = dcesrv_handle_new(dce_call->conn, HTYPE_REGKEY);
-               error = reg_open_key(parent, r->in.key.name, (REG_KEY **)&newh->data);
-               if(W_ERROR_IS_OK(error)) r->out.handle = &newh->wire_handle;
-               else dcesrv_handle_destroy(dce_call->conn, newh);
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+       
+       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;
+               }
        }
 
-       r->out.result = error;
+       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 {
+               talloc_free(newh);
+       }
 
-       return NT_STATUS_OK;
+       return error;
 }
 
 
 /* 
   winreg_DeleteKey 
 */
-static NTSTATUS 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 = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       REG_KEY *parent, *key;
-       if(!h) {
-               return NT_STATUS_INVALID_HANDLE;
-       }
+       struct dcesrv_handle *h;
 
-       parent = h->data;
-       r->out.result = reg_open_key(parent, r->in.key.name, &key);
-       if(W_ERROR_IS_OK(r->out.result)) {
-               r->out.result = reg_key_del(key);
-       }
-       return NT_STATUS_OK;
+       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 NTSTATUS 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)
 {
-       return NT_STATUS_NOT_IMPLEMENTED;
+       struct dcesrv_handle *h;
+       struct registry_key *key;
+
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
+       key = h->data;
+       
+       return reg_del_value(key, r->in.value.name);
 }
 
 
 /* 
   winreg_EnumKey 
 */
-static NTSTATUS 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 = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       REG_KEY *key;
-       if(!h) {
-               return NT_STATUS_INVALID_HANDLE;
+       struct dcesrv_handle *h;
+       struct registry_key *key;
+
+       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)) {
+               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;
+               }
        }
-
-       key = h->data;
        
-       return NT_STATUS_NOT_IMPLEMENTED;
+       return r->out.result;
 }
 
 
 /* 
   winreg_EnumValue 
 */
-static NTSTATUS 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)
 {
-       return NT_STATUS_NOT_IMPLEMENTED;
+       struct dcesrv_handle *h;
+       struct registry_key *key;
+       struct registry_value *value;
+       WERROR result;
+
+       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 NTSTATUS 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)
 {
-       return NT_STATUS_NOT_IMPLEMENTED;
+       struct dcesrv_handle *h;
+
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
+       return reg_key_flush(h->data);
 }
 
 
 /* 
   winreg_GetKeySecurity 
 */
-static NTSTATUS 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)
 {
-       return NT_STATUS_NOT_IMPLEMENTED;
+       struct dcesrv_handle *h;
+
+       DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
+
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_LoadKey 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_NotifyChangeKeyValue 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_OpenKey 
 */
-static NTSTATUS 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 = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY);
-       REG_KEY *k, *subkey;
-       if(!h) {
-               return NT_STATUS_INVALID_HANDLE;
+       struct dcesrv_handle *h, *newh;
+       WERROR result;
+
+       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);
        }
-
-       k = h->data;
-
-
-       r->out.result = reg_open_key(k, r->in.keyname.name, &subkey);
-       if(W_ERROR_IS_OK(r->out.result)) {
-               h->data = subkey; 
-               r->out.handle = &h->wire_handle; 
+       
+       if (W_ERROR_IS_OK(result)) {
+               r->out.handle = &newh->wire_handle; 
+       } else {
+               talloc_free(newh);
        }
        
-       return NT_STATUS_OK;
+       return result;
 }
 
 
 /* 
   winreg_QueryInfoKey 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       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 NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       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 NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_RestoreKey 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_SaveKey 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_SetKeySecurity 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_SetValue 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       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 NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_InitiateSystemShutdown 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_AbortSystemShutdown 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_GetVersion 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       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 NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_InitiateSystemShutdownEx 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_SaveKeyEx 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }
 
 
 /* 
   winreg_QueryMultipleValues2 
 */
-static NTSTATUS 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 NT_STATUS_NOT_IMPLEMENTED;
+       return WERR_NOT_SUPPORTED;
 }