Fix lsa_TrustedDomainInfo callers.
[ira/wip.git] / source3 / utils / net_rpc_registry.c
index aacf97445cb99dd650113726efd2a3029c770586..da078f4d3619817c295d9b993ba220b4447f64e2 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(TALLOC_CTX *ctx, const char *fullname,
+                        uint32 *reg_type, const char **key_name)
+{
+       WERROR werr;
+       char *hivename = NULL;
+       char *tmp_keyname = NULL;
+       bool ret = false;
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+       werr = split_hive_key(tmp_ctx, fullname, &hivename, &tmp_keyname);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
+
+       *key_name = talloc_strdup(ctx, tmp_keyname);
+       if (*key_name == NULL) {
+               goto done;
+       }
+
+       if (strequal(hivename, "HKLM") ||
+           strequal(hivename, "HKEY_LOCAL_MACHINE"))
+       {
+               (*reg_type) = HKEY_LOCAL_MACHINE;
+       } else if (strequal(hivename, "HKCR") ||
+                  strequal(hivename, "HKEY_CLASSES_ROOT")) 
+       {
+               (*reg_type) = HKEY_CLASSES_ROOT;
+       } else if (strequal(hivename, "HKU") ||
+                  strequal(hivename, "HKEY_USERS"))
+       {
+               (*reg_type) = HKEY_USERS;
+       } 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 {
+               DEBUG(10,("reg_hive_key: unrecognised hive key %s\n",
+                         fullname));
+               goto done;
+       }
+
+       ret = true;
+
+done:
+       TALLOC_FREE(tmp_ctx);
+       return ret;
+}
 
-void dump_regval_buffer( uint32 type, REGVAL_BUFFER *buffer )
+static NTSTATUS registry_openkey(TALLOC_CTX *mem_ctx,
+                                struct rpc_pipe_client *pipe_hnd,
+                                const char *name, uint32 access_mask,
+                                struct policy_handle *hive_hnd,
+                                struct policy_handle *key_hnd)
 {
-       pstring string;
-       uint32 value;
-       
-       switch (type) {
-       case REG_SZ:
-               rpcstr_pull( string, buffer->buffer, sizeof(string), -1, STR_TERMINATE );
-               d_printf("%s\n", string);
-               break;
-       case REG_MULTI_SZ: {
-               int i, num_values;
-               char **values;
+       uint32 hive;
+       NTSTATUS status;
+       struct winreg_String key;
 
-               d_printf("\n");
+       ZERO_STRUCT(key);
+
+       if (!reg_hive_key(mem_ctx, name, &hive, &key.name)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive, access_mask,
+                                      hive_hnd);
+       if (!(NT_STATUS_IS_OK(status))) {
+               return status;
+       }
+
+       status = rpccli_winreg_OpenKey(pipe_hnd, mem_ctx, hive_hnd, key, 0,
+                                      access_mask, key_hnd, NULL);
+       if (!(NT_STATUS_IS_OK(status))) {
+               rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, hive_hnd, NULL);
+               return status;
+       }
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS registry_enumkeys(TALLOC_CTX *ctx,
+                                 struct rpc_pipe_client *pipe_hnd,
+                                 struct policy_handle *key_hnd,
+                                 uint32 *pnum_keys, char ***pnames,
+                                 char ***pclasses, NTTIME ***pmodtimes)
+{
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+       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;
+       char **names, **classes;
+       NTTIME **modtimes;
+
+       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,
+               &max_subkeylen, &max_classlen, &num_values, &max_valnamelen,
+               &max_valbufsize, &secdescsize, &last_changed_time, NULL );
+
+       if (!NT_STATUS_IS_OK(status)) {
+               goto error;
+       }
+
+       if (num_subkeys == 0) {
+               *pnum_keys = 0;
+               TALLOC_FREE(mem_ctx);
+               return NT_STATUS_OK;
+       }
 
-               if (!NT_STATUS_IS_OK(reg_pull_multi_sz(NULL, buffer->buffer,
-                                                      buffer->buf_len,
-                                                      &num_values,
-                                                      &values))) {
-                       d_printf("reg_pull_multi_sz failed\n");
+       if ((!(names = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_subkeys))) ||
+           (!(classes = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_subkeys))) ||
+           (!(modtimes = TALLOC_ZERO_ARRAY(mem_ctx, NTTIME *,
+                                           num_subkeys)))) {
+               status = NT_STATUS_NO_MEMORY;
+               goto error;
+       }
+
+       for (i=0; i<num_subkeys; i++) {
+               char c, n;
+               struct winreg_StringBuf class_buf;
+               struct winreg_StringBuf name_buf;
+               NTTIME modtime;
+               WERROR werr;
+
+               c = '\0';
+               class_buf.name = &c;
+               class_buf.size = max_classlen+2;
+
+               n = '\0';
+               name_buf.name = &n;
+               name_buf.size = max_subkeylen+2;
+
+               ZERO_STRUCT(modtime);
+
+               status = rpccli_winreg_EnumKey(pipe_hnd, mem_ctx, key_hnd,
+                                              i, &name_buf, &class_buf,
+                                              &modtime, &werr);
+               
+               if (W_ERROR_EQUAL(werr,
+                                 WERR_NO_MORE_ITEMS) ) {
+                       status = NT_STATUS_OK;
                        break;
                }
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto error;
+               }
+
+               classes[i] = NULL;
 
-               for (i=0; i<num_values; i++) {
-                       d_printf("%s\n", values[i]);
+               if (class_buf.name &&
+                   (!(classes[i] = talloc_strdup(classes, class_buf.name)))) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto error;
+               }
+
+               if (!(names[i] = talloc_strdup(names, name_buf.name))) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto error;
+               }
+
+               if ((!(modtimes[i] = (NTTIME *)talloc_memdup(
+                              modtimes, &modtime, sizeof(modtime))))) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto error;
                }
-               TALLOC_FREE(values);
-               break;
-       }
-       case REG_DWORD:
-               value = IVAL( buffer->buffer, 0 );
-               d_printf( "0x%x\n", value );
-               break;
-       case REG_BINARY:
-               d_printf("\n");
-               break;
-       
-       
-       default:
-               d_printf( "\tUnknown type [%d]\n", type );
        }
-}
 
-/********************************************************************
-********************************************************************/
+       *pnum_keys = num_subkeys;
 
-static NTSTATUS rpc_registry_enumerate_internal(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 )
+       if (pnames) {
+               *pnames = talloc_move(ctx, &names);
+       }
+       if (pclasses) {
+               *pclasses = talloc_move(ctx, &classes);
+       }
+       if (pmodtimes) {
+               *pmodtimes = talloc_move(ctx, &modtimes);
+       }
+
+       status = NT_STATUS_OK;
+
+ error:
+       TALLOC_FREE(mem_ctx);
+       return status;
+}
+
+static NTSTATUS registry_enumvalues(TALLOC_CTX *ctx,
+                                   struct rpc_pipe_client *pipe_hnd,
+                                   struct policy_handle *key_hnd,
+                                   uint32 *pnum_values, char ***pvalnames,
+                                   struct registry_value ***pvalues)
 {
-       WERROR result = WERR_GENERAL_FAILURE;
-       uint32 hive;
-       pstring subpath;
-       POLICY_HND pol_hive, pol_key; 
-       uint32 idx;
+       TALLOC_CTX *mem_ctx;
        NTSTATUS status;
-       struct winreg_String subkeyname;
-       struct winreg_String classname;
        uint32 num_subkeys, max_subkeylen, max_classlen;
        uint32 num_values, max_valnamelen, max_valbufsize;
-       uint32 secdescsize;
+       uint32 i;
        NTTIME last_changed_time;
-       struct winreg_StringBuf subkey_namebuf;
-       char *name_buffer; 
-       uint8 *value_buffer;
-       
-       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;
+       uint32 secdescsize;
+       struct winreg_String classname;
+       struct registry_value **values;
+       char **names;
+
+       if (!(mem_ctx = talloc_new(ctx))) {
+               return NT_STATUS_NO_MEMORY;
        }
-       
-       if ( !reg_split_hive( argv[0], &hive, subpath ) ) {
-               d_fprintf(stderr, "invalid registry path\n");
+
+       ZERO_STRUCT(classname);
+       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, NULL );
+
+       if (!NT_STATUS_IS_OK(status)) {
+               goto error;
+       }
+
+       if (num_values == 0) {
+               *pnum_values = 0;
+               TALLOC_FREE(mem_ctx);
                return NT_STATUS_OK;
        }
-       
-       /* open the top level hive and then the registry key */
-       
-       status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive, MAXIMUM_ALLOWED_ACCESS, &pol_hive );
-       if ( !NT_STATUS_IS_OK(status) ) {
-               d_fprintf(stderr, "Unable to connect to remote registry: "
-                         "%s\n", nt_errstr(status));
+
+       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;
+       }
+
+       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 = rpccli_winreg_EnumValue(pipe_hnd, mem_ctx, key_hnd,
+                                                i, &name_buf, &type,
+                                                data, &data_size,
+                                                &value_length, &err);
+
+               if ( W_ERROR_EQUAL(err,
+                                  WERR_NO_MORE_ITEMS) ) {
+                       status = NT_STATUS_OK;
+                       break;
+               }
+
+               if (!(NT_STATUS_IS_OK(status))) {
+                       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;
+               }
+
+               err = registry_pull_value(values, &values[i], type, data,
+                                         data_size, value_length);
+               if (!W_ERROR_IS_OK(err)) {
+                       status = werror_to_ntstatus(err);
+                       goto error;
+               }
+       }
+
+       *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_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,
+                                 const char *name,
+                                 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);
+       }
+
+       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, NULL);
+       TALLOC_FREE(blob.data);
+       return result;
+}
+
+static NTSTATUS rpc_registry_setvalue_internal(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 policy_handle hive_hnd, key_hnd;
+       NTSTATUS status;
+       struct registry_value value;
+
+       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",
+                         nt_errstr(status));
                return status;
        }
-       
-       subkeyname.name = subpath;
-       status = rpccli_winreg_OpenKey(pipe_hnd, mem_ctx, &pol_hive, subkeyname,
-                                      0, MAXIMUM_ALLOWED_ACCESS, &pol_key );
-       if ( !NT_STATUS_IS_OK(status) ) {
-               d_fprintf(stderr, "Unable to open [%s]: %s\n", argv[0],
+
+       if (!strequal(argv[2], "multi_sz") && (argc != 4)) {
+               d_fprintf(stderr, "Too many args for type %s\n", argv[2]);
+               return NT_STATUS_NOT_IMPLEMENTED;
+       }
+
+       if (strequal(argv[2], "dword")) {
+               value.type = REG_DWORD;
+               value.v.dword = strtoul(argv[3], NULL, 10);
+       }
+       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]);
+       }
+       else {
+               d_fprintf(stderr, "type \"%s\" not implemented\n", argv[2]);
+               status = NT_STATUS_NOT_IMPLEMENTED;
+               goto error;
+       }
+
+       status = registry_setvalue(mem_ctx, pipe_hnd, &key_hnd,
+                                  argv[1], &value);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "registry_setvalue failed: %s\n",
                          nt_errstr(status));
-               return werror_to_ntstatus(result);
        }
 
-       classname.name = NULL;
-       status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, &pol_key, 
-                       &classname, &num_subkeys, &max_subkeylen,
-                       &max_classlen, &num_values, &max_valnamelen,
-                       &max_valbufsize, &secdescsize, &last_changed_time );
+ error:
+       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 )
+{
+       if (argc < 4) {
+               d_fprintf(stderr, "usage: net rpc registry setvalue <key> "
+                         "<valuename> <type> [<val>]+\n");
+               return -1;
+       }
+
+       return run_rpc_command( 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, 
+                                                 struct cli_state *cli,
+                                                 struct rpc_pipe_client *pipe_hnd,
+                                                 TALLOC_CTX *mem_ctx, 
+                                                 int argc,
+                                                 const char **argv )
+{
+       struct policy_handle hive_hnd, key_hnd;
+       NTSTATUS status;
+       struct winreg_String valuename;
+
+       ZERO_STRUCT(valuename);
 
-       if ( !NT_STATUS_IS_OK(status) ) {
-               d_fprintf(stderr, "Unable to determine subkeys (%s)\n", 
-                       nt_errstr(status));
+       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",
+                         nt_errstr(status));
                return status;
        }
 
-       /* values do not include the terminating NULL */
+       valuename.name = argv[1];
 
-       max_subkeylen += 2;
-       max_valnamelen += 2;
+       status = rpccli_winreg_DeleteValue(pipe_hnd, mem_ctx, &key_hnd,
+                                          valuename, NULL);
 
-       if ( (name_buffer = TALLOC_ARRAY( mem_ctx, char, max_subkeylen )) == NULL ) {
-               d_fprintf(stderr, "Memory allocation error.\n");
-               return NT_STATUS_NO_MEMORY;
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "registry_deletevalue failed: %s\n",
+                         nt_errstr(status));
        }
 
-       /* get the subkeys */
-       
-       status = NT_STATUS_OK;
-       idx = 0;
-       while ( NT_STATUS_IS_OK(status) ) {
-               struct winreg_StringBuf class_namebuf;
-               fstring kname;
-               NTTIME modtime;
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
 
-               class_namebuf.name = NULL;
-               class_namebuf.size = 0;
-               class_namebuf.length = 0;
+       return status;
+}
 
-               /* zero out each time */
+static int rpc_registry_deletevalue( int argc, const char **argv )
+{
+       if (argc != 2) {
+               d_fprintf(stderr, "usage: net rpc registry deletevalue <key> "
+                         "<valuename>\n");
+               return -1;
+       }
 
-               subkey_namebuf.length = 0;
-               subkey_namebuf.size = max_subkeylen;
-               memset( name_buffer, 0x0, max_subkeylen );
-               subkey_namebuf.name = name_buffer;
+       return run_rpc_command( NULL, PI_WINREG, 0, 
+               rpc_registry_deletevalue_internal, argc, argv );
+}
 
-               status = rpccli_winreg_EnumKey(pipe_hnd, mem_ctx, &pol_key, idx, 
-                       &subkey_namebuf, &class_namebuf, &modtime);
-                       
-               if ( W_ERROR_EQUAL(ntstatus_to_werror(status), WERR_NO_MORE_ITEMS) ) {
-                       status = NT_STATUS_OK;
-                       break;
-               }
+static NTSTATUS rpc_registry_createkey_internal(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 )
+{
+       uint32 hive;
+       struct policy_handle hive_hnd, key_hnd;
+       struct winreg_String key, keyclass;
+       enum winreg_CreateAction action;
+       NTSTATUS status;
 
-               if ( !NT_STATUS_IS_OK(status) )
-                       goto out;
-               
-               StrnCpy( kname, subkey_namebuf.name, MIN(subkey_namebuf.length,sizeof(kname))-1 );
-               kname[MIN(subkey_namebuf.length,sizeof(kname))-1] = '\0';
-               d_printf("Keyname   = %s\n", kname);
-               d_printf("Modtime   = %s\n", 
-                       http_timestring(nt_time_to_unix(modtime)) );
-               d_printf("\n" );
+       ZERO_STRUCT(key);
+       ZERO_STRUCT(keyclass);
 
-               idx++;
+       if (!reg_hive_key(mem_ctx, argv[0], &hive, &key.name)) {
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if ( !NT_STATUS_IS_OK(status) )
-               goto out;
+       status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive,
+                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
+                                      &hive_hnd);
+       if (!(NT_STATUS_IS_OK(status))) {
+               return status;
+       }
 
-       /* TALLOC_FREE( name_buffer ); */
+       action = REG_ACTION_NONE;
+       keyclass.name = "";
 
-       if ( (name_buffer = TALLOC_ARRAY( mem_ctx, char, max_valnamelen )) == NULL ) {
-               d_fprintf(stderr, "Memory allocation error.\n");
-               return NT_STATUS_NO_MEMORY;
+       status = rpccli_winreg_CreateKey(pipe_hnd, mem_ctx, &hive_hnd, key,
+                                        keyclass, 0, REG_KEY_READ, NULL,
+                                        &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, NULL);
+               return status;
        }
 
-       if ( (value_buffer = TALLOC_ARRAY( mem_ctx, uint8, max_valbufsize )) == NULL ) {
-               d_fprintf(stderr, "Memory allocation error.\n");
-               return NT_STATUS_NO_MEMORY;
+       switch (action) {
+               case REG_ACTION_NONE:
+                       d_printf("createkey did nothing -- huh?\n");
+                       break;
+               case REG_CREATED_NEW_KEY:
+                       d_printf("createkey created %s\n", argv[0]);
+                       break;
+               case REG_OPENED_EXISTING_KEY:
+                       d_printf("createkey opened existing %s\n", argv[0]);
+                       break;
        }
 
-       /* get the values */
-       
-       status = NT_STATUS_OK;
-       idx = 0;
-       while ( NT_STATUS_IS_OK(status) ) {
-               enum winreg_Type type;
-               fstring name;
-               uint8 *data;
-               uint32 data_size, value_length;
-               struct winreg_StringBuf value_namebuf;
-               REGVAL_BUFFER value;
-               
-               fstrcpy( name, "" );
-               ZERO_STRUCT( value );
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &key_hnd, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
 
-               memset( name_buffer, 0x0, max_valnamelen );
-               value_namebuf.name = name_buffer;
-               value_namebuf.length = 0;
-               value_namebuf.size = max_valnamelen;
+       return status;
+}
 
-               memset( value_buffer, 0x0, max_valbufsize );
-               data = value_buffer;
-               data_size = max_valbufsize;
-               value_length = 0;
+static int rpc_registry_createkey( int argc, const char **argv )
+{
+       if (argc != 1) {
+               d_fprintf(stderr, "usage: net rpc registry createkey <key>\n");
+               return -1;
+       }
 
-               status = rpccli_winreg_EnumValue(pipe_hnd, mem_ctx, &pol_key, idx, 
-                       &value_namebuf, &type, data, &data_size, &value_length );
-                       
-               if ( W_ERROR_EQUAL(ntstatus_to_werror(status), WERR_NO_MORE_ITEMS) ) {
-                       status = NT_STATUS_OK;
-                       break;
-               }
+       return run_rpc_command( NULL, PI_WINREG, 0, 
+               rpc_registry_createkey_internal, argc, argv );
+}
 
-               if ( !NT_STATUS_IS_OK(status) )
-                       goto out;
+static NTSTATUS rpc_registry_deletekey_internal(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 )
+{
+       uint32 hive;
+       struct policy_handle hive_hnd;
+       struct winreg_String key;
+       NTSTATUS status;
 
-               init_regval_buffer( &value, data, value_length );
-                       
-               StrnCpy( name, value_namebuf.name, MIN(max_valnamelen, sizeof(name)-1) );
-               name[MIN(max_valnamelen, sizeof(name)-1)] = '\0';
+       ZERO_STRUCT(key);
 
-               d_printf("Valuename  = %s\n", name );
-               d_printf("Type       = %s\n", reg_type_lookup(type));
-               d_printf("Data       = " );
-               dump_regval_buffer( type, &value );
-               d_printf("\n" );
+       if (!reg_hive_key(mem_ctx, argv[0], &hive, &key.name)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
-               idx++;
+       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, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &hive_hnd, NULL);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "deletekey returned %s\n",
+                         nt_errstr(status));
+       }
+
+       return status;
+}
+
+static int rpc_registry_deletekey( int argc, const char **argv )
+{
+       if (argc != 1) {
+               d_fprintf(stderr, "usage: net rpc registry deletekey <key>\n");
+               return -1;
+       }
+
+       return run_rpc_command( 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, 
+                                               struct cli_state *cli,
+                                               struct rpc_pipe_client *pipe_hnd,
+                                               TALLOC_CTX *mem_ctx, 
+                                               int argc,
+                                               const char **argv )
+{
+       POLICY_HND pol_hive, pol_key; 
+       NTSTATUS status;
+       uint32 num_subkeys = 0;
+       uint32 num_values = 0;
+       char **names = NULL, **classes = NULL;
+       NTTIME **modtimes = NULL;
+       uint32 i;
+       struct registry_value **values = NULL;
        
-out:
-       /* cleanup */
-       
-       if ( strlen( subpath ) != 0 )
-               rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key );
-       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive );
+       if (argc != 1 ) {
+               d_printf("Usage:    net rpc registry enumerate <path> [recurse]\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,
+                                 &pol_hive, &pol_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "registry_openkey failed: %s\n",
+                         nt_errstr(status));
+               return status;
+       }
+
+       status = registry_enumkeys(mem_ctx, pipe_hnd, &pol_key, &num_subkeys,
+                                  &names, &classes, &modtimes);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "enumerating keys failed: %s\n",
+                         nt_errstr(status));
+               return status;
+       }
+
+       for (i=0; i<num_subkeys; i++) {
+               print_registry_key(names[i], modtimes[i]);
+       }
+
+       status = registry_enumvalues(mem_ctx, pipe_hnd, &pol_key, &num_values,
+                                    &names, &values);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "enumerating values failed: %s\n",
+                         nt_errstr(status));
+               return status;
+       }
+
+       for (i=0; i<num_values; i++) {
+               print_registry_value(names[i], values[i]);
+       }
+
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key, NULL);
+       rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive, NULL);
 
        return status;
 }
@@ -285,49 +691,33 @@ static NTSTATUS rpc_registry_save_internal(const DOM_SID *domain_sid,
                                        const char **argv )
 {
        WERROR result = WERR_GENERAL_FAILURE;
-       uint32 hive;
-       pstring subpath;
        POLICY_HND pol_hive, pol_key; 
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       struct winreg_String subkeyname;
        struct winreg_String filename;
        
        if (argc != 2 ) {
-               d_printf("Usage:    net rpc backup <path> <file> \n");
-               return NT_STATUS_OK;
-       }
-       
-       if ( !reg_split_hive( argv[0], &hive, subpath ) ) {
-               d_fprintf(stderr, "invalid registry path\n");
-               return NT_STATUS_OK;
+               d_printf("Usage:    net rpc registry backup <path> <file> \n");
+               return NT_STATUS_INVALID_PARAMETER;
        }
        
-       /* open the top level hive and then the registry key */
-       
-       status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive, MAXIMUM_ALLOWED_ACCESS, &pol_hive );
-       if ( !NT_STATUS_IS_OK(status) ) {
-               d_fprintf(stderr, "Unable to connect to remote registry\n");
+       status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_ALL,
+                                 &pol_hive, &pol_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "registry_openkey failed: %s\n",
+                         nt_errstr(status));
                return status;
        }
-       
-       subkeyname.name = subpath;
-       status = rpccli_winreg_OpenKey(pipe_hnd, mem_ctx, &pol_hive, subkeyname,
-                       0, MAXIMUM_ALLOWED_ACCESS, &pol_key );
-       if ( !NT_STATUS_IS_OK(status) ) {
-               d_fprintf(stderr, "Unable to open [%s]\n", argv[0]);
-               return werror_to_ntstatus(result);
-       }
-       
+
        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;
 }
@@ -348,7 +738,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 )
@@ -361,7 +751,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:
@@ -392,19 +789,22 @@ 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;
@@ -413,15 +813,15 @@ static BOOL dump_registry_tree( REGF_FILE *file, REGF_NK_REC *nk, const char *pa
 /********************************************************************
 ********************************************************************/
 
-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"));
@@ -430,36 +830,45 @@ static BOOL write_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk,
 
        if ( !(values = TALLOC_ZERO_P( subkeys, REGVAL_CTR )) ) {
                DEBUG(0,("write_registry_tree: talloc() failed!\n"));
+               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 );
-       
+       TALLOC_FREE(subkeys);
+
        return True;
 }
 
@@ -472,8 +881,8 @@ static int rpc_registry_dump( int argc, const char **argv )
        REGF_NK_REC *nk;
        
        if (argc != 1 ) {
-               d_printf("Usage:    net rpc dump <file> \n");
-               return 0;
+               d_printf("Usage:    net rpc registry dump <file> \n");
+               return -1;
        }
        
        d_printf("Opening %s....", argv[0]);
@@ -516,8 +925,8 @@ static int rpc_registry_copy( int argc, const char **argv )
        int result = 1;
        
        if (argc != 2 ) {
-               d_printf("Usage:    net rpc copy <srcfile> <newfile>\n");
-               return 0;
+               d_printf("Usage:    net rpc registry copy <srcfile> <newfile>\n");
+               return -1;
        }
        
        d_printf("Opening %s....", argv[0]);
@@ -566,13 +975,86 @@ out:
 /********************************************************************
 ********************************************************************/
 
-static int net_help_registry( int argc, const char **argv )
+static NTSTATUS rpc_registry_getsd_internal(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)
 {
-       d_printf("net rpc registry enumerate <path> [recurse]  Enumerate the subkeya and values for a given registry path\n");
-       d_printf("net rpc registry save <path> <file>          Backup a registry tree to a file on the server\n");
-       d_printf("net rpc registry dump <file>                 Dump the contents of a registry file to stdout\n");
-       
-       return -1;
+       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) {
+               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(int argc, const char **argv)
+{
+       return run_rpc_command(NULL, PI_WINREG, 0,
+               rpc_registry_getsd_internal, argc, argv);
 }
 
 /********************************************************************
@@ -580,16 +1062,27 @@ static int net_help_registry( int argc, const char **argv )
 
 int net_rpc_registry(int argc, const char **argv) 
 {
-       struct functable func[] = {
-               {"enumerate", rpc_registry_enumerate},
-               {"save",      rpc_registry_save},
-               {"dump",      rpc_registry_dump},
-               {"copy",      rpc_registry_copy},
-               {NULL, NULL}
+       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" },
+               { "getsd", rpc_registry_getsd,
+                 "Get security descriptor" },
+               {NULL, NULL, NULL}
        };
        
-       if ( argc )
-               return net_run_function( argc, argv, func, net_help_registry );
-               
-       return net_help_registry( argc, argv );
+       return net_run_function2(argc, argv, "net rpc registry", func);
 }