Merge branch 'master' of ssh://git.samba.org/data/git/samba into regsrv
authorJelmer Vernooij <jelmer@samba.org>
Tue, 21 Oct 2008 12:51:13 +0000 (14:51 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Tue, 21 Oct 2008 12:51:13 +0000 (14:51 +0200)
Conflicts:
source4/lib/registry/ldb.c
source4/rpc_server/winreg/rpc_winreg.c

1  2 
source4/lib/registry/ldb.c
source4/rpc_server/winreg/rpc_winreg.c

index 87d066e2def006454833a7a85fc55b9da375af45,25b8c583ed2f4c27650e36fc65f56092e2439472..9c1f59c4df6f75e28b6a39de651c33c4ca5fcbc2
@@@ -1,8 -1,7 +1,8 @@@
  /*
     Unix SMB/CIFS implementation.
     Registry interface
 -   Copyright (C) Jelmer Vernooij  2004-2007.
 +   Copyright (C) 2004-2007, Jelmer Vernooij, jelmer@samba.org
 +   Copyright (C) 2008 Matthias Dieter Wallnöfer, mwallnoefer@yahoo.de
  
     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
@@@ -52,31 -51,17 +52,31 @@@ static void reg_ldb_unpack_value(TALLOC
                                      NULL));
  
        value_type = ldb_msg_find_attr_as_uint(msg, "type", 0);
 -      if (type != NULL)
 -              *type = value_type; 
 +      *type = value_type; 
 +
        val = ldb_msg_find_ldb_val(msg, "data");
  
        switch (value_type)
        {
        case REG_SZ:
        case REG_EXPAND_SZ:
 -              data->length = convert_string_talloc(mem_ctx, iconv_convenience, CH_UTF8, CH_UTF16,
 +              if (val != NULL)
 +                      data->length = convert_string_talloc(mem_ctx, iconv_convenience, CH_UTF8, CH_UTF16,
                                                     val->data, val->length,
                                                     (void **)&data->data);
 +              else {
 +                      data->data = NULL;
 +                      data->length = 0;
 +              }
 +              break;
 +
 +      case REG_BINARY:
 +              if (val != NULL)
 +                      *data = *val;
 +              else {
 +                      data->data = NULL;
 +                      data->length = 0;
 +              }
                break;
  
        case REG_DWORD: {
@@@ -86,7 -71,7 +86,7 @@@
                break;
  
        default:
 -              *data = data_blob_talloc(mem_ctx, val->data, val->length);
 +              *data = *val;
                break;
        }
  }
@@@ -105,22 -90,11 +105,22 @@@ static struct ldb_message *reg_ldb_pack
        switch (type) {
        case REG_SZ:
        case REG_EXPAND_SZ:
 -              val.length = convert_string_talloc(mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX,
 +              if (data.data[0] != '\0') {
 +                      val.length = convert_string_talloc(mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UTF8,
                                                   (void *)data.data,
                                                   data.length,
                                                   (void **)&val.data);
 -              ldb_msg_add_value(msg, "data", &val, NULL);
 +                      ldb_msg_add_value(msg, "data", &val, NULL);
 +              } else {
 +                      ldb_msg_add_empty(msg, "data", LDB_FLAG_MOD_DELETE, NULL);
 +              }
 +              break;
 +
 +      case REG_BINARY:
 +              if (data.length > 0)
 +                      ldb_msg_add_value(msg, "data", &data, NULL);
 +              else
 +                      ldb_msg_add_empty(msg, "data", LDB_FLAG_MOD_DELETE, NULL);
                break;
  
        case REG_DWORD:
@@@ -225,7 -199,7 +225,7 @@@ static WERROR cache_subkeys(struct ldb_
        struct ldb_result *res;
        int ret;
  
-       ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, "(key=*)", NULL, &res);
+       ret = ldb_search(c, c, &res, kd->dn, LDB_SCOPE_ONELEVEL, NULL, "(key=*)");
  
        if (ret != LDB_SUCCESS) {
                DEBUG(0, ("Error getting subkeys for '%s': %s\n",
@@@ -246,19 -220,17 +246,19 @@@ static WERROR cache_values(struct ldb_k
        struct ldb_result *res;
        int ret;
  
-       ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL,
-                        "(value=*)", NULL, &res);
+       ret = ldb_search(c, c, &res, kd->dn, LDB_SCOPE_ONELEVEL,
+                        NULL, "(value=*)");
  
        if (ret != LDB_SUCCESS) {
                DEBUG(0, ("Error getting values for '%s': %s\n",
                        ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
                return WERR_FOOBAR;
        }
 +
        kd->value_count = res->count;
        kd->values = talloc_steal(kd, res->msgs);
        talloc_free(res);
 +
        return WERR_OK;
  }
  
@@@ -271,15 -243,6 +271,15 @@@ static WERROR ldb_get_subkey_by_id(TALL
  {
        struct ldb_message_element *el;
        struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data);
 +      
 +      /* Initialization */
 +      if (name != NULL)
 +              *name = NULL;
 +      if (classname != NULL)
 +              *classname = NULL; /* TODO: Store properly */
 +      if (last_mod_time != NULL)
 +              *last_mod_time = 0; /* TODO: we need to add this to the
 +                                              ldb backend properly */
  
        /* Do a search if necessary */
        if (kd->subkeys == NULL) {
        if (name != NULL)
                *name = talloc_strdup(mem_ctx, (char *)el->values[0].data);
  
 -      if (classname != NULL)
 -              *classname = NULL; /* TODO: Store properly */
 +      return WERR_OK;
 +}
  
 -      if (last_mod_time != NULL)
 -              *last_mod_time = 0; /* TODO: we need to add this to the
 -                                              ldb backend properly */
 +static WERROR ldb_get_default_value(TALLOC_CTX *mem_ctx, struct hive_key *k,
 +                                const char **name, uint32_t *data_type,
 +                                 DATA_BLOB *data)
 +{
 +      struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data);
 +      struct ldb_context *c = kd->ldb;
 +      const char* attrs[] = { "data", "type", NULL };
 +      struct ldb_result *res;
 +      int ret;
 +
 +      ret = ldb_search(c, kd->dn, LDB_SCOPE_BASE, "", attrs, &res);
 +
 +      if (ret != LDB_SUCCESS) {
 +              DEBUG(0, ("Error getting default value for '%s': %s\n",
 +                      ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
 +              return WERR_FOOBAR;
 +      }
 +
 +      if (res->count == 0 || res->msgs[0]->num_elements == 0)
 +              return WERR_BADFILE;
 +
 +      reg_ldb_unpack_value(mem_ctx, lp_iconv_convenience(global_loadparm),
 +               res->msgs[0], name, data_type, data);
 +
 +      talloc_free(res);
  
        return WERR_OK;
  }
@@@ -334,15 -275,6 +334,15 @@@ static WERROR ldb_get_value_by_id(TALLO
  {
        struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data);
  
 +      /* if default value exists, give it back */
 +      if (W_ERROR_IS_OK(ldb_get_default_value(mem_ctx, k, name, data_type,
 +              data))) {
 +              if (idx == 0)
 +                      return WERR_OK;
 +              else
 +                      --idx;
 +      }
 +
        /* Do the search if necessary */
        if (kd->values == NULL) {
                W_ERROR_NOT_OK_RETURN(cache_values(kd));
        if (idx >= kd->value_count)
                return WERR_NO_MORE_ITEMS;
  
 -      reg_ldb_unpack_value(mem_ctx, lp_iconv_convenience(global_loadparm), kd->values[idx],
 -                           name, data_type, data);
 +      reg_ldb_unpack_value(mem_ctx, lp_iconv_convenience(global_loadparm),
 +                       kd->values[idx], name, data_type, data);
  
        return WERR_OK;
  }
@@@ -365,32 -297,27 +365,33 @@@ static WERROR ldb_get_value(TALLOC_CTX 
        struct ldb_context *c = kd->ldb;
        struct ldb_result *res;
        int ret;
 -      char *query = talloc_asprintf(mem_ctx, "(value=%s)", name);
 +      char *query;
  
 -      ret = ldb_search(c, mem_ctx, &res, kd->dn, LDB_SCOPE_ONELEVEL, NULL, "%s", query);
 +      if (strlen(name) == 0) {
 +              /* default value */
 +              return ldb_get_default_value(mem_ctx, k, NULL, data_type, data);
 +      } else {
 +              /* normal value */
 +              query = talloc_asprintf(mem_ctx, "(value=%s)", name);
-               ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, query, NULL, &res);
++              ret = ldb_search(c, kd->dn, &res, LDB_SCOPE_ONELEVEL, query, NULL, "%s", query);
 +              talloc_free(query);
 +
 +              if (ret != LDB_SUCCESS) {
 +                      DEBUG(0, ("Error getting values for '%s': %s\n",
 +                              ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
 +                      return WERR_FOOBAR;
 +              }
  
 -      talloc_free(query);
 +              if (res->count == 0)
 +                      return WERR_BADFILE;
  
 -      if (ret != LDB_SUCCESS) {
 -              DEBUG(0, ("Error getting values for '%s': %s\n",
 -                      ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
 -              talloc_free(res);
 -              return WERR_FOOBAR;
 -      }
 +              reg_ldb_unpack_value(mem_ctx, lp_iconv_convenience(global_loadparm),
 +                       res->msgs[0], NULL, data_type, data);
  
 -      if (res->count == 0) {
                talloc_free(res);
 -              return WERR_BADFILE;
        }
  
 -      reg_ldb_unpack_value(mem_ctx, lp_iconv_convenience(global_loadparm), res->msgs[0], NULL, data_type, data);
 -
+       talloc_free(res);
        return WERR_OK;
  }
  
@@@ -406,7 -333,7 +407,7 @@@ static WERROR ldb_open_key(TALLOC_CTX *
  
        ldap_path = reg_path_to_ldb(mem_ctx, h, name, NULL);
  
-       ret = ldb_search(c, ldap_path, LDB_SCOPE_BASE, "(key=*)", NULL, &res);
+       ret = ldb_search(c, mem_ctx, &res, ldap_path, LDB_SCOPE_BASE, NULL, "(key=*)");
  
        if (ret != LDB_SUCCESS) {
                DEBUG(3, ("Error opening key '%s': %s\n",
  
        *key = (struct hive_key *)newkd;
  
 -      talloc_free(res);
 -
        return WERR_OK;
  }
  
@@@ -522,47 -451,25 +523,47 @@@ static WERROR ldb_del_value (struct hiv
  {
        int ret;
        struct ldb_key_data *kd = talloc_get_type(key, struct ldb_key_data);
 +      TALLOC_CTX *mem_ctx;
 +      struct ldb_message *msg;
        struct ldb_dn *childdn;
  
 -      childdn = ldb_dn_copy(kd->ldb, kd->dn);
 -      if (!ldb_dn_add_child_fmt(childdn, "value=%s",
 +      if (strlen(child) == 0) {
 +              /* default value */
 +              mem_ctx = talloc_init("ldb_del_value");
 +
 +              msg = talloc_zero(mem_ctx, struct ldb_message);
 +              msg->dn = ldb_dn_copy(msg, kd->dn);
 +              ldb_msg_add_empty(msg, "data", LDB_FLAG_MOD_DELETE, NULL);
 +              ldb_msg_add_empty(msg, "type", LDB_FLAG_MOD_DELETE, NULL);
 +
 +              ret = ldb_modify(kd->ldb, msg);
 +              if (ret != LDB_SUCCESS) {
 +                      DEBUG(1, ("ldb_del_value: %s\n", ldb_errstring(kd->ldb)));
 +                      talloc_free(mem_ctx);
 +                      return WERR_FOOBAR;
 +              }
 +
 +              talloc_free(mem_ctx);
 +      } else {
 +              /* normal value */
 +              childdn = ldb_dn_copy(kd->ldb, kd->dn);
 +              if (!ldb_dn_add_child_fmt(childdn, "value=%s",
                                  reg_ldb_escape(childdn, child)))
 -      {
 -              talloc_free(childdn);
 -              return WERR_FOOBAR;
 -      }
 +              {
 +                      talloc_free(childdn);
 +                      return WERR_FOOBAR;
 +              }
  
 -      ret = ldb_delete(kd->ldb, childdn);
 +              ret = ldb_delete(kd->ldb, childdn);
  
 -      talloc_free(childdn);
 +              talloc_free(childdn);
  
 -      if (ret == LDB_ERR_NO_SUCH_OBJECT) {
 -              return WERR_BADFILE;
 -      } else if (ret != LDB_SUCCESS) {
 -              DEBUG(1, ("ldb_del_value: %s\n", ldb_errstring(kd->ldb)));
 -              return WERR_FOOBAR;
 +              if (ret == LDB_ERR_NO_SUCH_OBJECT) {
 +                      return WERR_BADFILE;
 +              } else if (ret != LDB_SUCCESS) {
 +                      DEBUG(1, ("ldb_del_value: %s\n", ldb_errstring(kd->ldb)));
 +                      return WERR_FOOBAR;
 +              }
        }
  
        /* reset cache */
@@@ -598,8 -505,8 +599,8 @@@ static WERROR ldb_del_key(const struct 
        }
  
        /* Search for subkeys */
-       ret = ldb_search(c, ldap_path, LDB_SCOPE_ONELEVEL,
-                        "(key=*)", NULL, &res_keys);
+       ret = ldb_search(c, mem_ctx, &res_keys, ldap_path, LDB_SCOPE_ONELEVEL,
+                        NULL, "(key=*)");
  
        if (ret != LDB_SUCCESS) {
                DEBUG(0, ("Error getting subkeys for '%s': %s\n",
        }
  
        /* Search for values */
-       ret = ldb_search(c, ldap_path, LDB_SCOPE_ONELEVEL,
-                        "(value=*)", NULL, &res_vals);
+       ret = ldb_search(c, mem_ctx, &res_vals, ldap_path, LDB_SCOPE_ONELEVEL,
+                        NULL, "(value=*)");
  
        if (ret != LDB_SUCCESS) {
                DEBUG(0, ("Error getting values for '%s': %s\n",
@@@ -698,31 -605,26 +699,31 @@@ static WERROR ldb_set_value(struct hive
        TALLOC_CTX *mem_ctx = talloc_init("ldb_set_value");
  
        msg = reg_ldb_pack_value(kd->ldb, mem_ctx, name, type, data);
 -
        msg->dn = ldb_dn_copy(msg, kd->dn);
 -      if (!ldb_dn_add_child_fmt(msg->dn, "value=%s",
 +      
 +      if (strlen(name) > 0) {
 +              /* For a default value, we add/overwrite the attributes to/of the hive.
 +                 For a normal value, we create new childs. */
 +              if (!ldb_dn_add_child_fmt(msg->dn, "value=%s",
                                  reg_ldb_escape(mem_ctx, name)))
 -      {
 -              talloc_free(mem_ctx);
 -              return WERR_FOOBAR;
 +              {
 +                      talloc_free(mem_ctx);
 +                      return WERR_FOOBAR;
 +              }
        }
  
        ret = ldb_add(kd->ldb, msg);
        if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
                int i;
                for (i = 0; i < msg->num_elements; i++) {
 -                      msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
 +                      if (msg->elements[i].flags != LDB_FLAG_MOD_DELETE)
 +                              msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
                }
                ret = ldb_modify(kd->ldb, msg);
        }
  
        if (ret != LDB_SUCCESS) {
 -              DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(kd->ldb)));
 +              DEBUG(1, ("ldb_set_value: %s\n", ldb_errstring(kd->ldb)));
                talloc_free(mem_ctx);
                return WERR_FOOBAR;
        }
@@@ -747,22 -649,6 +748,22 @@@ static WERROR ldb_get_key_info(TALLOC_C
  {
        struct ldb_key_data *kd = talloc_get_type(key, struct ldb_key_data);
  
 +      /* Initialization */
 +      if (classname != NULL)
 +              *classname = NULL;
 +      if (num_subkeys != NULL)
 +              *num_subkeys = 0;
 +      if (num_values != NULL)
 +              *num_values = 0;
 +      if (last_change_time != NULL)
 +              *last_change_time = 0;
 +      if (max_subkeynamelen != NULL)
 +              *max_subkeynamelen = 0;
 +      if (max_valnamelen != NULL)
 +              *max_valnamelen = 0;
 +      if (max_valbufsize != NULL)
 +              *max_valbufsize = 0;
 +
        if (kd->subkeys == NULL) {
                W_ERROR_NOT_OK_RETURN(cache_subkeys(kd));
        }
                W_ERROR_NOT_OK_RETURN(cache_values(kd));
        }
  
 -      /* FIXME */
 -      if (classname != NULL)
 -              *classname = NULL;
 -
        if (num_subkeys != NULL) {
                *num_subkeys = kd->subkey_count;
        }
 -
        if (num_values != NULL) {
                *num_values = kd->value_count;
        }
  
 -      if (last_change_time != NULL)
 -              *last_change_time = 0;
  
        if (max_subkeynamelen != NULL) {
                int i;
                        }
  
                        if (max_valbufsize != NULL) {
 +                              uint32_t data_type;
                                DATA_BLOB data;
                                reg_ldb_unpack_value(mem_ctx, 
                                                     lp_iconv_convenience(global_loadparm),
                                                     kd->values[i], NULL, 
 -                                                   NULL, &data);
 +                                                   &data_type, &data);
                                *max_valbufsize = MAX(*max_valbufsize, data.length);
                                talloc_free(data.data);
                        }
index 430982b9f8ce84a1442f6427302d3d60d886559d,e295634c6222587904c1a1e1e12f7efe69f3efef..db11958026a67d1b6e4621eb175533d70f407112
@@@ -3,8 -3,7 +3,8 @@@
  
     endpoint server for the winreg pipe
  
 -   Copyright (C) Jelmer Vernooij 2004
 +   Copyright (C) 2004 Jelmer Vernooij, jelmer@samba.org
 +   Copyright (C) 2008 Matthias Dieter Wallnöfer, mwallnoefer@yahoo.de
  
     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
@@@ -59,18 -58,19 +59,18 @@@ static WERROR dcesrv_winreg_openhive(st
  {
        struct registry_context *ctx = dce_call->context->private;
        struct dcesrv_handle *h;
 -      WERROR error;
 +      WERROR result;
  
        h = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);
  
 -      error = reg_get_predefined_key(ctx, hkey,
 +      result = reg_get_predefined_key(ctx, hkey,
                                       (struct registry_key **)&h->data);
 -      if (!W_ERROR_IS_OK(error)) {
 -              return error;
 +      if (!W_ERROR_IS_OK(result)) {
 +              return result;
        }
 -
        *outh = &h->wire_handle;
  
 -      return error;
 +      return result;
  }
  
  #define func_winreg_OpenHive(k,n) static WERROR dcesrv_winreg_Open ## k (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_Open ## k *r) \
@@@ -114,12 -114,10 +114,12 @@@ static WERROR dcesrv_winreg_CreateKey(s
                                      struct winreg_CreateKey *r)
  {
        struct dcesrv_handle *h, *newh;
 -      WERROR error;
        struct security_descriptor sd;
 +      struct registry_key *key;
 +      WERROR result;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 +      key = h->data;
  
        newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);
  
                        }
                }
                
 -              error = reg_key_add_name(newh, (struct registry_key *)h->data,
 -                                       r->in.name.name, NULL, r->in.secdesc?&sd:NULL,
 -                                       (struct registry_key **)&newh->data);
 -              if (W_ERROR_IS_OK(error)) {
 +              result = reg_key_add_name(newh, key, r->in.name.name, NULL,
 +                      r->in.secdesc?&sd:NULL, (struct registry_key **)&newh->data);
 +              if (W_ERROR_IS_OK(result)) {
                        r->out.new_handle = &newh->wire_handle;
                } else {
                        talloc_free(newh);
                }
                
 -              return error;
 +              return result;
        default:
                return WERR_ACCESS_DENIED;
        }
@@@ -166,16 -165,14 +166,16 @@@ static WERROR dcesrv_winreg_DeleteKey(s
                                      struct winreg_DeleteKey *r)
  {
        struct dcesrv_handle *h;
 +      struct registry_key *key;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 +      key = h->data;
  
        switch (security_session_user_level(dce_call->conn->auth_state.session_info))
        {
        case SECURITY_SYSTEM:
        case SECURITY_ADMINISTRATOR:
 -              return reg_key_del((struct registry_key *)h->data, r->in.key.name);
 +              return reg_key_del(key, r->in.key.name);
        default:
                return WERR_ACCESS_DENIED;
        }
@@@ -193,12 -190,13 +193,12 @@@ static WERROR dcesrv_winreg_DeleteValue
        struct registry_key *key;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 +      key = h->data;
  
        switch (security_session_user_level(dce_call->conn->auth_state.session_info))
        {
        case SECURITY_SYSTEM:
        case SECURITY_ADMINISTRATOR:
 -              key = h->data;
 -              
                return reg_del_value(key, r->in.value.name);
        default:
                return WERR_ACCESS_DENIED;
@@@ -214,44 -212,29 +214,44 @@@ static WERROR dcesrv_winreg_EnumKey(str
                                    struct winreg_EnumKey *r)
  {
        struct dcesrv_handle *h;
 -      const char *name;
 +      struct registry_key *key;
 +      const char *name, *classname;
        NTTIME last_mod;
 +      WERROR result;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 +      key = h->data;
  
 -      r->out.result = reg_key_get_subkey_by_index(mem_ctx,
 -                                                  (struct registry_key *)h->data,
 -                                                  r->in.enum_index,
 -                                                  &name, NULL, &last_mod);
 +      result = reg_key_get_subkey_by_index(mem_ctx, 
 +              key, r->in.enum_index, &name, &classname, &last_mod);
  
 -      if (W_ERROR_IS_OK(r->out.result)) {
 -              if (2*strlen_m_term(name) > r->in.name->size) {
 -                      return WERR_MORE_DATA;
 -              }
 -              r->out.name->length = 2*strlen_m_term(name);
 +      if (2*strlen_m_term(name) > r->in.name->size) {
 +              return WERR_MORE_DATA;
 +      }
 +
 +      if (name != NULL) {
                r->out.name->name = name;
 -              r->out.keyclass = talloc_zero(mem_ctx, struct winreg_StringBuf);
 -              if (r->in.last_changed_time) {
 -                      r->out.last_changed_time = &last_mod;
 -              }
 +              r->out.name->length = 2*strlen_m_term(name);
 +      } else {
 +              r->out.name->name = r->in.name->name;
 +              r->out.name->length = r->in.name->length;
        }
 +      r->out.name->size = r->in.name->size;
  
 -      return r->out.result;
 +      r->out.keyclass = r->in.keyclass;
 +      if (classname != NULL) {
 +              r->out.keyclass->name = classname;
 +              r->out.keyclass->length = 2*strlen_m_term(classname);
 +      } else {
 +              r->out.keyclass->name = r->in.keyclass->name;
 +              r->out.keyclass->length = r->in.keyclass->length;
 +      }
 +      r->out.keyclass->size = r->in.keyclass->size;
 +
 +      if (r->in.last_changed_time != NULL)
 +              r->out.last_changed_time = &last_mod;
 +
 +      return result;
  }
  
  
@@@ -264,45 -247,28 +264,45 @@@ static WERROR dcesrv_winreg_EnumValue(s
  {
        struct dcesrv_handle *h;
        struct registry_key *key;
 -      WERROR result;
        const char *data_name;
        uint32_t data_type;
        DATA_BLOB data;
 +      WERROR result;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 -
        key = h->data;
  
 -      result = reg_key_get_value_by_index(mem_ctx, key, r->in.enum_index,
 -                                          &data_name,
 -                                          &data_type, &data);
 +      result = reg_key_get_value_by_index(mem_ctx, key,
 +              r->in.enum_index, &data_name, &data_type, &data);
 +
        if (!W_ERROR_IS_OK(result)) {
 -              return result;
 +              /* if the lookup wasn't successful, send client query back */
 +              data_name = r->in.name->name;
 +              data_type = *r->in.type;
 +              data.data = r->in.value;
 +              data.length = *r->in.length;
        }
  
 -      /* the client can optionally pass a NULL for type, meaning they don't
 -         want that back */
 -      if (r->in.type != NULL) {
 -              r->out.type = talloc(mem_ctx, enum winreg_Type);
 -              *r->out.type = data_type;
 +      /* check if there is enough room for the name */
 +      if (r->in.name->size < 2*strlen_m_term(data_name)) {
 +              return WERR_MORE_DATA;
 +      }
 +
 +      /* "data_name" is NULL when we query the default attribute */
 +      if (data_name != NULL) {
 +              r->out.name->name = data_name;
 +              r->out.name->length = 2*strlen_m_term(data_name);
 +      } else {
 +              r->out.name->name = r->in.name->name;
 +              r->out.name->length = r->in.name->length;
        }
 +      r->out.name->size = r->in.name->size;
 +
 +      r->out.type = talloc(mem_ctx, uint32_t);
 +      if (!r->out.type) {
 +              return WERR_NOMEM;
 +      }
 +      *r->out.type = data_type;
  
        /* check the client has enough room for the value */
        if (r->in.value != NULL &&
                return WERR_MORE_DATA;
        }
  
 -      /* and enough room for the name */
 -      if (r->in.name->size < 2*strlen_m_term(data_name)) {
 -              return WERR_MORE_DATA;
 -      }
 -
 -      r->out.name->name = data_name;
 -      r->out.name->length = 2*strlen_m_term(data_name);
 -      r->out.name->size = r->in.name->size;
 -
 -      if (r->in.value) {
 +      if (r->in.value != NULL) {
                r->out.value = data.data;
        }
  
 -      if (r->in.size) {
 +      if (r->in.size != NULL) {
                r->out.size = talloc(mem_ctx, uint32_t);
                *r->out.size = data.length;
                r->out.length = r->out.size;
        }
  
 -      return WERR_OK;
 +      return result;
  }
  
  
@@@ -333,16 -308,14 +333,16 @@@ static WERROR dcesrv_winreg_FlushKey(st
                                     struct winreg_FlushKey *r)
  {
        struct dcesrv_handle *h;
 +      struct registry_key *key;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 +      key = h->data;
  
        switch (security_session_user_level(dce_call->conn->auth_state.session_info))
        {
        case SECURITY_SYSTEM:
        case SECURITY_ADMINISTRATOR:
 -              return reg_key_flush(h->data);
 +              return reg_key_flush(key);
        default:
                return WERR_ACCESS_DENIED;
        }
@@@ -394,11 -367,9 +394,11 @@@ static WERROR dcesrv_winreg_OpenKey(str
                                    struct winreg_OpenKey *r)
  {
        struct dcesrv_handle *h, *newh;
 +      struct registry_key *key;
        WERROR result;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.parent_handle, HTYPE_REGKEY);
 +      key = h->data;
  
        switch (security_session_user_level(dce_call->conn->auth_state.session_info))
        {
                        result = WERR_OK;
                } else {
                        newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);
 -                      result = reg_open_key(newh, (struct registry_key *)h->data,
 -                                            r->in.keyname.name,
 -                                            (struct registry_key **)&newh->data);
 +                      result = reg_open_key(newh, key, r->in.keyname.name,
 +                              (struct registry_key **)&newh->data);
                }
                
                if (W_ERROR_IS_OK(result)) {
@@@ -435,33 -407,28 +435,33 @@@ static WERROR dcesrv_winreg_QueryInfoKe
                                         struct winreg_QueryInfoKey *r)
  {
        struct dcesrv_handle *h;
 -      struct registry_key *k;
 -      WERROR ret;
 +      struct registry_key *key;
        const char *classname = NULL;
 +      WERROR result;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 +      key = h->data;
  
        switch (security_session_user_level(dce_call->conn->auth_state.session_info))
        {
        case SECURITY_SYSTEM:
        case SECURITY_ADMINISTRATOR:
        case SECURITY_USER:
 -              k = h->data;
 -              
 -              ret = reg_key_get_info(mem_ctx, k, &classname, r->out.num_subkeys,
 -                                     r->out.num_values, r->out.last_changed_time,
 -                                     r->out.max_subkeylen, r->out.max_valnamelen, 
 -                                     r->out.max_valbufsize);
 -              
 -              if (r->out.classname != NULL)
 +              result = reg_key_get_info(mem_ctx, key, &classname,
 +                      r->out.num_subkeys, r->out.num_values,
 +                      r->out.last_changed_time, r->out.max_subkeylen,
 +                      r->out.max_valnamelen, r->out.max_valbufsize);
 +
 +              if (classname != NULL) {
                        r->out.classname->name = classname;
 -              
 -              return ret;
 +                      r->out.classname->name_len = 2*strlen_m_term(classname);
 +              } else {
 +                      r->out.classname->name = r->in.classname->name;
 +                      r->out.classname->name_len = r->in.classname->name_len;
 +              }
 +              r->out.classname->name_size = r->in.classname->name_size;
 +
 +              return result;
        default:
                return WERR_ACCESS_DENIED;
        }
@@@ -482,42 -449,41 +482,41 @@@ static WERROR dcesrv_winreg_QueryValue(
        WERROR result;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 +      key = h->data;
  
        switch (security_session_user_level(dce_call->conn->auth_state.session_info))
        {
        case SECURITY_SYSTEM:
        case SECURITY_ADMINISTRATOR:
        case SECURITY_USER:
-               result = reg_key_get_value_by_name(mem_ctx, key,
-                        r->in.value_name.name, &value_type, &value_data);
 -              key = h->data;
 -              
 -              result = reg_key_get_value_by_name(mem_ctx, key, r->in.value_name->name,
 -                                                 &value_type, &value_data);
++              result = reg_key_get_value_by_name(mem_ctx, key, 
++                       r->in.value_name->name, &value_type, &value_data);
                
                if (!W_ERROR_IS_OK(result)) {
 -                      return result;
 +                      /* if the lookup wasn't successful, send client query back */
 +                      value_type = *r->in.type;
 +                      value_data.data = r->in.data;
 +                      value_data.length = *r->in.length;
                }
 -              
 -              /* Just asking for the size of the buffer */
 +
                r->out.type = talloc(mem_ctx, uint32_t);
                if (!r->out.type) {
                        return WERR_NOMEM;
                }
                *r->out.type = value_type;
-               r->out.length = talloc(mem_ctx, uint32_t);
-               if (!r->out.length) {
+               r->out.data_length = talloc(mem_ctx, uint32_t);
+               if (!r->out.data_length) {
                        return WERR_NOMEM;
                }
 -              *r->out.data_length = value_data.length;
 -              if (r->in.data == NULL) {
 -                      r->out.data_size = talloc(mem_ctx, uint32_t);
 -                      *r->out.data_size = value_data.length;
 -              } else {
 -                      r->out.data_size = r->in.data_size;
 -                      r->out.data = value_data.data;
 +              *r->out.length = value_data.length;
-               r->out.size = talloc(mem_ctx, uint32_t);
-               if (!r->out.size) {
++              r->out.data_size = talloc(mem_ctx, uint32_t);
++              if (!r->out.data_size) {
 +                      return WERR_NOMEM;
                }
-               *r->out.size = value_data.length;
 -              
 -              return WERR_OK;
++              *r->out.data_size = value_data.length;
 +              r->out.data = value_data.data;
 +
 +              return result;
        default:
                return WERR_ACCESS_DENIED;
        }
@@@ -577,10 -543,11 +576,10 @@@ static WERROR dcesrv_winreg_SetValue(st
  {
        struct dcesrv_handle *h;
        struct registry_key *key;
 -      WERROR result;
        DATA_BLOB data;
 +      WERROR result;
  
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 -
        key = h->data;
  
        switch (security_session_user_level(dce_call->conn->auth_state.session_info))