net: Make "net rpc registry" use functable3
[kai/samba.git] / source3 / utils / net_rpc_registry.c
index 0a3ceb2233cd0e5049d65b7ef208c07ad12d2dfe..0d7d46fb981e200f42869463e3b8de226c81b715 100644 (file)
@@ -6,7 +6,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 "utils/net.h"
+#include "utils/net_registry_util.h"
 #include "regfio.h"
 #include "reg_objects.h"
 
-static BOOL reg_hive_key(const char *fullname, uint32 *reg_type,
-                        const char **key_name)
+static bool reg_hive_key(TALLOC_CTX *ctx, const char *fullname,
+                        uint32 *reg_type, const char **key_name)
 {
-       const char *sep;
-       ptrdiff_t len;
+       WERROR werr;
+       char *hivename = NULL;
+       char *tmp_keyname = NULL;
+       bool ret = false;
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
 
-       sep = strchr_m(fullname, '\\');
-
-       if (sep != NULL) {
-               len = sep - fullname;
-               *key_name = sep+1;
+       werr = split_hive_key(tmp_ctx, fullname, &hivename, &tmp_keyname);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
        }
-       else {
-               len = strlen(fullname);
-               *key_name = "";
+
+       *key_name = talloc_strdup(ctx, tmp_keyname);
+       if (*key_name == NULL) {
+               goto done;
        }
 
-       if (strnequal(fullname, "HKLM", len) ||
-           strnequal(fullname, "HKEY_LOCAL_MACHINE", len))
+       if (strequal(hivename, "HKLM") ||
+           strequal(hivename, "HKEY_LOCAL_MACHINE"))
+       {
                (*reg_type) = HKEY_LOCAL_MACHINE;
-       else if (strnequal(fullname, "HKCR", len) ||
-                strnequal(fullname, "HKEY_CLASSES_ROOT", len))
+       } else if (strequal(hivename, "HKCR") ||
+                  strequal(hivename, "HKEY_CLASSES_ROOT"))
+       {
                (*reg_type) = HKEY_CLASSES_ROOT;
-       else if (strnequal(fullname, "HKU", len) ||
-                strnequal(fullname, "HKEY_USERS", len))
+       } else if (strequal(hivename, "HKU") ||
+                  strequal(hivename, "HKEY_USERS"))
+       {
                (*reg_type) = HKEY_USERS;
-       else if (strnequal(fullname, "HKPD", len) ||
-                strnequal(fullname, "HKEY_PERFORMANCE_DATA", len))
+       } else if (strequal(hivename, "HKCU") ||
+                  strequal(hivename, "HKEY_CURRENT_USER"))
+       {
+               (*reg_type) = HKEY_CURRENT_USER;
+       } else if (strequal(hivename, "HKPD") ||
+                  strequal(hivename, "HKEY_PERFORMANCE_DATA"))
+       {
                (*reg_type) = HKEY_PERFORMANCE_DATA;
-       else {
+       else {
                DEBUG(10,("reg_hive_key: unrecognised hive key %s\n",
                          fullname));
-               return False;
+               goto done;
        }
 
-       return True;
+       ret = true;
+
+done:
+       TALLOC_FREE(tmp_ctx);
+       return ret;
 }
 
 static NTSTATUS registry_openkey(TALLOC_CTX *mem_ctx,
@@ -71,7 +85,9 @@ static NTSTATUS registry_openkey(TALLOC_CTX *mem_ctx,
        NTSTATUS status;
        struct winreg_String key;
 
-       if (!reg_hive_key(name, &hive, &key.name)) {
+       ZERO_STRUCT(key);
+
+       if (!reg_hive_key(mem_ctx, name, &hive, &key.name)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -82,9 +98,9 @@ static NTSTATUS registry_openkey(TALLOC_CTX *mem_ctx,
        }
 
        status = rpccli_winreg_OpenKey(pipe_hnd, mem_ctx, hive_hnd, key, 0,
-                                      access_mask, key_hnd);
+                                      access_mask, key_hnd, NULL);
        if (!(NT_STATUS_IS_OK(status))) {
-               rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, hive_hnd);
+               rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, hive_hnd, NULL);
                return status;
        }
 
@@ -116,7 +132,7 @@ static NTSTATUS registry_enumkeys(TALLOC_CTX *ctx,
        status = rpccli_winreg_QueryInfoKey(
                pipe_hnd, mem_ctx, key_hnd, &classname, &num_subkeys,
                &max_subkeylen, &max_classlen, &num_values, &max_valnamelen,
-               &max_valbufsize, &secdescsize, &last_changed_time );
+               &max_valbufsize, &secdescsize, &last_changed_time, NULL );
 
        if (!NT_STATUS_IS_OK(status)) {
                goto error;
@@ -141,6 +157,7 @@ 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;
@@ -154,9 +171,9 @@ static NTSTATUS registry_enumkeys(TALLOC_CTX *ctx,
 
                status = rpccli_winreg_EnumKey(pipe_hnd, mem_ctx, key_hnd,
                                               i, &name_buf, &class_buf,
-                                              &modtime);
-               
-               if (W_ERROR_EQUAL(ntstatus_to_werror(status),
+                                              &modtime, &werr);
+
+               if (W_ERROR_EQUAL(werr,
                                  WERR_NO_MORE_ITEMS) ) {
                        status = NT_STATUS_OK;
                        break;
@@ -229,7 +246,7 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
        status = rpccli_winreg_QueryInfoKey(
                pipe_hnd, mem_ctx, key_hnd, &classname, &num_subkeys,
                &max_subkeylen, &max_classlen, &num_values, &max_valnamelen,
-               &max_valbufsize, &secdescsize, &last_changed_time );
+               &max_valbufsize, &secdescsize, &last_changed_time, NULL );
 
        if (!NT_STATUS_IS_OK(status)) {
                goto error;
@@ -263,14 +280,15 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
                name_buf.size = max_valnamelen + 2;
 
                data_size = max_valbufsize;
+               data = (uint8 *)TALLOC(mem_ctx, data_size);
                value_length = 0;
 
                status = rpccli_winreg_EnumValue(pipe_hnd, mem_ctx, key_hnd,
                                                 i, &name_buf, &type,
-                                                &data, &data_size,
-                                                &value_length );
+                                                data, &data_size,
+                                                &value_length, &err);
 
-               if ( W_ERROR_EQUAL(ntstatus_to_werror(status),
+               if ( W_ERROR_EQUAL(err,
                                   WERR_NO_MORE_ITEMS) ) {
                        status = NT_STATUS_OK;
                        break;
@@ -314,6 +332,17 @@ static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
        return status;
 }
 
+static NTSTATUS registry_getsd(TALLOC_CTX *mem_ctx,
+                              struct rpc_pipe_client *pipe_hnd,
+                              struct policy_handle *key_hnd,
+                              uint32_t sec_info,
+                              struct KeySecurityData *sd)
+{
+       return rpccli_winreg_GetKeySecurity(pipe_hnd, mem_ctx, key_hnd,
+                                           sec_info, sd, NULL);
+}
+
+
 static NTSTATUS registry_setvalue(TALLOC_CTX *mem_ctx,
                                  struct rpc_pipe_client *pipe_hnd,
                                  struct policy_handle *key_hnd,
@@ -330,19 +359,22 @@ static NTSTATUS registry_setvalue(TALLOC_CTX *mem_ctx,
                return werror_to_ntstatus(err);
        }
 
+       ZERO_STRUCT(name_string);
+
        name_string.name = name;
        result = rpccli_winreg_SetValue(pipe_hnd, blob.data, key_hnd,
                                        name_string, value->type,
-                                       blob.data, blob.length);
+                                       blob.data, blob.length, NULL);
        TALLOC_FREE(blob.data);
        return result;
 }
 
-static NTSTATUS rpc_registry_setvalue_internal(const DOM_SID *domain_sid,
-                                              const char *domain_name, 
+static NTSTATUS rpc_registry_setvalue_internal(struct net_context *c,
+                                              const DOM_SID *domain_sid,
+                                              const char *domain_name,
                                               struct cli_state *cli,
                                               struct rpc_pipe_client *pipe_hnd,
-                                              TALLOC_CTX *mem_ctx, 
+                                              TALLOC_CTX *mem_ctx,
                                               int argc,
                                               const char **argv )
 {
@@ -350,7 +382,8 @@ static NTSTATUS rpc_registry_setvalue_internal(const DOM_SID *domain_sid,
        NTSTATUS status;
        struct registry_value value;
 
-       status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_WRITE,
+       status = registry_openkey(mem_ctx, pipe_hnd, argv[0],
+                                 SEC_RIGHTS_MAXIMUM_ALLOWED,
                                  &hive_hnd, &key_hnd);
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, "registry_openkey failed: %s\n",
@@ -387,29 +420,31 @@ static NTSTATUS rpc_registry_setvalue_internal(const DOM_SID *domain_sid,
        }
 
  error:
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
 
        return NT_STATUS_OK;
 }
 
-static int rpc_registry_setvalue( int argc, const char **argv )
+static int rpc_registry_setvalue(struct net_context *c, int argc,
+                                const char **argv )
 {
-       if (argc < 4) {
+       if (argc < 4 || c->display_usage) {
                d_fprintf(stderr, "usage: net rpc registry setvalue <key> "
                          "<valuename> <type> [<val>]+\n");
                return -1;
        }
 
-       return run_rpc_command( NULL, PI_WINREG, 0, 
+       return run_rpc_command(c, NULL, PI_WINREG, 0,
                rpc_registry_setvalue_internal, argc, argv );
 }
 
-static NTSTATUS rpc_registry_deletevalue_internal(const DOM_SID *domain_sid,
-                                                 const char *domain_name, 
+static NTSTATUS rpc_registry_deletevalue_internal(struct net_context *c,
+                                                 const DOM_SID *domain_sid,
+                                                 const char *domain_name,
                                                  struct cli_state *cli,
                                                  struct rpc_pipe_client *pipe_hnd,
-                                                 TALLOC_CTX *mem_ctx, 
+                                                 TALLOC_CTX *mem_ctx,
                                                  int argc,
                                                  const char **argv )
 {
@@ -417,7 +452,10 @@ static NTSTATUS rpc_registry_deletevalue_internal(const DOM_SID *domain_sid,
        NTSTATUS status;
        struct winreg_String valuename;
 
-       status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_WRITE,
+       ZERO_STRUCT(valuename);
+
+       status = registry_openkey(mem_ctx, pipe_hnd, argv[0],
+                                 SEC_RIGHTS_MAXIMUM_ALLOWED,
                                  &hive_hnd, &key_hnd);
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, "registry_openkey failed: %s\n",
@@ -428,36 +466,180 @@ static NTSTATUS rpc_registry_deletevalue_internal(const DOM_SID *domain_sid,
        valuename.name = argv[1];
 
        status = rpccli_winreg_DeleteValue(pipe_hnd, mem_ctx, &key_hnd,
-                                          valuename);
+                                          valuename, NULL);
 
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, "registry_deletevalue failed: %s\n",
                          nt_errstr(status));
        }
 
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
 
-       return NT_STATUS_OK;
+       return status;
 }
 
-static int rpc_registry_deletevalue( int argc, const char **argv )
+static int rpc_registry_deletevalue(struct net_context *c, int argc,
+                                   const char **argv )
 {
-       if (argc != 2) {
+       if (argc != 2 || c->display_usage) {
                d_fprintf(stderr, "usage: net rpc registry deletevalue <key> "
                          "<valuename>\n");
                return -1;
        }
 
-       return run_rpc_command( NULL, PI_WINREG, 0, 
+       return run_rpc_command(c, NULL, PI_WINREG, 0,
                rpc_registry_deletevalue_internal, argc, argv );
 }
 
-static NTSTATUS rpc_registry_createkey_internal(const DOM_SID *domain_sid,
-                                               const char *domain_name, 
+static NTSTATUS rpc_registry_getvalue_internal(struct net_context *c,
+                                              const DOM_SID *domain_sid,
+                                              const char *domain_name,
+                                              struct cli_state *cli,
+                                              struct rpc_pipe_client *pipe_hnd,
+                                              TALLOC_CTX *mem_ctx,
+                                              bool raw,
+                                              int argc,
+                                              const char **argv)
+{
+       struct policy_handle hive_hnd, key_hnd;
+       NTSTATUS status;
+       WERROR werr;
+       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();
+
+       ZERO_STRUCT(valuename);
+
+       status = registry_openkey(tmp_ctx, pipe_hnd, argv[0],
+                                 SEC_RIGHTS_MAXIMUM_ALLOWED,
+                                 &hive_hnd, &key_hnd);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "registry_openkey failed: %s\n",
+                         nt_errstr(status));
+               return status;
+       }
+
+       valuename.name = argv[1];
+
+       /*
+        * 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,
+                                         &valuename,
+                                         &type,
+                                         data,
+                                         &data_size,
+                                         &value_length,
+                                         NULL);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "registry_queryvalue failed: %s\n",
+                         nt_errstr(status));
+               goto done;
+       }
+
+       data = (uint8 *)TALLOC(tmp_ctx, data_size);
+       value_length = 0;
+
+       status = rpccli_winreg_QueryValue(pipe_hnd, tmp_ctx, &key_hnd,
+                                         &valuename,
+                                         &type,
+                                         data,
+                                         &data_size,
+                                         &value_length,
+                                         NULL);
+
+       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);
+               goto done;
+       }
+
+       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);
+
+       TALLOC_FREE(tmp_ctx);
+
+       return status;
+}
+
+static NTSTATUS rpc_registry_getvalue_full(struct net_context *c,
+                                          const 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)
+{
+       return rpc_registry_getvalue_internal(c, domain_sid, domain_name,
+                                             cli, pipe_hnd, mem_ctx, false,
+                                             argc, argv);
+}
+
+static int rpc_registry_getvalue(struct net_context *c, int argc,
+                                const char **argv)
+{
+       if (argc != 2 || c->display_usage) {
+               d_fprintf(stderr, "usage: net rpc registry getvalue <key> "
+                         "<valuename>\n");
+               return -1;
+       }
+
+       return run_rpc_command(c, NULL, PI_WINREG, 0,
+               rpc_registry_getvalue_full, argc, argv);
+}
+
+static NTSTATUS rpc_registry_getvalue_raw(struct net_context *c,
+                                         const 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)
+{
+       return rpc_registry_getvalue_internal(c, domain_sid, domain_name,
+                                             cli, pipe_hnd, mem_ctx, true,
+                                             argc, argv);
+}
+
+static int rpc_registry_getvalueraw(struct net_context *c, int argc,
+                                   const char **argv)
+{
+       if (argc != 2 || c->display_usage) {
+               d_fprintf(stderr, "usage: net rpc registry getvalue <key> "
+                         "<valuename>\n");
+               return -1;
+       }
+
+       return run_rpc_command(c, NULL, PI_WINREG, 0,
+               rpc_registry_getvalue_raw, argc, argv);
+}
+
+static NTSTATUS rpc_registry_createkey_internal(struct net_context *c,
+                                               const DOM_SID *domain_sid,
+                                               const char *domain_name,
                                                struct cli_state *cli,
                                                struct rpc_pipe_client *pipe_hnd,
-                                               TALLOC_CTX *mem_ctx, 
+                                               TALLOC_CTX *mem_ctx,
                                                int argc,
                                                const char **argv )
 {
@@ -467,12 +649,15 @@ static NTSTATUS rpc_registry_createkey_internal(const DOM_SID *domain_sid,
        enum winreg_CreateAction action;
        NTSTATUS status;
 
-       if (!reg_hive_key(argv[0], &hive, &key.name)) {
+       ZERO_STRUCT(key);
+       ZERO_STRUCT(keyclass);
+
+       if (!reg_hive_key(mem_ctx, argv[0], &hive, &key.name)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
        status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive,
-                                      REG_KEY_READ|REG_KEY_WRITE,
+                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
                                       &hive_hnd);
        if (!(NT_STATUS_IS_OK(status))) {
                return status;
@@ -483,11 +668,11 @@ static NTSTATUS rpc_registry_createkey_internal(const DOM_SID *domain_sid,
 
        status = rpccli_winreg_CreateKey(pipe_hnd, mem_ctx, &hive_hnd, key,
                                         keyclass, 0, REG_KEY_READ, NULL,
-                                        &key_hnd, &action);
+                                        &key_hnd, &action, NULL);
        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);
+               rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
                return status;
        }
 
@@ -503,28 +688,30 @@ static NTSTATUS rpc_registry_createkey_internal(const DOM_SID *domain_sid,
                        break;
        }
 
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
 
        return status;
 }
 
-static int rpc_registry_createkey( int argc, const char **argv )
+static int rpc_registry_createkey(struct net_context *c, int argc,
+                                 const char **argv )
 {
-       if (argc != 1) {
+       if (argc != 1 || c->display_usage) {
                d_fprintf(stderr, "usage: net rpc registry createkey <key>\n");
                return -1;
        }
 
-       return run_rpc_command( NULL, PI_WINREG, 0, 
+       return run_rpc_command(c, NULL, PI_WINREG, 0,
                rpc_registry_createkey_internal, argc, argv );
 }
 
-static NTSTATUS rpc_registry_deletekey_internal(const DOM_SID *domain_sid,
-                                               const char *domain_name, 
+static NTSTATUS rpc_registry_deletekey_internal(struct net_context *c,
+                                               const DOM_SID *domain_sid,
+                                               const char *domain_name,
                                                struct cli_state *cli,
                                                struct rpc_pipe_client *pipe_hnd,
-                                               TALLOC_CTX *mem_ctx, 
+                                               TALLOC_CTX *mem_ctx,
                                                int argc,
                                                const char **argv )
 {
@@ -533,18 +720,21 @@ static NTSTATUS rpc_registry_deletekey_internal(const DOM_SID *domain_sid,
        struct winreg_String key;
        NTSTATUS status;
 
-       if (!reg_hive_key(argv[0], &hive, &key.name)) {
+       ZERO_STRUCT(key);
+
+       if (!reg_hive_key(mem_ctx, argv[0], &hive, &key.name)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive, REG_KEY_WRITE,
+       status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive,
+                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
                                       &hive_hnd);
        if (!(NT_STATUS_IS_OK(status))) {
                return status;
        }
 
-       status = rpccli_winreg_DeleteKey(pipe_hnd, mem_ctx, &hive_hnd, key);
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd);
+       status = rpccli_winreg_DeleteKey(pipe_hnd, mem_ctx, &hive_hnd, key, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
 
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, "deletekey returned %s\n",
@@ -554,29 +744,30 @@ static NTSTATUS rpc_registry_deletekey_internal(const DOM_SID *domain_sid,
        return status;
 }
 
-static int rpc_registry_deletekey( int argc, const char **argv )
+static int rpc_registry_deletekey(struct net_context *c, int argc, const char **argv )
 {
-       if (argc != 1) {
+       if (argc != 1 || c->display_usage) {
                d_fprintf(stderr, "usage: net rpc registry deletekey <key>\n");
                return -1;
        }
 
-       return run_rpc_command( NULL, PI_WINREG, 0, 
+       return run_rpc_command(c, NULL, PI_WINREG, 0,
                rpc_registry_deletekey_internal, argc, argv );
 }
 
 /********************************************************************
 ********************************************************************/
 
-static NTSTATUS rpc_registry_enumerate_internal(const DOM_SID *domain_sid,
-                                               const char *domain_name, 
+static NTSTATUS rpc_registry_enumerate_internal(struct net_context *c,
+                                               const DOM_SID *domain_sid,
+                                               const char *domain_name,
                                                struct cli_state *cli,
                                                struct rpc_pipe_client *pipe_hnd,
-                                               TALLOC_CTX *mem_ctx, 
+                                               TALLOC_CTX *mem_ctx,
                                                int argc,
                                                const char **argv )
 {
-       POLICY_HND pol_hive, pol_key; 
+       POLICY_HND pol_hive, pol_key;
        NTSTATUS status;
        uint32 num_subkeys = 0;
        uint32 num_values = 0;
@@ -584,11 +775,11 @@ static NTSTATUS rpc_registry_enumerate_internal(const DOM_SID *domain_sid,
        NTTIME **modtimes = NULL;
        uint32 i;
        struct registry_value **values = NULL;
-       
-       if (argc != 1 ) {
-               d_printf("Usage:    net rpc enumerate <path> [recurse]\n");
-               d_printf("Example:  net rpc enumerate 'HKLM\\Software\\Samba'\n");
-               return NT_STATUS_OK;
+
+       if (argc != 1 || c->display_usage) {
+               d_printf("Usage:    net rpc registry enumerate <path>\n");
+               d_printf("Example:  net rpc registry enumerate 'HKLM\\Software\\Samba'\n");
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
        status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_READ,
@@ -608,11 +799,7 @@ static NTSTATUS rpc_registry_enumerate_internal(const DOM_SID *domain_sid,
        }
 
        for (i=0; i<num_subkeys; i++) {
-               d_printf("Keyname   = %s\n", names[i]);
-               d_printf("Modtime   = %s\n", modtimes[i]
-                        ? http_timestring(nt_time_to_unix(*modtimes[i]))
-                        : "None");
-               d_printf("\n" );
+               print_registry_key(names[i], modtimes[i]);
        }
 
        status = registry_enumvalues(mem_ctx, pipe_hnd, &pol_key, &num_values,
@@ -624,40 +811,11 @@ static NTSTATUS rpc_registry_enumerate_internal(const DOM_SID *domain_sid,
        }
 
        for (i=0; i<num_values; i++) {
-               struct registry_value *v = values[i];
-               d_printf("Valuename  = %s\n", names[i]);
-               d_printf("Type       = %s\n",
-                        reg_type_lookup(v->type));
-               switch(v->type) {
-               case REG_DWORD:
-                       d_printf("Value      = %d\n", v->v.dword);
-                       break;
-               case REG_SZ:
-               case REG_EXPAND_SZ:
-                       d_printf("Value      = \"%s\"\n", v->v.sz.str);
-                       break;
-               case REG_MULTI_SZ: {
-                       uint32 j;
-                       for (j = 0; j < v->v.multi_sz.num_strings; j++) {
-                               d_printf("Value[%3.3d] = \"%s\"\n", j,
-                                        v->v.multi_sz.strings[j]);
-                       }
-                       break;
-               }
-               case REG_BINARY:
-                       d_printf("Value      = %d bytes\n",
-                                (int)v->v.binary.length);
-                       break;
-               default:
-                       d_printf("Value      = <unprintable>\n");
-                       break;
-               }
-                       
-               d_printf("\n");
+               print_registry_value_with_name(names[i], values[i]);
        }
 
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key );
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive );
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive, NULL);
 
        return status;
 }
@@ -665,33 +823,35 @@ static NTSTATUS rpc_registry_enumerate_internal(const DOM_SID *domain_sid,
 /********************************************************************
 ********************************************************************/
 
-static int rpc_registry_enumerate( int argc, const char **argv )
+static int rpc_registry_enumerate(struct net_context *c, int argc,
+                                 const char **argv )
 {
-       return run_rpc_command( NULL, PI_WINREG, 0, 
+       return run_rpc_command(c, NULL, PI_WINREG, 0,
                rpc_registry_enumerate_internal, argc, argv );
 }
 
 /********************************************************************
 ********************************************************************/
 
-static NTSTATUS rpc_registry_save_internal(const DOM_SID *domain_sid,
-                                       const char *domain_name, 
+static NTSTATUS rpc_registry_save_internal(struct net_context *c,
+                                       const DOM_SID *domain_sid,
+                                       const char *domain_name,
                                        struct cli_state *cli,
                                        struct rpc_pipe_client *pipe_hnd,
-                                       TALLOC_CTX *mem_ctx, 
+                                       TALLOC_CTX *mem_ctx,
                                        int argc,
                                        const char **argv )
 {
        WERROR result = WERR_GENERAL_FAILURE;
-       POLICY_HND pol_hive, pol_key; 
+       POLICY_HND pol_hive, pol_key;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        struct winreg_String filename;
-       
-       if (argc != 2 ) {
-               d_printf("Usage:    net rpc backup <path> <file> \n");
-               return NT_STATUS_OK;
+
+       if (argc != 2 || c->display_usage) {
+               d_printf("Usage:    net rpc registry backup <path> <file> \n");
+               return NT_STATUS_INVALID_PARAMETER;
        }
-       
+
        status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_ALL,
                                  &pol_hive, &pol_key);
        if (!NT_STATUS_IS_OK(status)) {
@@ -701,15 +861,15 @@ static NTSTATUS rpc_registry_save_internal(const DOM_SID *domain_sid,
        }
 
        filename.name = argv[1];
-       status = rpccli_winreg_SaveKey( pipe_hnd, mem_ctx, &pol_key, &filename, NULL  );
+       status = rpccli_winreg_SaveKey( pipe_hnd, mem_ctx, &pol_key, &filename, NULL, NULL);
        if ( !W_ERROR_IS_OK(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 );
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive );
+
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive, NULL);
 
        return status;
 }
@@ -717,9 +877,9 @@ static NTSTATUS rpc_registry_save_internal(const DOM_SID *domain_sid,
 /********************************************************************
 ********************************************************************/
 
-static int rpc_registry_save( int argc, const char **argv )
+static int rpc_registry_save(struct net_context *c, int argc, const char **argv )
 {
-       return run_rpc_command( NULL, PI_WINREG, 0, 
+       return run_rpc_command(c, NULL, PI_WINREG, 0,
                rpc_registry_save_internal, argc, argv );
 }
 
@@ -730,7 +890,7 @@ static int rpc_registry_save( int argc, const char **argv )
 static void dump_values( REGF_NK_REC *nk )
 {
        int i, j;
-       pstring data_str;
+       char *data_str = NULL;
        uint32 data_size, data;
 
        if ( !nk->values )
@@ -743,7 +903,14 @@ static void dump_values( REGF_NK_REC *nk )
                data_size = nk->values[i].data_size & ~VK_DATA_IN_OFFSET;
                switch ( nk->values[i].type ) {
                        case REG_SZ:
-                               rpcstr_pull( data_str, nk->values[i].data, sizeof(data_str), -1, STR_TERMINATE );
+                               rpcstr_pull_talloc(talloc_tos(),
+                                               &data_str,
+                                               nk->values[i].data,
+                                               -1,
+                                               STR_TERMINATE);
+                               if (!data_str) {
+                                       break;
+                               }
                                d_printf( "%s", data_str );
                                break;
                        case REG_MULTI_SZ:
@@ -774,99 +941,111 @@ static void dump_values( REGF_NK_REC *nk )
 /********************************************************************
 ********************************************************************/
 
-static BOOL dump_registry_tree( REGF_FILE *file, REGF_NK_REC *nk, const char *parent )
+static bool dump_registry_tree( REGF_FILE *file, REGF_NK_REC *nk, const char *parent )
 {
        REGF_NK_REC *key;
-       pstring regpath;
 
        /* depth first dump of the registry tree */
 
        while ( (key = regfio_fetch_subkey( file, nk )) ) {
-               pstr_sprintf( regpath, "%s\\%s", parent, key->keyname );
+               char *regpath;
+               if (asprintf(&regpath, "%s\\%s", parent, key->keyname) < 0) {
+                       break;
+               }
                d_printf("[%s]\n", regpath );
                dump_values( key );
                d_printf("\n");
                dump_registry_tree( file, key, regpath );
+               SAFE_FREE(regpath);
        }
 
-       return True;
+       return true;
 }
 
 /********************************************************************
 ********************************************************************/
 
-static BOOL write_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk, 
+static bool write_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk,
                                  REGF_NK_REC *parent, REGF_FILE *outfile,
                                 const char *parentpath )
 {
        REGF_NK_REC *key, *subkey;
-       REGVAL_CTR *values;
-       REGSUBKEY_CTR *subkeys;
+       REGVAL_CTR *values = NULL;
+       REGSUBKEY_CTR *subkeys = NULL;
        int i;
-       pstring path;
+       char *path = NULL;
 
        if ( !( subkeys = TALLOC_ZERO_P( infile->mem_ctx, REGSUBKEY_CTR )) ) {
                DEBUG(0,("write_registry_tree: talloc() failed!\n"));
-               return False;
+               return false;
        }
 
        if ( !(values = TALLOC_ZERO_P( subkeys, REGVAL_CTR )) ) {
                DEBUG(0,("write_registry_tree: talloc() failed!\n"));
-               return False;
+               TALLOC_FREE(subkeys);
+               return false;
        }
 
        /* copy values into the REGVAL_CTR */
-       
+
        for ( i=0; i<nk->num_values; i++ ) {
                regval_ctr_addvalue( values, nk->values[i].valuename, nk->values[i].type,
                        (const char *)nk->values[i].data, (nk->values[i].data_size & ~VK_DATA_IN_OFFSET) );
        }
 
        /* copy subkeys into the REGSUBKEY_CTR */
-       
+
        while ( (subkey = regfio_fetch_subkey( infile, nk )) ) {
                regsubkey_ctr_addkey( subkeys, subkey->keyname );
        }
-       
+
        key = regfio_write_key( outfile, nk->keyname, values, subkeys, nk->sec_desc->sec_desc, parent );
 
        /* write each one of the subkeys out */
 
-       pstr_sprintf( path, "%s%s%s", parentpath, parent ? "\\" : "", nk->keyname );
+       path = talloc_asprintf(subkeys,
+                       "%s%s%s",
+                       parentpath,
+                       parent ? "\\" : "",
+                       nk->keyname);
+       if (!path) {
+               TALLOC_FREE(subkeys);
+               return false;
+       }
+
        nk->subkey_index = 0;
        while ( (subkey = regfio_fetch_subkey( infile, nk )) ) {
                write_registry_tree( infile, subkey, key, outfile, path );
        }
 
-       TALLOC_FREE( subkeys );
-
        d_printf("[%s]\n", path );
-       
-       return True;
+       TALLOC_FREE(subkeys);
+
+       return true;
 }
 
 /********************************************************************
 ********************************************************************/
 
-static int rpc_registry_dump( int argc, const char **argv )
+static int rpc_registry_dump(struct net_context *c, int argc, const char **argv)
 {
        REGF_FILE   *registry;
        REGF_NK_REC *nk;
-       
-       if (argc != 1 ) {
-               d_printf("Usage:    net rpc dump <file> \n");
-               return 0;
+
+       if (argc != 1 || c->display_usage) {
+               d_printf("Usage:    net rpc registry dump <file> \n");
+               return -1;
        }
-       
+
        d_printf("Opening %s....", argv[0]);
        if ( !(registry = regfio_open( argv[0], O_RDONLY, 0)) ) {
                d_fprintf(stderr, "Failed to open %s for reading\n", argv[0]);
                return 1;
        }
        d_printf("ok\n");
-       
+
        /* get the root of the registry file */
-       
+
        if ((nk = regfio_rootkey( registry )) == NULL) {
                d_fprintf(stderr, "Could not get rootkey\n");
                regfio_close( registry );
@@ -880,7 +1059,7 @@ static int rpc_registry_dump( int argc, const char **argv )
 
 #if 0
        talloc_report_full( registry->mem_ctx, stderr );
-#endif 
+#endif
        d_printf("Closing registry...");
        regfio_close( registry );
        d_printf("ok\n");
@@ -891,17 +1070,17 @@ static int rpc_registry_dump( int argc, const char **argv )
 /********************************************************************
 ********************************************************************/
 
-static int rpc_registry_copy( int argc, const char **argv )
+static int rpc_registry_copy(struct net_context *c, int argc, const char **argv )
 {
        REGF_FILE   *infile = NULL, *outfile = NULL;
        REGF_NK_REC *nk;
        int result = 1;
-       
-       if (argc != 2 ) {
-               d_printf("Usage:    net rpc copy <srcfile> <newfile>\n");
-               return 0;
+
+       if (argc != 2 || c->display_usage) {
+               d_printf("Usage:    net rpc registry copy <srcfile> <newfile>\n");
+               return -1;
        }
-       
+
        d_printf("Opening %s....", argv[0]);
        if ( !(infile = regfio_open( argv[0], O_RDONLY, 0 )) ) {
                d_fprintf(stderr, "Failed to open %s for reading\n", argv[0]);
@@ -915,9 +1094,9 @@ static int rpc_registry_copy( int argc, const char **argv )
                goto out;
        }
        d_printf("ok\n");
-       
+
        /* get the root of the registry file */
-       
+
        if ((nk = regfio_rootkey( infile )) == NULL) {
                d_fprintf(stderr, "Could not get rootkey\n");
                goto out;
@@ -948,27 +1127,185 @@ out:
 /********************************************************************
 ********************************************************************/
 
-int net_rpc_registry(int argc, const char **argv) 
+static NTSTATUS rpc_registry_getsd_internal(struct net_context *c,
+                                           const 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 functable2 func[] = {
-               { "enumerate", rpc_registry_enumerate,
-                 "Enumerate registry keys and values" },
-               { "createkey",  rpc_registry_createkey,
-                 "Create a new registry key" },
-               { "deletekey",  rpc_registry_deletekey,
-                 "Delete a registry key" },
-               { "setvalue",  rpc_registry_setvalue,
-                 "Set a new registry value" },
-               { "deletevalue",  rpc_registry_deletevalue,
-                 "Delete a registry value" },
-               { "save", rpc_registry_save,
-                 "Save a registry file" },
-               { "dump", rpc_registry_dump,
-                 "Dump a registry file" },
-               { "copy", rpc_registry_copy,
-                 "Copy a registry file" },
-               {NULL, NULL, NULL}
+       POLICY_HND pol_hive, pol_key;
+       NTSTATUS status;
+       enum ndr_err_code ndr_err;
+       struct KeySecurityData *sd = NULL;
+       uint32_t sec_info;
+       DATA_BLOB blob;
+       struct security_descriptor sec_desc;
+       uint32_t access_mask = REG_KEY_READ |
+                              SEC_RIGHT_MAXIMUM_ALLOWED |
+                              SEC_RIGHT_SYSTEM_SECURITY;
+
+       if (argc <1 || argc > 2 || c->display_usage) {
+               d_printf("Usage:    net rpc registry getsd <path> <secinfo>\n");
+               d_printf("Example:  net rpc registry getsd 'HKLM\\Software\\Samba'\n");
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       status = registry_openkey(mem_ctx, pipe_hnd, argv[0],
+                                 access_mask,
+                                 &pol_hive, &pol_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "registry_openkey failed: %s\n",
+                         nt_errstr(status));
+               return status;
+       }
+
+       sd = TALLOC_ZERO_P(mem_ctx, struct KeySecurityData);
+       if (!sd) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       sd->size = 0x1000;
+
+       if (argc >= 2) {
+               sscanf(argv[1], "%x", &sec_info);
+       } else {
+               sec_info = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL;
+       }
+
+       status = registry_getsd(mem_ctx, pipe_hnd, &pol_key, sec_info, sd);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "getting sd failed: %s\n",
+                         nt_errstr(status));
+               goto out;
+       }
+
+       blob.data = sd->data;
+       blob.length = sd->size;
+
+       ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &sec_desc,
+                                      (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               status = ndr_map_error2ntstatus(ndr_err);
+               goto out;
+       }
+       status = NT_STATUS_OK;
+
+       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);
+
+       return status;
+}
+
+
+static int rpc_registry_getsd(struct net_context *c, int argc, const char **argv)
+{
+       return run_rpc_command(c, NULL, PI_WINREG, 0,
+               rpc_registry_getsd_internal, argc, argv);
+}
+
+/********************************************************************
+********************************************************************/
+
+int net_rpc_registry(struct net_context *c, int argc, const char **argv)
+{
+       struct functable3 func[] = {
+               {
+                       "enumerate",
+                       rpc_registry_enumerate,
+                       NET_TRANSPORT_RPC,
+                       "Enumerate registry keys and values",
+                       "net rpc registry enumerate\n"
+                       "    Enumerate registry keys and values"
+               },
+               {
+                       "createkey",
+                       rpc_registry_createkey,
+                       NET_TRANSPORT_RPC,
+                       "Create a new registry key",
+                       "net rpc registry createkey\n"
+                       "    Create a new registry key"
+               },
+               {
+                       "deletekey",
+                       rpc_registry_deletekey,
+                       NET_TRANSPORT_RPC,
+                       "Delete a registry key",
+                       "net rpc registry deletekey\n"
+                       "    Delete a registry key"
+               },
+               {
+                       "getvalue",
+                       rpc_registry_getvalue,
+                       NET_TRANSPORT_RPC,
+                       "Print a registry value",
+                       "net rpc registry getvalue\n"
+                       "    Print a registry value"
+               },
+               {
+                       "getvalueraw",
+                       rpc_registry_getvalueraw,
+                       NET_TRANSPORT_RPC,
+                       "Print a registry value",
+                       "net rpc registry getvalueraw\n"
+                       "    Print a registry value (raw version)"
+               },
+               {
+                       "setvalue",
+                       rpc_registry_setvalue,
+                       NET_TRANSPORT_RPC,
+                       "Set a new registry value",
+                       "net rpc registry setvalue\n"
+                       "    Set a new registry value"
+               },
+               {
+                       "deletevalue",
+                       rpc_registry_deletevalue,
+                       NET_TRANSPORT_RPC,
+                       "Delete a registry value",
+                       "net rpc registry deletevalue\n"
+                       "    Delete a registry value"
+               },
+               {
+                       "save",
+                       rpc_registry_save,
+                       NET_TRANSPORT_RPC,
+                       "Save a registry file",
+                       "net rpc registry save\n"
+                       "    Save a registry file"
+               },
+               {
+                       "dump",
+                       rpc_registry_dump,
+                       NET_TRANSPORT_RPC,
+                       "Dump a registry file",
+                       "net rpc registry dump\n"
+                       "    Dump a registry file"
+               },
+               {
+                       "copy",
+                       rpc_registry_copy,
+                       NET_TRANSPORT_RPC,
+                       "Copy a registry file",
+                       "net rpc registry copy\n"
+                       "    Copy a registry file"
+               },
+               {
+                       "getsd",
+                       rpc_registry_getsd,
+                       NET_TRANSPORT_RPC,
+                       "Get security descriptor",
+                       "net rpc registry getsd\n"
+                       "    Get security descriptior"
+               },
+               {NULL, NULL, 0, NULL, NULL}
        };
-       
-       return net_run_function2(argc, argv, "net rpc registry", func);
+
+       return net_run_function3(c, argc, argv, "net rpc registry", func);
 }