s3-talloc Change TALLOC_ARRAY() to talloc_array()
[samba.git] / source3 / utils / net_rpc_registry.c
index fb1e14f0d5cd754ebc0d1696ad3bedae3d6bfc42..77b15a45c7b4d5395f4b5959d18a611b916c4a91 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
  
 #include "includes.h"
+#include "system/filesys.h"
+#include "rpc_client/rpc_client.h"
 #include "registry.h"
 #include "utils/net.h"
 #include "utils/net_registry_util.h"
-#include "regfio.h"
-#include "../librpc/gen_ndr/cli_winreg.h"
-#include "registry/reg_util_marshalling.h"
-#include "registry/reg_objects.h"
+#include "registry/regfio.h"
+#include "../librpc/gen_ndr/ndr_winreg_c.h"
 #include "../librpc/gen_ndr/ndr_security.h"
+#include "registry/reg_format.h"
+#include "registry/reg_import.h"
+#include <assert.h>
+#include "../libcli/security/display_sec.h"
+#include "../libcli/registry/util_reg.h"
+#include "client.h"
+
 
 /*******************************************************************
  connect to a registry hive root (open a registry policy)
 *******************************************************************/
 
-static NTSTATUS rpccli_winreg_Connect(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
+static NTSTATUS dcerpc_winreg_Connect(struct dcerpc_binding_handle *b, TALLOC_CTX *mem_ctx,
                                      uint32_t reg_type, uint32_t access_mask,
-                                     struct policy_handle *reg_hnd)
+                                     struct policy_handle *reg_hnd, WERROR *werr)
 {
        ZERO_STRUCTP(reg_hnd);
 
        switch (reg_type)
        {
        case HKEY_CLASSES_ROOT:
-               return rpccli_winreg_OpenHKCR( cli, mem_ctx, NULL,
-                       access_mask, reg_hnd, NULL);
+               return dcerpc_winreg_OpenHKCR(b, mem_ctx, NULL,
+                       access_mask, reg_hnd, werr);
 
        case HKEY_LOCAL_MACHINE:
-               return rpccli_winreg_OpenHKLM( cli, mem_ctx, NULL,
-                       access_mask, reg_hnd, NULL);
+               return dcerpc_winreg_OpenHKLM(b, mem_ctx, NULL,
+                       access_mask, reg_hnd, werr);
 
        case HKEY_USERS:
-               return rpccli_winreg_OpenHKU( cli, mem_ctx, NULL,
-                       access_mask, reg_hnd, NULL);
+               return dcerpc_winreg_OpenHKU(b, mem_ctx, NULL,
+                       access_mask, reg_hnd, werr);
 
        case HKEY_CURRENT_USER:
-               return rpccli_winreg_OpenHKCU( cli, mem_ctx, NULL,
-                       access_mask, reg_hnd, NULL);
+               return dcerpc_winreg_OpenHKCU(b, mem_ctx, NULL,
+                       access_mask, reg_hnd, werr);
 
        case HKEY_PERFORMANCE_DATA:
-               return rpccli_winreg_OpenHKPD( cli, mem_ctx, NULL,
-                       access_mask, reg_hnd, NULL);
+               return dcerpc_winreg_OpenHKPD(b, mem_ctx, NULL,
+                       access_mask, reg_hnd, werr);
 
        default:
                /* fall through to end of function */
@@ -127,7 +134,9 @@ static NTSTATUS registry_openkey(TALLOC_CTX *mem_ctx,
 {
        uint32 hive;
        NTSTATUS status;
+       WERROR werr;
        struct winreg_String key;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        ZERO_STRUCT(key);
 
@@ -135,18 +144,26 @@ static NTSTATUS registry_openkey(TALLOC_CTX *mem_ctx,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive, access_mask,
-                                      hive_hnd);
+       status = dcerpc_winreg_Connect(b, mem_ctx, hive, access_mask,
+                                      hive_hnd, &werr);
        if (!(NT_STATUS_IS_OK(status))) {
                return status;
        }
+       if (!W_ERROR_IS_OK(werr)) {
+               return werror_to_ntstatus(werr);
+       }
 
-       status = rpccli_winreg_OpenKey(pipe_hnd, mem_ctx, hive_hnd, key, 0,
-                                      access_mask, key_hnd, NULL);
+       status = dcerpc_winreg_OpenKey(b, mem_ctx, hive_hnd, key, 0,
+                                      access_mask, key_hnd, &werr);
        if (!(NT_STATUS_IS_OK(status))) {
-               rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, hive_hnd, NULL);
+               dcerpc_winreg_CloseKey(b, mem_ctx, hive_hnd, &werr);
                return status;
        }
+       if (!(W_ERROR_IS_OK(werr))) {
+               WERROR _werr;
+               dcerpc_winreg_CloseKey(b, mem_ctx, hive_hnd, &_werr);
+               return werror_to_ntstatus(werr);
+       }
 
        return NT_STATUS_OK;
 }
@@ -159,6 +176,7 @@ static NTSTATUS registry_enumkeys(TALLOC_CTX *ctx,
 {
        TALLOC_CTX *mem_ctx;
        NTSTATUS status;
+       WERROR werr;
        uint32 num_subkeys, max_subkeylen, max_classlen;
        uint32 num_values, max_valnamelen, max_valbufsize;
        uint32 i;
@@ -167,20 +185,25 @@ static NTSTATUS registry_enumkeys(TALLOC_CTX *ctx,
        struct winreg_String classname;
        char **names, **classes;
        NTTIME **modtimes;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        if (!(mem_ctx = talloc_new(ctx))) {
                return NT_STATUS_NO_MEMORY;
        }
 
        ZERO_STRUCT(classname);
-       status = rpccli_winreg_QueryInfoKey(
-               pipe_hnd, mem_ctx, key_hnd, &classname, &num_subkeys,
+       status = dcerpc_winreg_QueryInfoKey(
+               b, mem_ctx, key_hnd, &classname, &num_subkeys,
                &max_subkeylen, &max_classlen, &num_values, &max_valnamelen,
-               &max_valbufsize, &secdescsize, &last_changed_time, NULL );
+               &max_valbufsize, &secdescsize, &last_changed_time, &werr);
 
        if (!NT_STATUS_IS_OK(status)) {
                goto error;
        }
+       if (!W_ERROR_IS_OK(werr)) {
+               status = werror_to_ntstatus(werr);
+               goto error;
+       }
 
        if (num_subkeys == 0) {
                *pnum_keys = 0;
@@ -201,7 +224,6 @@ static NTSTATUS registry_enumkeys(TALLOC_CTX *ctx,
                struct winreg_StringBuf class_buf;
                struct winreg_StringBuf name_buf;
                NTTIME modtime;
-               WERROR werr;
 
                c = '\0';
                class_buf.name = &c;
@@ -213,16 +235,19 @@ static NTSTATUS registry_enumkeys(TALLOC_CTX *ctx,
 
                ZERO_STRUCT(modtime);
 
-               status = rpccli_winreg_EnumKey(pipe_hnd, mem_ctx, key_hnd,
+               status = dcerpc_winreg_EnumKey(b, mem_ctx, key_hnd,
                                               i, &name_buf, &class_buf,
                                               &modtime, &werr);
-
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto error;
+               }
                if (W_ERROR_EQUAL(werr,
                                  WERR_NO_MORE_ITEMS) ) {
                        status = NT_STATUS_OK;
                        break;
                }
-               if (!NT_STATUS_IS_OK(status)) {
+               if (!W_ERROR_IS_OK(werr)) {
+                       status = werror_to_ntstatus(werr);
                        goto error;
                }
 
@@ -273,6 +298,7 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
 {
        TALLOC_CTX *mem_ctx;
        NTSTATUS status;
+       WERROR werr;
        uint32 num_subkeys, max_subkeylen, max_classlen;
        uint32 num_values, max_valnamelen, max_valbufsize;
        uint32 i;
@@ -281,20 +307,25 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
        struct winreg_String classname;
        struct registry_value **values;
        char **names;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        if (!(mem_ctx = talloc_new(ctx))) {
                return NT_STATUS_NO_MEMORY;
        }
 
        ZERO_STRUCT(classname);
-       status = rpccli_winreg_QueryInfoKey(
-               pipe_hnd, mem_ctx, key_hnd, &classname, &num_subkeys,
+       status = dcerpc_winreg_QueryInfoKey(
+               b, mem_ctx, key_hnd, &classname, &num_subkeys,
                &max_subkeylen, &max_classlen, &num_values, &max_valnamelen,
-               &max_valbufsize, &secdescsize, &last_changed_time, NULL );
+               &max_valbufsize, &secdescsize, &last_changed_time, &werr);
 
        if (!NT_STATUS_IS_OK(status)) {
                goto error;
        }
+       if (!W_ERROR_IS_OK(werr)) {
+               status = werror_to_ntstatus(werr);
+               goto error;
+       }
 
        if (num_values == 0) {
                *pnum_values = 0;
@@ -302,8 +333,8 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
                return NT_STATUS_OK;
        }
 
-       if ((!(names = TALLOC_ARRAY(mem_ctx, char *, num_values))) ||
-           (!(values = TALLOC_ARRAY(mem_ctx, struct registry_value *,
+       if ((!(names = talloc_array(mem_ctx, char *, num_values))) ||
+           (!(values = talloc_array(mem_ctx, struct registry_value *,
                                     num_values)))) {
                status = NT_STATUS_NO_MEMORY;
                goto error;
@@ -327,10 +358,13 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
                data = (uint8 *)TALLOC(mem_ctx, data_size);
                value_length = 0;
 
-               status = rpccli_winreg_EnumValue(pipe_hnd, mem_ctx, key_hnd,
+               status = dcerpc_winreg_EnumValue(b, mem_ctx, key_hnd,
                                                 i, &name_buf, &type,
                                                 data, &data_size,
                                                 &value_length, &err);
+               if (!(NT_STATUS_IS_OK(status))) {
+                       goto error;
+               }
 
                if ( W_ERROR_EQUAL(err,
                                   WERR_NO_MORE_ITEMS) ) {
@@ -338,7 +372,8 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
                        break;
                }
 
-               if (!(NT_STATUS_IS_OK(status))) {
+               if (!W_ERROR_IS_OK(err)) {
+                       status = werror_to_ntstatus(err);
                        goto error;
                }
 
@@ -352,12 +387,138 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
                        goto error;
                }
 
-               err = registry_pull_value(values, &values[i], type, data,
-                                         data_size, value_length);
+               values[i] = talloc_zero(values, struct registry_value);
+               if (values[i] == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto error;
+               }
+
+               values[i]->type = type;
+               values[i]->data = data_blob_talloc(values[i], data, data_size);
+       }
+
+       *pnum_values = num_values;
+
+       if (pvalnames) {
+               *pvalnames = talloc_move(ctx, &names);
+       }
+       if (pvalues) {
+               *pvalues = talloc_move(ctx, &values);
+       }
+
+       status = NT_STATUS_OK;
+
+ error:
+       TALLOC_FREE(mem_ctx);
+       return status;
+}
+
+static NTSTATUS registry_enumvalues2(TALLOC_CTX *ctx,
+                                    struct rpc_pipe_client *pipe_hnd,
+                                    struct policy_handle *key_hnd,
+                                    uint32 *pnum_values, char ***pvalnames,
+                                    struct regval_blob ***pvalues)
+{
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+       WERROR werr;
+       uint32 num_subkeys, max_subkeylen, max_classlen;
+       uint32 num_values, max_valnamelen, max_valbufsize;
+       uint32 i;
+       NTTIME last_changed_time;
+       uint32 secdescsize;
+       struct winreg_String classname;
+       struct regval_blob **values;
+       char **names;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
+
+       if (!(mem_ctx = talloc_new(ctx))) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ZERO_STRUCT(classname);
+       status = dcerpc_winreg_QueryInfoKey(
+               b, mem_ctx, key_hnd, &classname, &num_subkeys,
+               &max_subkeylen, &max_classlen, &num_values, &max_valnamelen,
+               &max_valbufsize, &secdescsize, &last_changed_time, &werr);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               goto error;
+       }
+       if (!W_ERROR_IS_OK(werr)) {
+               status = werror_to_ntstatus(werr);
+               goto error;
+       }
+
+       if (num_values == 0) {
+               *pnum_values = 0;
+               TALLOC_FREE(mem_ctx);
+               return NT_STATUS_OK;
+       }
+
+       if ((!(names = talloc_array(mem_ctx, char *, num_values))) ||
+           (!(values = talloc_array(mem_ctx, struct regval_blob *,
+                                    num_values)))) {
+               status = NT_STATUS_NO_MEMORY;
+               goto error;
+       }
+
+       for (i=0; i<num_values; i++) {
+               enum winreg_Type type = REG_NONE;
+               uint8 *data = NULL;
+               uint32 data_size;
+               uint32 value_length;
+
+               char n;
+               struct winreg_ValNameBuf name_buf;
+               WERROR err;
+
+               n = '\0';
+               name_buf.name = &n;
+               name_buf.size = max_valnamelen + 2;
+
+               data_size = max_valbufsize;
+               data = (uint8 *)TALLOC(mem_ctx, data_size);
+               value_length = 0;
+
+               status = dcerpc_winreg_EnumValue(b, mem_ctx, key_hnd,
+                                                i, &name_buf, &type,
+                                                data, &data_size,
+                                                &value_length, &err);
+               if (!(NT_STATUS_IS_OK(status))) {
+                       goto error;
+               }
+
+               if ( W_ERROR_EQUAL(err, WERR_NO_MORE_ITEMS) ) {
+                       status = NT_STATUS_OK;
+                       break;
+               }
+
                if (!W_ERROR_IS_OK(err)) {
                        status = werror_to_ntstatus(err);
                        goto error;
                }
+
+               if (name_buf.name == NULL) {
+                       status = NT_STATUS_INVALID_PARAMETER;
+                       goto error;
+               }
+
+               if (!(names[i] = talloc_strdup(names, name_buf.name))) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto error;
+               }
+
+               assert(value_length<=data_size); //???
+
+               values[i] = regval_compose(values,
+                                          name_buf.name,
+                                          type,
+                                          data, value_length);
+               if (!values[i]) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto error;
+               }
        }
 
        *pnum_values = num_values;
@@ -377,13 +538,14 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
 }
 
 static NTSTATUS registry_getsd(TALLOC_CTX *mem_ctx,
-                              struct rpc_pipe_client *pipe_hnd,
+                              struct dcerpc_binding_handle *b,
                               struct policy_handle *key_hnd,
                               uint32_t sec_info,
-                              struct KeySecurityData *sd)
+                              struct KeySecurityData *sd,
+                              WERROR *werr)
 {
-       return rpccli_winreg_GetKeySecurity(pipe_hnd, mem_ctx, key_hnd,
-                                           sec_info, sd, NULL);
+       return dcerpc_winreg_GetKeySecurity(b, mem_ctx, key_hnd,
+                                           sec_info, sd, werr);
 }
 
 
@@ -394,23 +556,21 @@ static NTSTATUS registry_setvalue(TALLOC_CTX *mem_ctx,
                                  const struct registry_value *value)
 {
        struct winreg_String name_string;
-       DATA_BLOB blob;
        NTSTATUS result;
-       WERROR err;
-
-       err = registry_push_value(mem_ctx, value, &blob);
-       if (!W_ERROR_IS_OK(err)) {
-               return werror_to_ntstatus(err);
-       }
+       WERROR werr;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        ZERO_STRUCT(name_string);
 
        name_string.name = name;
-       result = rpccli_winreg_SetValue(pipe_hnd, blob.data, key_hnd,
+       result = dcerpc_winreg_SetValue(b, mem_ctx, key_hnd,
                                        name_string, value->type,
-                                       blob.data, blob.length, NULL);
-       TALLOC_FREE(blob.data);
-       return result;
+                                       value->data.data, value->data.length, &werr);
+       if (!NT_STATUS_IS_OK(result)) {
+               return result;
+       }
+
+       return werror_to_ntstatus(werr);
 }
 
 static NTSTATUS rpc_registry_setvalue_internal(struct net_context *c,
@@ -424,7 +584,9 @@ static NTSTATUS rpc_registry_setvalue_internal(struct net_context *c,
 {
        struct policy_handle hive_hnd, key_hnd;
        NTSTATUS status;
+       WERROR werr;
        struct registry_value value;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        status = registry_openkey(mem_ctx, pipe_hnd, argv[0],
                                  SEC_FLAG_MAXIMUM_ALLOWED,
@@ -441,13 +603,17 @@ static NTSTATUS rpc_registry_setvalue_internal(struct net_context *c,
        }
 
        if (strequal(argv[2], "dword")) {
+               uint32_t v = strtoul(argv[3], NULL, 10);
                value.type = REG_DWORD;
-               value.v.dword = strtoul(argv[3], NULL, 10);
+               value.data = data_blob_talloc(mem_ctx, NULL, 4);
+               SIVAL(value.data.data, 0, v);
        }
        else if (strequal(argv[2], "sz")) {
                value.type = REG_SZ;
-               value.v.sz.len = strlen(argv[3])+1;
-               value.v.sz.str = CONST_DISCARD(char *, argv[3]);
+               if (!push_reg_sz(mem_ctx, &value.data, argv[3])) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto error;
+               }
        }
        else {
                d_fprintf(stderr, _("type \"%s\" not implemented\n"), argv[2]);
@@ -464,8 +630,8 @@ static NTSTATUS rpc_registry_setvalue_internal(struct net_context *c,
        }
 
  error:
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &key_hnd, &werr);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &hive_hnd, &werr);
 
        return NT_STATUS_OK;
 }
@@ -496,7 +662,9 @@ static NTSTATUS rpc_registry_deletevalue_internal(struct net_context *c,
 {
        struct policy_handle hive_hnd, key_hnd;
        NTSTATUS status;
+       WERROR werr;
        struct winreg_String valuename;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        ZERO_STRUCT(valuename);
 
@@ -511,16 +679,20 @@ static NTSTATUS rpc_registry_deletevalue_internal(struct net_context *c,
 
        valuename.name = argv[1];
 
-       status = rpccli_winreg_DeleteValue(pipe_hnd, mem_ctx, &key_hnd,
-                                          valuename, NULL);
-
+       status = dcerpc_winreg_DeleteValue(b, mem_ctx, &key_hnd,
+                                          valuename, &werr);
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, _("registry_deletevalue failed: %s\n"),
                          nt_errstr(status));
        }
+       if (!W_ERROR_IS_OK(werr)) {
+               status = werror_to_ntstatus(werr);
+               d_fprintf(stderr, _("registry_deletevalue failed: %s\n"),
+                         win_errstr(werr));
+       }
 
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &key_hnd, &werr);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &hive_hnd, &werr);
 
        return status;
 }
@@ -555,10 +727,10 @@ static NTSTATUS rpc_registry_getvalue_internal(struct net_context *c,
        struct winreg_String valuename;
        struct registry_value *value = NULL;
        enum winreg_Type type = REG_NONE;
-       uint8_t *data = NULL;
        uint32_t data_size = 0;
        uint32_t value_length = 0;
        TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        ZERO_STRUCT(valuename);
 
@@ -573,54 +745,66 @@ static NTSTATUS rpc_registry_getvalue_internal(struct net_context *c,
 
        valuename.name = argv[1];
 
+       value = talloc_zero(tmp_ctx, struct registry_value);
+       if (value == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        /*
         * call QueryValue once with data == NULL to get the
         * needed memory size to be allocated, then allocate
         * data buffer and call again.
         */
-       status = rpccli_winreg_QueryValue(pipe_hnd, tmp_ctx, &key_hnd,
+       status = dcerpc_winreg_QueryValue(b, tmp_ctx, &key_hnd,
                                          &valuename,
                                          &type,
-                                         data,
+                                         NULL,
                                          &data_size,
                                          &value_length,
-                                         NULL);
+                                         &werr);
 
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, _("registry_queryvalue failed: %s\n"),
                          nt_errstr(status));
                goto done;
        }
+       if (!W_ERROR_IS_OK(werr)) {
+               status = werror_to_ntstatus(werr);
+               d_fprintf(stderr, _("registry_queryvalue failed: %s\n"),
+                         nt_errstr(status));
+               goto done;
+       }
 
-       data = (uint8 *)TALLOC(tmp_ctx, data_size);
-       value_length = 0;
+       value->data = data_blob_talloc(tmp_ctx, NULL, data_size);
 
-       status = rpccli_winreg_QueryValue(pipe_hnd, tmp_ctx, &key_hnd,
+       status = dcerpc_winreg_QueryValue(b, tmp_ctx, &key_hnd,
                                          &valuename,
                                          &type,
-                                         data,
+                                         value->data.data,
                                          &data_size,
                                          &value_length,
-                                         NULL);
+                                         &werr);
 
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, _("registry_queryvalue failed: %s\n"),
                          nt_errstr(status));
                goto done;
        }
-
-       werr = registry_pull_value(tmp_ctx, &value, type, data,
-                                  data_size, value_length);
        if (!W_ERROR_IS_OK(werr)) {
                status = werror_to_ntstatus(werr);
+               d_fprintf(stderr, _("registry_queryvalue failed: %s\n"),
+                         win_errstr(werr));
                goto done;
        }
 
+
+       value->type = type;
+
        print_registry_value(value, raw);
 
 done:
-       rpccli_winreg_CloseKey(pipe_hnd, tmp_ctx, &key_hnd, NULL);
-       rpccli_winreg_CloseKey(pipe_hnd, tmp_ctx, &hive_hnd, NULL);
+       dcerpc_winreg_CloseKey(b, tmp_ctx, &key_hnd, &werr);
+       dcerpc_winreg_CloseKey(b, tmp_ctx, &hive_hnd, &werr);
 
        TALLOC_FREE(tmp_ctx);
 
@@ -697,6 +881,8 @@ static NTSTATUS rpc_registry_createkey_internal(struct net_context *c,
        struct winreg_String key, keyclass;
        enum winreg_CreateAction action;
        NTSTATUS status;
+       WERROR werr;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        ZERO_STRUCT(key);
        ZERO_STRUCT(keyclass);
@@ -705,25 +891,35 @@ static NTSTATUS rpc_registry_createkey_internal(struct net_context *c,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive,
+       status = dcerpc_winreg_Connect(b, mem_ctx, hive,
                                       SEC_FLAG_MAXIMUM_ALLOWED,
-                                      &hive_hnd);
+                                      &hive_hnd, &werr);
        if (!(NT_STATUS_IS_OK(status))) {
                return status;
        }
+       if (!W_ERROR_IS_OK(werr)) {
+               return werror_to_ntstatus(werr);
+       }
 
        action = REG_ACTION_NONE;
        keyclass.name = "";
 
-       status = rpccli_winreg_CreateKey(pipe_hnd, mem_ctx, &hive_hnd, key,
+       status = dcerpc_winreg_CreateKey(b, mem_ctx, &hive_hnd, key,
                                         keyclass, 0, REG_KEY_READ, NULL,
-                                        &key_hnd, &action, NULL);
+                                        &key_hnd, &action, &werr);
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, _("createkey returned %s\n"),
                          nt_errstr(status));
-               rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+               dcerpc_winreg_CloseKey(b, mem_ctx, &hive_hnd, &werr);
                return status;
        }
+       if (!W_ERROR_IS_OK(werr)) {
+               WERROR _werr;
+               d_fprintf(stderr, _("createkey returned %s\n"),
+                         win_errstr(werr));
+               dcerpc_winreg_CloseKey(b, mem_ctx, &hive_hnd, &_werr);
+               return werror_to_ntstatus(werr);
+       }
 
        switch (action) {
                case REG_ACTION_NONE:
@@ -737,8 +933,8 @@ static NTSTATUS rpc_registry_createkey_internal(struct net_context *c,
                        break;
        }
 
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &key_hnd, &werr);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &hive_hnd, &werr);
 
        return status;
 }
@@ -770,6 +966,8 @@ static NTSTATUS rpc_registry_deletekey_internal(struct net_context *c,
        struct policy_handle hive_hnd;
        struct winreg_String key;
        NTSTATUS status;
+       WERROR werr;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        ZERO_STRUCT(key);
 
@@ -777,19 +975,32 @@ static NTSTATUS rpc_registry_deletekey_internal(struct net_context *c,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive,
+       status = dcerpc_winreg_Connect(b, mem_ctx, hive,
                                       SEC_FLAG_MAXIMUM_ALLOWED,
-                                      &hive_hnd);
+                                      &hive_hnd, &werr);
        if (!(NT_STATUS_IS_OK(status))) {
                return status;
        }
+       if (!W_ERROR_IS_OK(werr)) {
+               return werror_to_ntstatus(werr);
+       }
 
-       status = rpccli_winreg_DeleteKey(pipe_hnd, mem_ctx, &hive_hnd, key, NULL);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+       status = dcerpc_winreg_DeleteKey(b, mem_ctx, &hive_hnd, key, &werr);
+       if (is_valid_policy_hnd(&hive_hnd)) {
+               WERROR _werr;
+               dcerpc_winreg_CloseKey(b, mem_ctx, &hive_hnd, &_werr);
+       }
 
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, _("deletekey returned %s\n"),
                          nt_errstr(status));
+               return status;
+       }
+
+       if (!W_ERROR_IS_OK(werr)) {
+               d_fprintf(stderr, _("deletekey returned %s\n"),
+                         win_errstr(werr));
+               return werror_to_ntstatus(werr);
        }
 
        return status;
@@ -822,12 +1033,14 @@ static NTSTATUS rpc_registry_enumerate_internal(struct net_context *c,
 {
        struct policy_handle pol_hive, pol_key;
        NTSTATUS status;
+       WERROR werr;
        uint32 num_subkeys = 0;
        uint32 num_values = 0;
        char **names = NULL, **classes = NULL;
        NTTIME **modtimes = NULL;
        uint32 i;
        struct registry_value **values = NULL;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        if (argc != 1 || c->display_usage) {
                d_printf("%s\n%s",
@@ -870,8 +1083,8 @@ static NTSTATUS rpc_registry_enumerate_internal(struct net_context *c,
                print_registry_value_with_name(names[i], values[i]);
        }
 
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key, NULL);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive, NULL);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &pol_key, &werr);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &pol_hive, &werr);
 
        return status;
 }
@@ -902,6 +1115,7 @@ static NTSTATUS rpc_registry_save_internal(struct net_context *c,
        struct policy_handle pol_hive, pol_key;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        struct winreg_String filename;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        if (argc != 2 || c->display_usage) {
                d_printf("%s\n%s",
@@ -919,16 +1133,21 @@ static NTSTATUS rpc_registry_save_internal(struct net_context *c,
        }
 
        filename.name = argv[1];
-       status = rpccli_winreg_SaveKey( pipe_hnd, mem_ctx, &pol_key, &filename, NULL, NULL);
-       if ( !W_ERROR_IS_OK(result) ) {
+       status = dcerpc_winreg_SaveKey(b, mem_ctx, &pol_key, &filename, NULL, &result);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, _("Unable to save [%s] to %s:%s\n"), argv[0],
+                         cli->desthost, argv[1]);
+       }
+       if (!W_ERROR_IS_OK(result)) {
+               status = werror_to_ntstatus(result);
                d_fprintf(stderr, _("Unable to save [%s] to %s:%s\n"), argv[0],
                          cli->desthost, argv[1]);
        }
 
        /* cleanup */
 
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key, NULL);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive, NULL);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &pol_key, &result);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &pol_hive, &result);
 
        return status;
 }
@@ -1154,7 +1373,8 @@ static int rpc_registry_copy(struct net_context *c, int argc, const char **argv
        d_printf(_("ok\n"));
 
        d_printf(_("Opening %s...."), argv[1]);
-       if ( !(outfile = regfio_open( argv[1], (O_RDWR|O_CREAT|O_TRUNC), (S_IREAD|S_IWRITE) )) ) {
+       if ( !(outfile = regfio_open( argv[1], (O_RDWR|O_CREAT|O_TRUNC),
+                                     (S_IRUSR|S_IWUSR) )) ) {
                d_fprintf(stderr, _("Failed to open %s for writing\n"),argv[1]);
                goto out;
        }
@@ -1203,6 +1423,7 @@ static NTSTATUS rpc_registry_getsd_internal(struct net_context *c,
 {
        struct policy_handle pol_hive, pol_key;
        NTSTATUS status;
+       WERROR werr;
        enum ndr_err_code ndr_err;
        struct KeySecurityData *sd = NULL;
        uint32_t sec_info;
@@ -1210,6 +1431,7 @@ static NTSTATUS rpc_registry_getsd_internal(struct net_context *c,
        struct security_descriptor sec_desc;
        uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED |
                               SEC_FLAG_SYSTEM_SECURITY;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
 
        if (argc <1 || argc > 2 || c->display_usage) {
                d_printf("%s\n%s",
@@ -1243,12 +1465,18 @@ static NTSTATUS rpc_registry_getsd_internal(struct net_context *c,
                sec_info = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL;
        }
 
-       status = registry_getsd(mem_ctx, pipe_hnd, &pol_key, sec_info, sd);
+       status = registry_getsd(mem_ctx, b, &pol_key, sec_info, sd, &werr);
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, _("getting sd failed: %s\n"),
                          nt_errstr(status));
                goto out;
        }
+       if (!W_ERROR_IS_OK(werr)) {
+               status = werror_to_ntstatus(werr);
+               d_fprintf(stderr, _("getting sd failed: %s\n"),
+                         win_errstr(werr));
+               goto out;
+       }
 
        blob.data = sd->data;
        blob.length = sd->size;
@@ -1264,8 +1492,8 @@ static NTSTATUS rpc_registry_getsd_internal(struct net_context *c,
        display_sec_desc(&sec_desc);
 
  out:
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key, NULL);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive, NULL);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &pol_key, &werr);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &pol_hive, &werr);
 
        return status;
 }
@@ -1278,7 +1506,499 @@ static int rpc_registry_getsd(struct net_context *c, int argc, const char **argv
 }
 
 /********************************************************************
-********************************************************************/
+ ********************************************************************/
+/**
+ * @defgroup net_rpc_registry net rpc registry
+ */
+
+/**
+ * @defgroup net_rpc_registry_export Export
+ * @ingroup net_rpc_registry
+ * @{
+ */
+
+static NTSTATUS registry_export(struct rpc_pipe_client* pipe_hnd,
+                               TALLOC_CTX* ctx,
+                               struct policy_handle* key_hnd,
+                               struct reg_format* f,
+                               const char* parentfullname,
+                               const char* name)
+{
+       NTSTATUS status;
+       uint32 num_subkeys = 0;
+       uint32 num_values = 0;
+       char **names = NULL, **classes = NULL;
+       NTTIME **modtimes = NULL;
+       struct regval_blob **values = NULL;
+       uint32 i;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
+
+       TALLOC_CTX* mem_ctx = talloc_new(ctx);
+
+
+       const char* fullname = name
+               ? talloc_asprintf(mem_ctx, "%s\\%s", parentfullname, name)
+               : parentfullname;
+       reg_format_key(f, &fullname, 1, false);
+
+       status = registry_enumvalues2(mem_ctx, pipe_hnd, key_hnd, &num_values,
+                                     &names, &values);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, _("enumerating values failed: %s\n"),
+                         nt_errstr(status));
+               goto done;
+       }
+
+       for (i=0; i<num_values; i++) {
+               reg_format_regval_blob(f, names[i], values[i]);
+       }
+
+
+       status = registry_enumkeys(mem_ctx, pipe_hnd, key_hnd, &num_subkeys,
+                                  &names, &classes, &modtimes);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, _("enumerating keys failed: %s\n"),
+                         nt_errstr(status));
+               goto done;
+       }
+
+       for (i=0; i<num_subkeys; i++) {
+               struct policy_handle subkey_hnd;
+               struct winreg_String key;
+               WERROR werr;
+               ZERO_STRUCT(key);
+               /* key.name = talloc_strdup(mem_ctx, names[i]); ??? */
+               key.name = names[i];
+
+               status = dcerpc_winreg_OpenKey(b, mem_ctx, key_hnd, key,
+                                              0, REG_KEY_READ,
+                                              &subkey_hnd, &werr);
+               if (!NT_STATUS_IS_OK(status)) {
+                       d_fprintf(stderr,
+                                 _("dcerpc_winreg_OpenKey failed: %s %s\n"),
+                                 names[i], nt_errstr(status));
+                       continue;
+               }
+               if (!W_ERROR_IS_OK(werr)) {
+                       status = werror_to_ntstatus(werr);
+                       d_fprintf(stderr,
+                                 _("dcerpc_winreg_OpenKey failed: %s %s\n"),
+                                 names[i], win_errstr(werr));
+                       continue;
+               }
+
+               status = registry_export(pipe_hnd, mem_ctx, &subkey_hnd,
+                                        f, fullname, names[i]);
+               if (!(NT_STATUS_IS_OK(status))) {
+                       d_fprintf(stderr,
+                                 _("export key failed: %s %s\n"),
+                                 names[i], nt_errstr(status));
+               }
+               dcerpc_winreg_CloseKey(b, mem_ctx,
+                                      &subkey_hnd, &werr);
+       }
+done:
+       talloc_free(mem_ctx);
+       return status;
+}
+
+static NTSTATUS rpc_registry_export_internal(struct net_context *c,
+                                            const struct dom_sid *domain_sid,
+                                            const char *domain_name,
+                                            struct cli_state *cli,
+                                            struct rpc_pipe_client *pipe_hnd,
+                                            TALLOC_CTX *mem_ctx,
+                                            int argc,
+                                            const char **argv )
+{
+       struct policy_handle pol_hive, pol_key;
+       NTSTATUS status;
+       WERROR werr;
+       struct reg_format* f;
+       struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
+
+       if (argc < 2 || argc > 3 || c->display_usage) {
+               d_printf("%s\n%s",
+                        _("Usage:"),
+                        _("net rpc registry export <path> <file> [opt]\n"));
+               d_printf("%s  net rpc registry export "
+                        "'HKLM\\Software\\Samba' samba.reg\n", _("Example:"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_READ,
+                                 &pol_hive, &pol_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, _("registry_openkey failed: %s\n"),
+                         nt_errstr(status));
+               return status;
+       }
+
+       f = reg_format_file(mem_ctx, argv[1], (argc > 2) ? argv[2] : NULL);
+       if (f == NULL) {
+               d_fprintf(stderr, _("open file failed: %s\n"), strerror(errno));
+               return map_nt_error_from_unix(errno);
+       }
+
+       status = registry_export(pipe_hnd, mem_ctx, &pol_key,
+                                f, argv[0], NULL );
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       dcerpc_winreg_CloseKey(b, mem_ctx, &pol_key, &werr);
+       dcerpc_winreg_CloseKey(b, mem_ctx, &pol_hive, &werr);
+
+       return status;
+}
+/********************************************************************
+ ********************************************************************/
+
+static int rpc_registry_export(struct net_context *c, int argc,
+                              const char **argv )
+{
+       return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+                              rpc_registry_export_internal, argc, argv );
+}
+
+/**@}*/
+
+/********************************************************************
+ ********************************************************************/
+
+/**
+ * @defgroup net_rpc_registry_import Import
+ * @ingroup net_rpc_registry
+ * @{
+ */
+
+struct import_ctx {
+       struct rpc_pipe_client *pipe_hnd;
+       TALLOC_CTX *mem_ctx;
+};
+
+static WERROR import_create_key(struct import_ctx* ctx,
+                               struct policy_handle* parent, const char* name,
+                               void** pkey, bool* existing)
+{
+       WERROR werr;
+       NTSTATUS status;
+       void* mem_ctx = talloc_new(ctx->mem_ctx);
+
+       struct policy_handle* key = NULL;
+       struct policy_handle  hive;
+       struct winreg_String  keyclass, keyname;
+       enum winreg_CreateAction action = REG_ACTION_NONE;
+       struct dcerpc_binding_handle *b = ctx->pipe_hnd->binding_handle;
+
+       ZERO_STRUCT(keyname);
+       keyname.name = name;
+
+       if (parent == NULL) {
+               uint32 hive_idx = 0;
+               if (!reg_hive_key(mem_ctx, name, &hive_idx, &keyname.name)) {
+                       werr = WERR_FOOBAR;
+                       goto done;
+               }
+
+               status = dcerpc_winreg_Connect(b, mem_ctx,
+                                              hive_idx, SEC_FLAG_MAXIMUM_ALLOWED,
+                                              &hive, &werr);
+               if (!NT_STATUS_IS_OK(status)) {
+                       werr = ntstatus_to_werror(status);
+                       d_fprintf(stderr, _("dcerpc_winreg_Connect returned %s\n"),
+                                 nt_errstr(status));
+                       goto done;
+               }
+               if (!W_ERROR_IS_OK(werr)) {
+                       d_fprintf(stderr, _("dcerpc_winreg_Connect returned %s\n"),
+                                 win_errstr(werr));
+                       goto done;
+               }
+
+               parent = &hive;
+       }
+
+       key = talloc_zero(mem_ctx, struct policy_handle);
+       if (key == NULL) {
+               werr = WERR_NOMEM;
+               goto done;
+       }
+
+       ZERO_STRUCT(keyclass);
+       keyclass.name = "";
+
+       status = dcerpc_winreg_CreateKey(b, mem_ctx,
+                                        parent, keyname,
+                                        keyclass, 0, REG_KEY_READ, NULL,
+                                        key, &action, &werr);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               d_fprintf(stderr, _("dcerpc_winreg_CreateKey returned %s\n"),
+                         nt_errstr(status));
+               goto done;
+       }
+       if (!W_ERROR_IS_OK(werr)) {
+               d_fprintf(stderr, _("dcerpc_winreg_CreateKey returned %s\n"),
+                         win_errstr(werr));
+               goto done;
+       }
+
+       switch (action) {
+       case REG_CREATED_NEW_KEY:
+               d_printf(_("createkey created %s\n"), name);
+               if (existing != NULL)
+                       *existing = false;
+               break;
+
+       case REG_OPENED_EXISTING_KEY:
+               d_printf(_("createkey opened existing %s\n"), name);
+               if (existing != NULL)
+                       *existing = true;
+               break;
+
+       case REG_ACTION_NONE:
+               d_printf(_("createkey did nothing -- huh?\n"));
+               werr = WERR_CREATE_FAILED;
+               break;
+       default:
+               assert(false);
+       }
+
+done:
+       if ( parent == &hive ) {
+               WERROR _result;
+               dcerpc_winreg_CloseKey(b, mem_ctx,
+                                      parent, &_result);
+       }
+
+       if (pkey!=NULL) {
+               *pkey = talloc_steal(ctx->mem_ctx, key);
+       }
+
+       talloc_free(mem_ctx);
+       return werr;
+}
+
+static WERROR import_delete_key(struct import_ctx* ctx,
+                               struct policy_handle* parent, const char* name)
+{
+       WERROR werr;
+       NTSTATUS status;
+       void* mem_ctx = talloc_new(ctx->mem_ctx);
+       struct winreg_String  keyname = { 0, };
+       struct policy_handle  hive;
+       struct dcerpc_binding_handle *b = ctx->pipe_hnd->binding_handle;
+
+       keyname.name = name;
+
+       if (parent == NULL) {
+               uint32 hive_idx;
+               if (!reg_hive_key(mem_ctx, name, &hive_idx, &keyname.name)) {
+                       werr = WERR_FOOBAR;
+                       goto done;
+               }
+
+               status = dcerpc_winreg_Connect(b, mem_ctx, hive_idx,
+                                              SEC_FLAG_MAXIMUM_ALLOWED, &hive,
+                                              &werr);
+               if (!NT_STATUS_IS_OK(status)) {
+                       werr = ntstatus_to_werror(status);
+                       d_fprintf(stderr, _("dcerpc_winreg_Connect returned %s\n"),
+                                 nt_errstr(status));
+                       goto done;
+               }
+               if (!W_ERROR_IS_OK(werr)) {
+                       d_fprintf(stderr, _("dcerpc_winreg_Connect returned %s\n"),
+                                 win_errstr(werr));
+                       goto done;
+               }
+
+               parent = &hive;
+       }
+
+       status = dcerpc_winreg_DeleteKey(b, mem_ctx, parent,
+                                        keyname, &werr);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               d_fprintf(stderr, _("dcerpc_winreg_DeleteKey returned %s\n"),
+                         nt_errstr(status));
+               goto done;
+       }
+       if (!W_ERROR_IS_OK(werr)) {
+               d_fprintf(stderr, _("dcerpc_winreg_DeleteKey returned %s\n"),
+                         win_errstr(werr));
+               goto done;
+       }
+
+done:
+       if ( parent == &hive ) {
+               WERROR _result;
+               dcerpc_winreg_CloseKey(b, mem_ctx, parent, &_result);
+       }
+
+       talloc_free(mem_ctx);
+       return werr;
+}
+
+static WERROR import_close_key(struct import_ctx* ctx,
+                              struct policy_handle* key)
+{
+       WERROR werr;
+       NTSTATUS status;
+       void* mem_ctx = talloc_new(ctx->mem_ctx);
+       struct dcerpc_binding_handle *b = ctx->pipe_hnd->binding_handle;
+
+       status = dcerpc_winreg_CloseKey(b, mem_ctx, key, &werr);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               d_fprintf(stderr, _("dcerpc_winreg_CloseKey returned %s\n"),
+                         nt_errstr(status));
+               goto done;
+       }
+       if (!W_ERROR_IS_OK(werr)) {
+               d_fprintf(stderr, _("dcerpc_winreg_CloseKey returned %s\n"),
+                         win_errstr(werr));
+               goto done;
+       }
+
+       werr = (talloc_free(key) == 0) ? WERR_OK : WERR_GENERAL_FAILURE;
+done:
+       talloc_free(mem_ctx);
+       return werr;
+}
+
+static WERROR import_create_val(struct import_ctx* ctx,
+                               struct policy_handle* parent, const char* name,
+                               uint32_t type, const uint8_t* val, uint32_t len)
+{
+       WERROR werr;
+       NTSTATUS status;
+       void* mem_ctx = talloc_new(ctx->mem_ctx);
+       struct winreg_String valuename;
+       struct dcerpc_binding_handle *b = ctx->pipe_hnd->binding_handle;
+
+       if (parent == NULL) {
+               return WERR_INVALID_PARAM;
+       }
+
+       ZERO_STRUCT(valuename);
+       valuename.name = name;
+
+       status = dcerpc_winreg_SetValue(b, mem_ctx, parent,
+                                       valuename, type,
+                                       (uint8_t *)discard_const(val), len, &werr);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               d_fprintf(stderr, _("registry_setvalue failed: %s\n"),
+                         nt_errstr(status));
+               goto done;
+       }
+       if (!W_ERROR_IS_OK(werr)) {
+               d_fprintf(stderr, _("registry_setvalue failed: %s\n"),
+                         win_errstr(werr));
+               goto done;
+       }
+
+done:
+       talloc_free(mem_ctx);
+       return werr;
+}
+
+static WERROR import_delete_val(struct import_ctx* ctx,
+                               struct policy_handle* parent, const char* name)
+{
+       WERROR werr;
+       NTSTATUS status;
+       void* mem_ctx = talloc_new(ctx->mem_ctx);
+       struct winreg_String valuename;
+       struct dcerpc_binding_handle *b = ctx->pipe_hnd->binding_handle;
+
+       if (parent == NULL) {
+               return WERR_INVALID_PARAM;
+       }
+
+       ZERO_STRUCT(valuename);
+       valuename.name = name;
+
+       status = dcerpc_winreg_DeleteValue(b, mem_ctx,
+                                          parent, valuename, &werr);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               d_fprintf(stderr, _("registry_deletevalue failed: %s\n"),
+                         nt_errstr(status));
+               goto done;
+       }
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, _("registry_deletevalue failed: %s\n"),
+                         win_errstr(werr));
+               goto done;
+       }
+
+done:
+       talloc_free(mem_ctx);
+       return werr;
+}
+
+
+
+static NTSTATUS rpc_registry_import_internal(struct net_context *c,
+                                            const struct dom_sid *domain_sid,
+                                            const char *domain_name,
+                                            struct cli_state *cli,
+                                            struct rpc_pipe_client *pipe_hnd,
+                                            TALLOC_CTX *mem_ctx,
+                                            int argc,
+                                            const char **argv )
+{
+       struct import_ctx import_ctx;
+
+       struct reg_import_callback import_callback = {
+               .openkey     = NULL,
+               .closekey    = (reg_import_callback_closekey_t)&import_close_key,
+               .createkey   = (reg_import_callback_createkey_t)&import_create_key,
+               .deletekey   = (reg_import_callback_deletekey_t)&import_delete_key,
+               .deleteval   = (reg_import_callback_deleteval_t)&import_delete_val,
+               .setval.blob = (reg_import_callback_setval_blob_t)&import_create_val,
+               .setval_type = BLOB,
+               .data = &import_ctx
+       };
+
+       int ret;
+       if (argc < 1 || argc > 2 || c->display_usage) {
+               d_printf("%s\n%s",
+                        _("Usage:"),
+                        _("net rpc registry import <file> [options]\n"));
+               d_printf("%s  net rpc registry export "
+                        "samba.reg enc=CP1252,flags=0\n", _("Example:"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       ZERO_STRUCT(import_ctx);
+       import_ctx.pipe_hnd = pipe_hnd;
+       import_ctx.mem_ctx  = mem_ctx;
+       ret = reg_parse_file(argv[0],
+                            reg_import_adapter(import_ctx.mem_ctx,
+                                               import_callback
+                                    ),
+                            (argc > 1) ? argv[1] : NULL
+               );
+
+       return ret==0 ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static int rpc_registry_import(struct net_context *c, int argc,
+                              const char **argv )
+{
+       return run_rpc_command(c, NULL, &ndr_table_winreg.syntax_id, 0,
+                              rpc_registry_import_internal, argc, argv );
+}
+
+/**@}*/
+/********************************************************************
+ ********************************************************************/
 
 int net_rpc_registry(struct net_context *c, int argc, const char **argv)
 {
@@ -1371,8 +2091,23 @@ int net_rpc_registry(struct net_context *c, int argc, const char **argv)
                        N_("net rpc registry getsd\n"
                           "    Get security descriptior")
                },
+               {
+                       "import",
+                       rpc_registry_import,
+                       NET_TRANSPORT_RPC,
+                       N_("Import .reg file"),
+                       N_("net rpc registry import\n"
+                          "    Import .reg file")
+               },
+               {
+                       "export",
+                       rpc_registry_export,
+                       NET_TRANSPORT_RPC,
+                       N_("Export .reg file"),
+                       N_("net rpc registry export\n"
+                          "    Export .reg file")
+               },
                {NULL, NULL, 0, NULL, NULL}
        };
-
        return net_run_function(c, argc, argv, "net rpc registry", func);
 }