When Windows initially creates a new value, the value name is "New Value #1".
authorAndrew Kroeger <andrew@sprocks.gotdns.com>
Fri, 18 Jan 2008 00:50:33 +0000 (01:50 +0100)
committerJelmer Vernooij <jelmer@samba.org>
Fri, 18 Jan 2008 02:41:59 +0000 (03:41 +0100)
The '#' character was causing problems, as it was not being escaped for the dn,
but the failure returned by ldb_dn_add_child_fmt() was not being caught.  This
was causing the new value to be added on the parent key, not the current key.
When attempting to delete the new value (now on the parent key) the same
escaping error was returned by ldb_dn_add_child_fmt(), causing the delete to
delete the key and not the value.

When attempting to rename a value, Windows first tries to ensure the new name
does not already exist.  When a value does not exist, Windows expects a return
value of WERR_BADFILE, but WERR_NOT_FOUND was being returned instead.
Providing the WERR_BADFILE that Windows expects allows values to be renamed.

source/lib/registry/ldb.c
source/rpc_server/winreg/rpc_winreg.c

index d87bc6cf8e214c27121c89980b62ce995ecd9439..884aed15790c9a4ae2bab75c271e73486979ca5b 100644 (file)
@@ -112,6 +112,16 @@ static struct ldb_message *reg_ldb_pack_value(struct ldb_context *ctx,
 }
 
 
+static char *reg_ldb_escape(TALLOC_CTX *mem_ctx, const char *value)
+{
+       struct ldb_val val;
+
+       val.data = discard_const_p(uint8_t, value);
+       val.length = strlen(value);
+
+       return ldb_dn_escape_value(mem_ctx, val);
+}
+
 static int reg_close_ldb_key(struct ldb_key_data *key)
 {
        if (key->subkeys != NULL) {
@@ -447,7 +457,12 @@ static WERROR ldb_del_value (struct hive_key *key, const char *child)
        struct ldb_dn *childdn;
 
        childdn = ldb_dn_copy(kd->ldb, kd->dn);
-       ldb_dn_add_child_fmt(childdn, "value=%s", child);
+       if (!ldb_dn_add_child_fmt(childdn, "value=%s",
+                                 reg_ldb_escape(childdn, child)))
+       {
+               talloc_free(childdn);
+               return WERR_FOOBAR;
+       }
 
        ret = ldb_delete(kd->ldb, childdn);
 
@@ -475,7 +490,12 @@ static WERROR ldb_set_value(struct hive_key *parent,
        msg = reg_ldb_pack_value(kd->ldb, mem_ctx, name, type, data);
 
        msg->dn = ldb_dn_copy(msg, kd->dn);
-       ldb_dn_add_child_fmt(msg->dn, "value=%s", name);
+       if (!ldb_dn_add_child_fmt(msg->dn, "value=%s",
+                                 reg_ldb_escape(mem_ctx, name)))
+       {
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
 
        ret = ldb_add(kd->ldb, msg);
        if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
index 681e3b918f870afc11f38ce47c81539fbd3ee8c0..7eba428aef3360b5d78b3ac552b27d3e1392c280 100644 (file)
@@ -411,7 +411,15 @@ static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call,
                                           &value_type, &value_data);
 
        if (!W_ERROR_IS_OK(result)) {
-               return result;
+               /*
+                * Windows expects WERR_BADFILE when a particular value
+                * is not found.  If we receive WERR_NOT_FOUND from the lower
+                * layer calls, translate it here to return what is expected.
+                */
+               if (W_ERROR_EQUAL(result, WERR_NOT_FOUND))
+                       return WERR_BADFILE;
+               else
+                       return result;
        }
 
        /* Just asking for the size of the buffer */