| 1 | /*
 | 
|---|
| 2 |  *  Unix SMB/CIFS implementation.
 | 
|---|
| 3 |  *  Virtual Windows Registry Layer
 | 
|---|
| 4 |  *  Copyright (C) Volker Lendecke 2006
 | 
|---|
| 5 |  *  Copyright (C) Michael Adam 2007-2010
 | 
|---|
| 6 |  *
 | 
|---|
| 7 |  *  This program is free software; you can redistribute it and/or modify
 | 
|---|
| 8 |  *  it under the terms of the GNU General Public License as published by
 | 
|---|
| 9 |  *  the Free Software Foundation; either version 3 of the License, or
 | 
|---|
| 10 |  *  (at your option) any later version.
 | 
|---|
| 11 |  *
 | 
|---|
| 12 |  *  This program is distributed in the hope that it will be useful,
 | 
|---|
| 13 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 14 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 15 |  *  GNU General Public License for more details.
 | 
|---|
| 16 |  *
 | 
|---|
| 17 |  *  You should have received a copy of the GNU General Public License
 | 
|---|
| 18 |  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 | 
|---|
| 19 |  */
 | 
|---|
| 20 | 
 | 
|---|
| 21 | /* Attempt to wrap the existing API in a more winreg.idl-like way */
 | 
|---|
| 22 | 
 | 
|---|
| 23 | /*
 | 
|---|
| 24 |  * Here is a list of winreg.idl functions and corresponding implementations
 | 
|---|
| 25 |  * provided here:
 | 
|---|
| 26 |  *
 | 
|---|
| 27 |  * 0x00         winreg_OpenHKCR
 | 
|---|
| 28 |  * 0x01         winreg_OpenHKCU
 | 
|---|
| 29 |  * 0x02         winreg_OpenHKLM
 | 
|---|
| 30 |  * 0x03         winreg_OpenHKPD
 | 
|---|
| 31 |  * 0x04         winreg_OpenHKU
 | 
|---|
| 32 |  * 0x05         winreg_CloseKey
 | 
|---|
| 33 |  * 0x06         winreg_CreateKey                        reg_createkey
 | 
|---|
| 34 |  * 0x07         winreg_DeleteKey                        reg_deletekey
 | 
|---|
| 35 |  * 0x08         winreg_DeleteValue                      reg_deletevalue
 | 
|---|
| 36 |  * 0x09         winreg_EnumKey                          reg_enumkey
 | 
|---|
| 37 |  * 0x0a         winreg_EnumValue                        reg_enumvalue
 | 
|---|
| 38 |  * 0x0b         winreg_FlushKey
 | 
|---|
| 39 |  * 0x0c         winreg_GetKeySecurity                   reg_getkeysecurity
 | 
|---|
| 40 |  * 0x0d         winreg_LoadKey
 | 
|---|
| 41 |  * 0x0e         winreg_NotifyChangeKeyValue
 | 
|---|
| 42 |  * 0x0f         winreg_OpenKey                          reg_openkey
 | 
|---|
| 43 |  * 0x10         winreg_QueryInfoKey                     reg_queryinfokey
 | 
|---|
| 44 |  * 0x11         winreg_QueryValue                       reg_queryvalue
 | 
|---|
| 45 |  * 0x12         winreg_ReplaceKey
 | 
|---|
| 46 |  * 0x13         winreg_RestoreKey                       reg_restorekey
 | 
|---|
| 47 |  * 0x14         winreg_SaveKey                          reg_savekey
 | 
|---|
| 48 |  * 0x15         winreg_SetKeySecurity                   reg_setkeysecurity
 | 
|---|
| 49 |  * 0x16         winreg_SetValue                         reg_setvalue
 | 
|---|
| 50 |  * 0x17         winreg_UnLoadKey
 | 
|---|
| 51 |  * 0x18         winreg_InitiateSystemShutdown
 | 
|---|
| 52 |  * 0x19         winreg_AbortSystemShutdown
 | 
|---|
| 53 |  * 0x1a         winreg_GetVersion                       reg_getversion
 | 
|---|
| 54 |  * 0x1b         winreg_OpenHKCC
 | 
|---|
| 55 |  * 0x1c         winreg_OpenHKDD
 | 
|---|
| 56 |  * 0x1d         winreg_QueryMultipleValues              reg_querymultiplevalues
 | 
|---|
| 57 |  * 0x1e         winreg_InitiateSystemShutdownEx
 | 
|---|
| 58 |  * 0x1f         winreg_SaveKeyEx
 | 
|---|
| 59 |  * 0x20         winreg_OpenHKPT
 | 
|---|
| 60 |  * 0x21         winreg_OpenHKPN
 | 
|---|
| 61 |  * 0x22         winreg_QueryMultipleValues2             reg_querymultiplevalues
 | 
|---|
| 62 |  *
 | 
|---|
| 63 |  */
 | 
|---|
| 64 | 
 | 
|---|
| 65 | #include "includes.h"
 | 
|---|
| 66 | #include "registry.h"
 | 
|---|
| 67 | #include "reg_api.h"
 | 
|---|
| 68 | #include "reg_cachehook.h"
 | 
|---|
| 69 | #include "reg_backend_db.h"
 | 
|---|
| 70 | #include "reg_dispatcher.h"
 | 
|---|
| 71 | #include "reg_objects.h"
 | 
|---|
| 72 | #include "../librpc/gen_ndr/ndr_security.h"
 | 
|---|
| 73 | 
 | 
|---|
| 74 | #undef DBGC_CLASS
 | 
|---|
| 75 | #define DBGC_CLASS DBGC_REGISTRY
 | 
|---|
| 76 | 
 | 
|---|
| 77 | 
 | 
|---|
| 78 | /**********************************************************************
 | 
|---|
| 79 |  * Helper functions
 | 
|---|
| 80 |  **********************************************************************/
 | 
|---|
| 81 | 
 | 
|---|
| 82 | static WERROR fill_value_cache(struct registry_key *key)
 | 
|---|
| 83 | {
 | 
|---|
| 84 |         WERROR werr;
 | 
|---|
| 85 | 
 | 
|---|
| 86 |         if (key->values != NULL) {
 | 
|---|
| 87 |                 if (!reg_values_need_update(key->key, key->values)) {
 | 
|---|
| 88 |                         return WERR_OK;
 | 
|---|
| 89 |                 }
 | 
|---|
| 90 |         }
 | 
|---|
| 91 | 
 | 
|---|
| 92 |         TALLOC_FREE(key->values);
 | 
|---|
| 93 |         werr = regval_ctr_init(key, &(key->values));
 | 
|---|
| 94 |         W_ERROR_NOT_OK_RETURN(werr);
 | 
|---|
| 95 | 
 | 
|---|
| 96 |         if (fetch_reg_values(key->key, key->values) == -1) {
 | 
|---|
| 97 |                 TALLOC_FREE(key->values);
 | 
|---|
| 98 |                 return WERR_BADFILE;
 | 
|---|
| 99 |         }
 | 
|---|
| 100 | 
 | 
|---|
| 101 |         return WERR_OK;
 | 
|---|
| 102 | }
 | 
|---|
| 103 | 
 | 
|---|
| 104 | static WERROR fill_subkey_cache(struct registry_key *key)
 | 
|---|
| 105 | {
 | 
|---|
| 106 |         WERROR werr;
 | 
|---|
| 107 | 
 | 
|---|
| 108 |         if (key->subkeys != NULL) {
 | 
|---|
| 109 |                 if (!reg_subkeys_need_update(key->key, key->subkeys)) {
 | 
|---|
| 110 |                         return WERR_OK;
 | 
|---|
| 111 |                 }
 | 
|---|
| 112 |         }
 | 
|---|
| 113 | 
 | 
|---|
| 114 |         werr = regsubkey_ctr_init(key, &(key->subkeys));
 | 
|---|
| 115 |         W_ERROR_NOT_OK_RETURN(werr);
 | 
|---|
| 116 | 
 | 
|---|
| 117 |         if (fetch_reg_keys(key->key, key->subkeys) == -1) {
 | 
|---|
| 118 |                 TALLOC_FREE(key->subkeys);
 | 
|---|
| 119 |                 return WERR_BADFILE;
 | 
|---|
| 120 |         }
 | 
|---|
| 121 | 
 | 
|---|
| 122 |         return WERR_OK;
 | 
|---|
| 123 | }
 | 
|---|
| 124 | 
 | 
|---|
| 125 | static int regkey_destructor(struct registry_key_handle *key)
 | 
|---|
| 126 | {
 | 
|---|
| 127 |         return regdb_close();
 | 
|---|
| 128 | }
 | 
|---|
| 129 | 
 | 
|---|
| 130 | static WERROR regkey_open_onelevel(TALLOC_CTX *mem_ctx, 
 | 
|---|
| 131 |                                    struct registry_key *parent,
 | 
|---|
| 132 |                                    const char *name,
 | 
|---|
| 133 |                                    const struct security_token *token,
 | 
|---|
| 134 |                                    uint32 access_desired,
 | 
|---|
| 135 |                                    struct registry_key **pregkey)
 | 
|---|
| 136 | {
 | 
|---|
| 137 |         WERROR          result = WERR_OK;
 | 
|---|
| 138 |         struct registry_key *regkey;
 | 
|---|
| 139 |         struct registry_key_handle *key;
 | 
|---|
| 140 | 
 | 
|---|
| 141 |         DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name));
 | 
|---|
| 142 | 
 | 
|---|
| 143 |         SMB_ASSERT(strchr(name, '\\') == NULL);
 | 
|---|
| 144 | 
 | 
|---|
| 145 |         if (!(regkey = TALLOC_ZERO_P(mem_ctx, struct registry_key)) ||
 | 
|---|
| 146 |             !(regkey->token = dup_nt_token(regkey, token)) ||
 | 
|---|
| 147 |             !(regkey->key = TALLOC_ZERO_P(regkey, struct registry_key_handle)))
 | 
|---|
| 148 |         {
 | 
|---|
| 149 |                 result = WERR_NOMEM;
 | 
|---|
| 150 |                 goto done;
 | 
|---|
| 151 |         }
 | 
|---|
| 152 | 
 | 
|---|
| 153 |         result = regdb_open();
 | 
|---|
| 154 |         if (!(W_ERROR_IS_OK(result))) {
 | 
|---|
| 155 |                 goto done;
 | 
|---|
| 156 |         }
 | 
|---|
| 157 | 
 | 
|---|
| 158 |         key = regkey->key;
 | 
|---|
| 159 |         talloc_set_destructor(key, regkey_destructor);
 | 
|---|
| 160 | 
 | 
|---|
| 161 |         /* initialization */
 | 
|---|
| 162 | 
 | 
|---|
| 163 |         key->type = REG_KEY_GENERIC;
 | 
|---|
| 164 | 
 | 
|---|
| 165 |         if (name[0] == '\0') {
 | 
|---|
| 166 |                 /*
 | 
|---|
| 167 |                  * Open a copy of the parent key
 | 
|---|
| 168 |                  */
 | 
|---|
| 169 |                 if (!parent) {
 | 
|---|
| 170 |                         result = WERR_BADFILE;
 | 
|---|
| 171 |                         goto done;
 | 
|---|
| 172 |                 }
 | 
|---|
| 173 |                 key->name = talloc_strdup(key, parent->key->name);
 | 
|---|
| 174 |         }
 | 
|---|
| 175 |         else {
 | 
|---|
| 176 |                 /*
 | 
|---|
| 177 |                  * Normal subkey open
 | 
|---|
| 178 |                  */
 | 
|---|
| 179 |                 key->name = talloc_asprintf(key, "%s%s%s",
 | 
|---|
| 180 |                                             parent ? parent->key->name : "",
 | 
|---|
| 181 |                                             parent ? "\\": "",
 | 
|---|
| 182 |                                             name);
 | 
|---|
| 183 |         }
 | 
|---|
| 184 | 
 | 
|---|
| 185 |         if (key->name == NULL) {
 | 
|---|
| 186 |                 result = WERR_NOMEM;
 | 
|---|
| 187 |                 goto done;
 | 
|---|
| 188 |         }
 | 
|---|
| 189 | 
 | 
|---|
| 190 |         /* Tag this as a Performance Counter Key */
 | 
|---|
| 191 | 
 | 
|---|
| 192 |         if( StrnCaseCmp(key->name, KEY_HKPD, strlen(KEY_HKPD)) == 0 )
 | 
|---|
| 193 |                 key->type = REG_KEY_HKPD;
 | 
|---|
| 194 | 
 | 
|---|
| 195 |         /* Look up the table of registry I/O operations */
 | 
|---|
| 196 | 
 | 
|---|
| 197 |         key->ops = reghook_cache_find( key->name );
 | 
|---|
| 198 |         if (key->ops == NULL) {
 | 
|---|
| 199 |                 DEBUG(0,("reg_open_onelevel: Failed to assign "
 | 
|---|
| 200 |                          "registry_ops to [%s]\n", key->name ));
 | 
|---|
| 201 |                 result = WERR_BADFILE;
 | 
|---|
| 202 |                 goto done;
 | 
|---|
| 203 |         }
 | 
|---|
| 204 | 
 | 
|---|
| 205 |         /* FIXME: Existence is currently checked by fetching the subkeys */
 | 
|---|
| 206 | 
 | 
|---|
| 207 |         result = fill_subkey_cache(regkey);
 | 
|---|
| 208 |         if (!W_ERROR_IS_OK(result)) {
 | 
|---|
| 209 |                 goto done;
 | 
|---|
| 210 |         }
 | 
|---|
| 211 | 
 | 
|---|
| 212 |         if ( !regkey_access_check( key, access_desired, &key->access_granted,
 | 
|---|
| 213 |                                    token ) ) {
 | 
|---|
| 214 |                 result = WERR_ACCESS_DENIED;
 | 
|---|
| 215 |                 goto done;
 | 
|---|
| 216 |         }
 | 
|---|
| 217 | 
 | 
|---|
| 218 |         *pregkey = regkey;
 | 
|---|
| 219 |         result = WERR_OK;
 | 
|---|
| 220 | 
 | 
|---|
| 221 | done:
 | 
|---|
| 222 |         if ( !W_ERROR_IS_OK(result) ) {
 | 
|---|
| 223 |                 TALLOC_FREE(regkey);
 | 
|---|
| 224 |         }
 | 
|---|
| 225 | 
 | 
|---|
| 226 |         return result;
 | 
|---|
| 227 | }
 | 
|---|
| 228 | 
 | 
|---|
| 229 | WERROR reg_openhive(TALLOC_CTX *mem_ctx, const char *hive,
 | 
|---|
| 230 |                     uint32 desired_access,
 | 
|---|
| 231 |                     const struct security_token *token,
 | 
|---|
| 232 |                     struct registry_key **pkey)
 | 
|---|
| 233 | {
 | 
|---|
| 234 |         SMB_ASSERT(hive != NULL);
 | 
|---|
| 235 |         SMB_ASSERT(hive[0] != '\0');
 | 
|---|
| 236 |         SMB_ASSERT(strchr(hive, '\\') == NULL);
 | 
|---|
| 237 | 
 | 
|---|
| 238 |         return regkey_open_onelevel(mem_ctx, NULL, hive, token, desired_access,
 | 
|---|
| 239 |                                     pkey);
 | 
|---|
| 240 | }
 | 
|---|
| 241 | 
 | 
|---|
| 242 | 
 | 
|---|
| 243 | /**********************************************************************
 | 
|---|
| 244 |  * The API functions
 | 
|---|
| 245 |  **********************************************************************/
 | 
|---|
| 246 | 
 | 
|---|
| 247 | WERROR reg_openkey(TALLOC_CTX *mem_ctx, struct registry_key *parent,
 | 
|---|
| 248 |                    const char *name, uint32 desired_access,
 | 
|---|
| 249 |                    struct registry_key **pkey)
 | 
|---|
| 250 | {
 | 
|---|
| 251 |         struct registry_key *direct_parent = parent;
 | 
|---|
| 252 |         WERROR err;
 | 
|---|
| 253 |         char *p, *path;
 | 
|---|
| 254 |         size_t len;
 | 
|---|
| 255 |         TALLOC_CTX *frame = talloc_stackframe();
 | 
|---|
| 256 | 
 | 
|---|
| 257 |         path = talloc_strdup(frame, name);
 | 
|---|
| 258 |         if (path == NULL) {
 | 
|---|
| 259 |                 err = WERR_NOMEM;
 | 
|---|
| 260 |                 goto error;
 | 
|---|
| 261 |         }
 | 
|---|
| 262 | 
 | 
|---|
| 263 |         len = strlen(path);
 | 
|---|
| 264 | 
 | 
|---|
| 265 |         if ((len > 0) && (path[len-1] == '\\')) {
 | 
|---|
| 266 |                 path[len-1] = '\0';
 | 
|---|
| 267 |         }
 | 
|---|
| 268 | 
 | 
|---|
| 269 |         while ((p = strchr(path, '\\')) != NULL) {
 | 
|---|
| 270 |                 char *name_component;
 | 
|---|
| 271 |                 struct registry_key *tmp;
 | 
|---|
| 272 | 
 | 
|---|
| 273 |                 name_component = talloc_strndup(frame, path, (p - path));
 | 
|---|
| 274 |                 if (name_component == NULL) {
 | 
|---|
| 275 |                         err = WERR_NOMEM;
 | 
|---|
| 276 |                         goto error;
 | 
|---|
| 277 |                 }
 | 
|---|
| 278 | 
 | 
|---|
| 279 |                 err = regkey_open_onelevel(frame, direct_parent,
 | 
|---|
| 280 |                                            name_component, parent->token,
 | 
|---|
| 281 |                                            KEY_ENUMERATE_SUB_KEYS, &tmp);
 | 
|---|
| 282 | 
 | 
|---|
| 283 |                 if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 284 |                         goto error;
 | 
|---|
| 285 |                 }
 | 
|---|
| 286 | 
 | 
|---|
| 287 |                 direct_parent = tmp;
 | 
|---|
| 288 |                 path = p+1;
 | 
|---|
| 289 |         }
 | 
|---|
| 290 | 
 | 
|---|
| 291 |         err = regkey_open_onelevel(mem_ctx, direct_parent, path, parent->token,
 | 
|---|
| 292 |                                    desired_access, pkey);
 | 
|---|
| 293 | 
 | 
|---|
| 294 | error:
 | 
|---|
| 295 |         talloc_free(frame);
 | 
|---|
| 296 |         return err;
 | 
|---|
| 297 | }
 | 
|---|
| 298 | 
 | 
|---|
| 299 | WERROR reg_enumkey(TALLOC_CTX *mem_ctx, struct registry_key *key,
 | 
|---|
| 300 |                    uint32 idx, char **name, NTTIME *last_write_time)
 | 
|---|
| 301 | {
 | 
|---|
| 302 |         WERROR err;
 | 
|---|
| 303 | 
 | 
|---|
| 304 |         if (!(key->key->access_granted & KEY_ENUMERATE_SUB_KEYS)) {
 | 
|---|
| 305 |                 return WERR_ACCESS_DENIED;
 | 
|---|
| 306 |         }
 | 
|---|
| 307 | 
 | 
|---|
| 308 |         if (!W_ERROR_IS_OK(err = fill_subkey_cache(key))) {
 | 
|---|
| 309 |                 return err;
 | 
|---|
| 310 |         }
 | 
|---|
| 311 | 
 | 
|---|
| 312 |         if (idx >= regsubkey_ctr_numkeys(key->subkeys)) {
 | 
|---|
| 313 |                 return WERR_NO_MORE_ITEMS;
 | 
|---|
| 314 |         }
 | 
|---|
| 315 | 
 | 
|---|
| 316 |         if (!(*name = talloc_strdup(mem_ctx,
 | 
|---|
| 317 |                         regsubkey_ctr_specific_key(key->subkeys, idx))))
 | 
|---|
| 318 |         {
 | 
|---|
| 319 |                 return WERR_NOMEM;
 | 
|---|
| 320 |         }
 | 
|---|
| 321 | 
 | 
|---|
| 322 |         if (last_write_time) {
 | 
|---|
| 323 |                 *last_write_time = 0;
 | 
|---|
| 324 |         }
 | 
|---|
| 325 | 
 | 
|---|
| 326 |         return WERR_OK;
 | 
|---|
| 327 | }
 | 
|---|
| 328 | 
 | 
|---|
| 329 | WERROR reg_enumvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
 | 
|---|
| 330 |                      uint32 idx, char **pname, struct registry_value **pval)
 | 
|---|
| 331 | {
 | 
|---|
| 332 |         struct registry_value *val;
 | 
|---|
| 333 |         struct regval_blob *blob;
 | 
|---|
| 334 |         WERROR err;
 | 
|---|
| 335 | 
 | 
|---|
| 336 |         if (!(key->key->access_granted & KEY_QUERY_VALUE)) {
 | 
|---|
| 337 |                 return WERR_ACCESS_DENIED;
 | 
|---|
| 338 |         }
 | 
|---|
| 339 | 
 | 
|---|
| 340 |         if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) {
 | 
|---|
| 341 |                 return err;
 | 
|---|
| 342 |         }
 | 
|---|
| 343 | 
 | 
|---|
| 344 |         if (idx >= regval_ctr_numvals(key->values)) {
 | 
|---|
| 345 |                 return WERR_NO_MORE_ITEMS;
 | 
|---|
| 346 |         }
 | 
|---|
| 347 | 
 | 
|---|
| 348 |         blob = regval_ctr_specific_value(key->values, idx);
 | 
|---|
| 349 | 
 | 
|---|
| 350 |         val = talloc_zero(mem_ctx, struct registry_value);
 | 
|---|
| 351 |         if (val == NULL) {
 | 
|---|
| 352 |                 return WERR_NOMEM;
 | 
|---|
| 353 |         }
 | 
|---|
| 354 | 
 | 
|---|
| 355 |         val->type = regval_type(blob);
 | 
|---|
| 356 |         val->data = data_blob_talloc(mem_ctx, regval_data_p(blob), regval_size(blob));
 | 
|---|
| 357 | 
 | 
|---|
| 358 |         if (pname
 | 
|---|
| 359 |             && !(*pname = talloc_strdup(
 | 
|---|
| 360 |                          mem_ctx, regval_name(blob)))) {
 | 
|---|
| 361 |                 TALLOC_FREE(val);
 | 
|---|
| 362 |                 return WERR_NOMEM;
 | 
|---|
| 363 |         }
 | 
|---|
| 364 | 
 | 
|---|
| 365 |         *pval = val;
 | 
|---|
| 366 |         return WERR_OK;
 | 
|---|
| 367 | }
 | 
|---|
| 368 | 
 | 
|---|
| 369 | static WERROR reg_enumvalue_nocachefill(TALLOC_CTX *mem_ctx,
 | 
|---|
| 370 |                                         struct registry_key *key,
 | 
|---|
| 371 |                                         uint32 idx, char **pname,
 | 
|---|
| 372 |                                         struct registry_value **pval)
 | 
|---|
| 373 | {
 | 
|---|
| 374 |         struct registry_value *val;
 | 
|---|
| 375 |         struct regval_blob *blob;
 | 
|---|
| 376 | 
 | 
|---|
| 377 |         if (!(key->key->access_granted & KEY_QUERY_VALUE)) {
 | 
|---|
| 378 |                 return WERR_ACCESS_DENIED;
 | 
|---|
| 379 |         }
 | 
|---|
| 380 | 
 | 
|---|
| 381 |         if (idx >= regval_ctr_numvals(key->values)) {
 | 
|---|
| 382 |                 return WERR_NO_MORE_ITEMS;
 | 
|---|
| 383 |         }
 | 
|---|
| 384 | 
 | 
|---|
| 385 |         blob = regval_ctr_specific_value(key->values, idx);
 | 
|---|
| 386 | 
 | 
|---|
| 387 |         val = talloc_zero(mem_ctx, struct registry_value);
 | 
|---|
| 388 |         if (val == NULL) {
 | 
|---|
| 389 |                 return WERR_NOMEM;
 | 
|---|
| 390 |         }
 | 
|---|
| 391 | 
 | 
|---|
| 392 |         val->type = regval_type(blob);
 | 
|---|
| 393 |         val->data = data_blob_talloc(mem_ctx, regval_data_p(blob), regval_size(blob));
 | 
|---|
| 394 | 
 | 
|---|
| 395 |         if (pname
 | 
|---|
| 396 |             && !(*pname = talloc_strdup(
 | 
|---|
| 397 |                          mem_ctx, regval_name(blob)))) {
 | 
|---|
| 398 |                 TALLOC_FREE(val);
 | 
|---|
| 399 |                 return WERR_NOMEM;
 | 
|---|
| 400 |         }
 | 
|---|
| 401 | 
 | 
|---|
| 402 |         *pval = val;
 | 
|---|
| 403 |         return WERR_OK;
 | 
|---|
| 404 | }
 | 
|---|
| 405 | 
 | 
|---|
| 406 | WERROR reg_queryvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
 | 
|---|
| 407 |                       const char *name, struct registry_value **pval)
 | 
|---|
| 408 | {
 | 
|---|
| 409 |         WERROR err;
 | 
|---|
| 410 |         uint32 i;
 | 
|---|
| 411 | 
 | 
|---|
| 412 |         if (!(key->key->access_granted & KEY_QUERY_VALUE)) {
 | 
|---|
| 413 |                 return WERR_ACCESS_DENIED;
 | 
|---|
| 414 |         }
 | 
|---|
| 415 | 
 | 
|---|
| 416 |         if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) {
 | 
|---|
| 417 |                 return err;
 | 
|---|
| 418 |         }
 | 
|---|
| 419 | 
 | 
|---|
| 420 |         for (i=0; i < regval_ctr_numvals(key->values); i++) {
 | 
|---|
| 421 |                 struct regval_blob *blob;
 | 
|---|
| 422 |                 blob = regval_ctr_specific_value(key->values, i);
 | 
|---|
| 423 |                 if (strequal(regval_name(blob), name)) {
 | 
|---|
| 424 |                         /*
 | 
|---|
| 425 |                          * don't use reg_enumvalue here:
 | 
|---|
| 426 |                          * re-reading the values from the disk
 | 
|---|
| 427 |                          * would change the indexing and break
 | 
|---|
| 428 |                          * this function.
 | 
|---|
| 429 |                          */
 | 
|---|
| 430 |                         return reg_enumvalue_nocachefill(mem_ctx, key, i,
 | 
|---|
| 431 |                                                          NULL, pval);
 | 
|---|
| 432 |                 }
 | 
|---|
| 433 |         }
 | 
|---|
| 434 | 
 | 
|---|
| 435 |         return WERR_BADFILE;
 | 
|---|
| 436 | }
 | 
|---|
| 437 | 
 | 
|---|
| 438 | WERROR reg_querymultiplevalues(TALLOC_CTX *mem_ctx,
 | 
|---|
| 439 |                                struct registry_key *key,
 | 
|---|
| 440 |                                uint32_t num_names,
 | 
|---|
| 441 |                                const char **names,
 | 
|---|
| 442 |                                uint32_t *pnum_vals,
 | 
|---|
| 443 |                                struct registry_value **pvals)
 | 
|---|
| 444 | {
 | 
|---|
| 445 |         WERROR err;
 | 
|---|
| 446 |         uint32_t i, n, found = 0;
 | 
|---|
| 447 |         struct registry_value *vals;
 | 
|---|
| 448 | 
 | 
|---|
| 449 |         if (num_names == 0) {
 | 
|---|
| 450 |                 return WERR_OK;
 | 
|---|
| 451 |         }
 | 
|---|
| 452 | 
 | 
|---|
| 453 |         if (!(key->key->access_granted & KEY_QUERY_VALUE)) {
 | 
|---|
| 454 |                 return WERR_ACCESS_DENIED;
 | 
|---|
| 455 |         }
 | 
|---|
| 456 | 
 | 
|---|
| 457 |         if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) {
 | 
|---|
| 458 |                 return err;
 | 
|---|
| 459 |         }
 | 
|---|
| 460 | 
 | 
|---|
| 461 |         vals = talloc_zero_array(mem_ctx, struct registry_value, num_names);
 | 
|---|
| 462 |         if (vals == NULL) {
 | 
|---|
| 463 |                 return WERR_NOMEM;
 | 
|---|
| 464 |         }
 | 
|---|
| 465 | 
 | 
|---|
| 466 |         for (n=0; n < num_names; n++) {
 | 
|---|
| 467 |                 for (i=0; i < regval_ctr_numvals(key->values); i++) {
 | 
|---|
| 468 |                         struct regval_blob *blob;
 | 
|---|
| 469 |                         blob = regval_ctr_specific_value(key->values, i);
 | 
|---|
| 470 |                         if (strequal(regval_name(blob), names[n])) {
 | 
|---|
| 471 |                                 struct registry_value *v;
 | 
|---|
| 472 |                                 err = reg_enumvalue(mem_ctx, key, i, NULL, &v);
 | 
|---|
| 473 |                                 if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 474 |                                         return err;
 | 
|---|
| 475 |                                 }
 | 
|---|
| 476 |                                 vals[n] = *v;
 | 
|---|
| 477 |                                 found++;
 | 
|---|
| 478 |                         }
 | 
|---|
| 479 |                 }
 | 
|---|
| 480 |         }
 | 
|---|
| 481 | 
 | 
|---|
| 482 |         *pvals = vals;
 | 
|---|
| 483 |         *pnum_vals = found;
 | 
|---|
| 484 | 
 | 
|---|
| 485 |         return WERR_OK;
 | 
|---|
| 486 | }
 | 
|---|
| 487 | 
 | 
|---|
| 488 | WERROR reg_queryinfokey(struct registry_key *key, uint32_t *num_subkeys,
 | 
|---|
| 489 |                         uint32_t *max_subkeylen, uint32_t *max_subkeysize, 
 | 
|---|
| 490 |                         uint32_t *num_values, uint32_t *max_valnamelen, 
 | 
|---|
| 491 |                         uint32_t *max_valbufsize, uint32_t *secdescsize,
 | 
|---|
| 492 |                         NTTIME *last_changed_time)
 | 
|---|
| 493 | {
 | 
|---|
| 494 |         uint32 i, max_size;
 | 
|---|
| 495 |         size_t max_len;
 | 
|---|
| 496 |         TALLOC_CTX *mem_ctx;
 | 
|---|
| 497 |         WERROR err;
 | 
|---|
| 498 |         struct security_descriptor *secdesc;
 | 
|---|
| 499 | 
 | 
|---|
| 500 |         if (!(key->key->access_granted & KEY_QUERY_VALUE)) {
 | 
|---|
| 501 |                 return WERR_ACCESS_DENIED;
 | 
|---|
| 502 |         }
 | 
|---|
| 503 | 
 | 
|---|
| 504 |         if (!W_ERROR_IS_OK(fill_subkey_cache(key)) ||
 | 
|---|
| 505 |             !W_ERROR_IS_OK(fill_value_cache(key))) {
 | 
|---|
| 506 |                 return WERR_BADFILE;
 | 
|---|
| 507 |         }
 | 
|---|
| 508 | 
 | 
|---|
| 509 |         max_len = 0;
 | 
|---|
| 510 |         for (i=0; i< regsubkey_ctr_numkeys(key->subkeys); i++) {
 | 
|---|
| 511 |                 max_len = MAX(max_len,
 | 
|---|
| 512 |                         strlen(regsubkey_ctr_specific_key(key->subkeys, i)));
 | 
|---|
| 513 |         }
 | 
|---|
| 514 | 
 | 
|---|
| 515 |         *num_subkeys = regsubkey_ctr_numkeys(key->subkeys);
 | 
|---|
| 516 |         *max_subkeylen = max_len;
 | 
|---|
| 517 |         *max_subkeysize = 0;    /* Class length? */
 | 
|---|
| 518 | 
 | 
|---|
| 519 |         max_len = 0;
 | 
|---|
| 520 |         max_size = 0;
 | 
|---|
| 521 |         for (i=0; i < regval_ctr_numvals(key->values); i++) {
 | 
|---|
| 522 |                 struct regval_blob *blob;
 | 
|---|
| 523 |                 blob = regval_ctr_specific_value(key->values, i);
 | 
|---|
| 524 |                 max_len = MAX(max_len, strlen(regval_name(blob)));
 | 
|---|
| 525 |                 max_size = MAX(max_size, regval_size(blob));
 | 
|---|
| 526 |         }
 | 
|---|
| 527 | 
 | 
|---|
| 528 |         *num_values = regval_ctr_numvals(key->values);
 | 
|---|
| 529 |         *max_valnamelen = max_len;
 | 
|---|
| 530 |         *max_valbufsize = max_size;
 | 
|---|
| 531 | 
 | 
|---|
| 532 |         if (!(mem_ctx = talloc_new(key))) {
 | 
|---|
| 533 |                 return WERR_NOMEM;
 | 
|---|
| 534 |         }
 | 
|---|
| 535 | 
 | 
|---|
| 536 |         err = regkey_get_secdesc(mem_ctx, key->key, &secdesc);
 | 
|---|
| 537 |         if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 538 |                 TALLOC_FREE(mem_ctx);
 | 
|---|
| 539 |                 return err;
 | 
|---|
| 540 |         }
 | 
|---|
| 541 | 
 | 
|---|
| 542 |         *secdescsize = ndr_size_security_descriptor(secdesc, 0);
 | 
|---|
| 543 |         TALLOC_FREE(mem_ctx);
 | 
|---|
| 544 | 
 | 
|---|
| 545 |         *last_changed_time = 0;
 | 
|---|
| 546 | 
 | 
|---|
| 547 |         return WERR_OK;
 | 
|---|
| 548 | }
 | 
|---|
| 549 | 
 | 
|---|
| 550 | WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent,
 | 
|---|
| 551 |                      const char *subkeypath, uint32 desired_access,
 | 
|---|
| 552 |                      struct registry_key **pkey,
 | 
|---|
| 553 |                      enum winreg_CreateAction *paction)
 | 
|---|
| 554 | {
 | 
|---|
| 555 |         struct registry_key *key = parent;
 | 
|---|
| 556 |         struct registry_key *create_parent;
 | 
|---|
| 557 |         TALLOC_CTX *mem_ctx;
 | 
|---|
| 558 |         char *path, *end;
 | 
|---|
| 559 |         WERROR err;
 | 
|---|
| 560 |         uint32_t access_granted;
 | 
|---|
| 561 | 
 | 
|---|
| 562 |         mem_ctx = talloc_new(ctx);
 | 
|---|
| 563 |         if (mem_ctx == NULL) {
 | 
|---|
| 564 |                 return WERR_NOMEM;
 | 
|---|
| 565 |         }
 | 
|---|
| 566 | 
 | 
|---|
| 567 |         path = talloc_strdup(mem_ctx, subkeypath);
 | 
|---|
| 568 |         if (path == NULL) {
 | 
|---|
| 569 |                 err = WERR_NOMEM;
 | 
|---|
| 570 |                 goto done;
 | 
|---|
| 571 |         }
 | 
|---|
| 572 | 
 | 
|---|
| 573 |         err = regdb_transaction_start();
 | 
|---|
| 574 |         if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 575 |                 DEBUG(0, ("reg_createkey: failed to start transaction: %s\n",
 | 
|---|
| 576 |                           win_errstr(err)));
 | 
|---|
| 577 |                 goto done;
 | 
|---|
| 578 |         }
 | 
|---|
| 579 | 
 | 
|---|
| 580 |         while ((end = strchr(path, '\\')) != NULL) {
 | 
|---|
| 581 |                 struct registry_key *tmp;
 | 
|---|
| 582 |                 enum winreg_CreateAction action;
 | 
|---|
| 583 | 
 | 
|---|
| 584 |                 *end = '\0';
 | 
|---|
| 585 | 
 | 
|---|
| 586 |                 err = reg_createkey(mem_ctx, key, path,
 | 
|---|
| 587 |                                     KEY_ENUMERATE_SUB_KEYS, &tmp, &action);
 | 
|---|
| 588 |                 if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 589 |                         goto trans_done;
 | 
|---|
| 590 |                 }
 | 
|---|
| 591 | 
 | 
|---|
| 592 |                 if (key != parent) {
 | 
|---|
| 593 |                         TALLOC_FREE(key);
 | 
|---|
| 594 |                 }
 | 
|---|
| 595 | 
 | 
|---|
| 596 |                 key = tmp;
 | 
|---|
| 597 |                 path = end+1;
 | 
|---|
| 598 |         }
 | 
|---|
| 599 | 
 | 
|---|
| 600 |         /*
 | 
|---|
| 601 |          * At this point, "path" contains the one-element subkey of "key". We
 | 
|---|
| 602 |          * can try to open it.
 | 
|---|
| 603 |          */
 | 
|---|
| 604 | 
 | 
|---|
| 605 |         err = reg_openkey(ctx, key, path, desired_access, pkey);
 | 
|---|
| 606 |         if (W_ERROR_IS_OK(err)) {
 | 
|---|
| 607 |                 if (paction != NULL) {
 | 
|---|
| 608 |                         *paction = REG_OPENED_EXISTING_KEY;
 | 
|---|
| 609 |                 }
 | 
|---|
| 610 |                 goto trans_done;
 | 
|---|
| 611 |         }
 | 
|---|
| 612 | 
 | 
|---|
| 613 |         if (!W_ERROR_EQUAL(err, WERR_BADFILE)) {
 | 
|---|
| 614 |                 /*
 | 
|---|
| 615 |                  * Something but "notfound" has happened, so bail out
 | 
|---|
| 616 |                  */
 | 
|---|
| 617 |                 goto trans_done;
 | 
|---|
| 618 |         }
 | 
|---|
| 619 | 
 | 
|---|
| 620 |         /*
 | 
|---|
| 621 |          * We may (e.g. in the iteration) have opened the key with ENUM_SUBKEY.
 | 
|---|
| 622 |          * Instead of re-opening the key with CREATE_SUB_KEY, we simply
 | 
|---|
| 623 |          * duplicate the access check here and skip the expensive full open.
 | 
|---|
| 624 |          */
 | 
|---|
| 625 |         if (!regkey_access_check(key->key, KEY_CREATE_SUB_KEY, &access_granted,
 | 
|---|
| 626 |                                  key->token))
 | 
|---|
| 627 |         {
 | 
|---|
| 628 |                 err = WERR_ACCESS_DENIED;
 | 
|---|
| 629 |                 goto done;
 | 
|---|
| 630 |         }
 | 
|---|
| 631 | 
 | 
|---|
| 632 |         /*
 | 
|---|
| 633 |          * Actually create the subkey
 | 
|---|
| 634 |          */
 | 
|---|
| 635 | 
 | 
|---|
| 636 |         err = create_reg_subkey(key->key, path);
 | 
|---|
| 637 |         if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 638 |                 goto trans_done;
 | 
|---|
| 639 |         }
 | 
|---|
| 640 | 
 | 
|---|
| 641 |         /*
 | 
|---|
| 642 |          * Now open the newly created key
 | 
|---|
| 643 |          */
 | 
|---|
| 644 | 
 | 
|---|
| 645 |         err = reg_openkey(ctx, key, path, desired_access, pkey);
 | 
|---|
| 646 |         if (W_ERROR_IS_OK(err) && (paction != NULL)) {
 | 
|---|
| 647 |                 *paction = REG_CREATED_NEW_KEY;
 | 
|---|
| 648 |         }
 | 
|---|
| 649 | 
 | 
|---|
| 650 | trans_done:
 | 
|---|
| 651 |         if (W_ERROR_IS_OK(err)) {
 | 
|---|
| 652 |                 err = regdb_transaction_commit();
 | 
|---|
| 653 |                 if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 654 |                         DEBUG(0, ("reg_createkey: Error committing transaction: %s\n", win_errstr(err)));
 | 
|---|
| 655 |                 }
 | 
|---|
| 656 |         } else {
 | 
|---|
| 657 |                 WERROR err1 = regdb_transaction_cancel();
 | 
|---|
| 658 |                 if (!W_ERROR_IS_OK(err1)) {
 | 
|---|
| 659 |                         DEBUG(0, ("reg_createkey: Error cancelling transaction: %s\n", win_errstr(err1)));
 | 
|---|
| 660 |                 }
 | 
|---|
| 661 |         }
 | 
|---|
| 662 | 
 | 
|---|
| 663 |  done:
 | 
|---|
| 664 |         TALLOC_FREE(mem_ctx);
 | 
|---|
| 665 |         return err;
 | 
|---|
| 666 | }
 | 
|---|
| 667 | 
 | 
|---|
| 668 | WERROR reg_deletekey(struct registry_key *parent, const char *path)
 | 
|---|
| 669 | {
 | 
|---|
| 670 |         WERROR err;
 | 
|---|
| 671 |         char *name, *end;
 | 
|---|
| 672 |         struct registry_key *tmp_key, *key;
 | 
|---|
| 673 |         TALLOC_CTX *mem_ctx = talloc_stackframe();
 | 
|---|
| 674 | 
 | 
|---|
| 675 |         name = talloc_strdup(mem_ctx, path);
 | 
|---|
| 676 |         if (name == NULL) {
 | 
|---|
| 677 |                 err = WERR_NOMEM;
 | 
|---|
| 678 |                 goto done;
 | 
|---|
| 679 |         }
 | 
|---|
| 680 | 
 | 
|---|
| 681 |         /* check if the key has subkeys */
 | 
|---|
| 682 |         err = reg_openkey(mem_ctx, parent, name, REG_KEY_READ, &key);
 | 
|---|
| 683 |         W_ERROR_NOT_OK_GOTO_DONE(err);
 | 
|---|
| 684 | 
 | 
|---|
| 685 |         err = regdb_transaction_start();
 | 
|---|
| 686 |         if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 687 |                 DEBUG(0, ("reg_deletekey: Error starting transaction: %s\n",
 | 
|---|
| 688 |                           win_errstr(err)));
 | 
|---|
| 689 |                 goto done;
 | 
|---|
| 690 |         }
 | 
|---|
| 691 | 
 | 
|---|
| 692 |         err = fill_subkey_cache(key);
 | 
|---|
| 693 |         W_ERROR_NOT_OK_GOTO(err, trans_done);
 | 
|---|
| 694 | 
 | 
|---|
| 695 |         if (regsubkey_ctr_numkeys(key->subkeys) > 0) {
 | 
|---|
| 696 |                 err = WERR_ACCESS_DENIED;
 | 
|---|
| 697 |                 goto trans_done;
 | 
|---|
| 698 |         }
 | 
|---|
| 699 | 
 | 
|---|
| 700 |         /* no subkeys - proceed with delete */
 | 
|---|
| 701 |         end = strrchr(name, '\\');
 | 
|---|
| 702 |         if (end != NULL) {
 | 
|---|
| 703 |                 *end = '\0';
 | 
|---|
| 704 | 
 | 
|---|
| 705 |                 err = reg_openkey(mem_ctx, parent, name,
 | 
|---|
| 706 |                                   KEY_CREATE_SUB_KEY, &tmp_key);
 | 
|---|
| 707 |                 W_ERROR_NOT_OK_GOTO(err, trans_done);
 | 
|---|
| 708 | 
 | 
|---|
| 709 |                 parent = tmp_key;
 | 
|---|
| 710 |                 name = end+1;
 | 
|---|
| 711 |         }
 | 
|---|
| 712 | 
 | 
|---|
| 713 |         if (name[0] == '\0') {
 | 
|---|
| 714 |                 err = WERR_INVALID_PARAM;
 | 
|---|
| 715 |                 goto trans_done;
 | 
|---|
| 716 |         }
 | 
|---|
| 717 | 
 | 
|---|
| 718 |         err = delete_reg_subkey(parent->key, name);
 | 
|---|
| 719 | 
 | 
|---|
| 720 | trans_done:
 | 
|---|
| 721 |         if (W_ERROR_IS_OK(err)) {
 | 
|---|
| 722 |                 err = regdb_transaction_commit();
 | 
|---|
| 723 |                 if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 724 |                         DEBUG(0, ("reg_deletekey: Error committing transaction: %s\n", win_errstr(err)));
 | 
|---|
| 725 |                 }
 | 
|---|
| 726 |         } else {
 | 
|---|
| 727 |                 WERROR err1 = regdb_transaction_cancel();
 | 
|---|
| 728 |                 if (!W_ERROR_IS_OK(err1)) {
 | 
|---|
| 729 |                         DEBUG(0, ("reg_deletekey: Error cancelling transaction: %s\n", win_errstr(err1)));
 | 
|---|
| 730 |                 }
 | 
|---|
| 731 |         }
 | 
|---|
| 732 | 
 | 
|---|
| 733 | done:
 | 
|---|
| 734 |         TALLOC_FREE(mem_ctx);
 | 
|---|
| 735 |         return err;
 | 
|---|
| 736 | }
 | 
|---|
| 737 | 
 | 
|---|
| 738 | WERROR reg_setvalue(struct registry_key *key, const char *name,
 | 
|---|
| 739 |                     const struct registry_value *val)
 | 
|---|
| 740 | {
 | 
|---|
| 741 |         struct regval_blob *existing;
 | 
|---|
| 742 |         WERROR err;
 | 
|---|
| 743 |         int res;
 | 
|---|
| 744 | 
 | 
|---|
| 745 |         if (!(key->key->access_granted & KEY_SET_VALUE)) {
 | 
|---|
| 746 |                 return WERR_ACCESS_DENIED;
 | 
|---|
| 747 |         }
 | 
|---|
| 748 | 
 | 
|---|
| 749 |         err = regdb_transaction_start();
 | 
|---|
| 750 |         if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 751 |                 DEBUG(0, ("reg_setvalue: Failed to start transaction: %s\n",
 | 
|---|
| 752 |                           win_errstr(err)));
 | 
|---|
| 753 |                 return err;
 | 
|---|
| 754 |         }
 | 
|---|
| 755 | 
 | 
|---|
| 756 |         err = fill_value_cache(key);
 | 
|---|
| 757 |         if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 758 |                 DEBUG(0, ("reg_setvalue: Error filling value cache: %s\n", win_errstr(err)));
 | 
|---|
| 759 |                 goto done;
 | 
|---|
| 760 |         }
 | 
|---|
| 761 | 
 | 
|---|
| 762 |         existing = regval_ctr_getvalue(key->values, name);
 | 
|---|
| 763 | 
 | 
|---|
| 764 |         if ((existing != NULL) &&
 | 
|---|
| 765 |             (regval_size(existing) == val->data.length) &&
 | 
|---|
| 766 |             (memcmp(regval_data_p(existing), val->data.data,
 | 
|---|
| 767 |                     val->data.length) == 0))
 | 
|---|
| 768 |         {
 | 
|---|
| 769 |                 err = WERR_OK;
 | 
|---|
| 770 |                 goto done;
 | 
|---|
| 771 |         }
 | 
|---|
| 772 | 
 | 
|---|
| 773 |         res = regval_ctr_addvalue(key->values, name, val->type,
 | 
|---|
| 774 |                                   val->data.data, val->data.length);
 | 
|---|
| 775 | 
 | 
|---|
| 776 |         if (res == 0) {
 | 
|---|
| 777 |                 TALLOC_FREE(key->values);
 | 
|---|
| 778 |                 err = WERR_NOMEM;
 | 
|---|
| 779 |                 goto done;
 | 
|---|
| 780 |         }
 | 
|---|
| 781 | 
 | 
|---|
| 782 |         if (!store_reg_values(key->key, key->values)) {
 | 
|---|
| 783 |                 TALLOC_FREE(key->values);
 | 
|---|
| 784 |                 DEBUG(0, ("reg_setvalue: store_reg_values failed\n"));
 | 
|---|
| 785 |                 err = WERR_REG_IO_FAILURE;
 | 
|---|
| 786 |                 goto done;
 | 
|---|
| 787 |         }
 | 
|---|
| 788 | 
 | 
|---|
| 789 |         err = WERR_OK;
 | 
|---|
| 790 | 
 | 
|---|
| 791 | done:
 | 
|---|
| 792 |         if (W_ERROR_IS_OK(err)) {
 | 
|---|
| 793 |                 err = regdb_transaction_commit();
 | 
|---|
| 794 |                 if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 795 |                         DEBUG(0, ("reg_setvalue: Error committing transaction: %s\n", win_errstr(err)));
 | 
|---|
| 796 |                 }
 | 
|---|
| 797 |         } else {
 | 
|---|
| 798 |                 WERROR err1 = regdb_transaction_cancel();
 | 
|---|
| 799 |                 if (!W_ERROR_IS_OK(err1)) {
 | 
|---|
| 800 |                         DEBUG(0, ("reg_setvalue: Error cancelling transaction: %s\n", win_errstr(err1)));
 | 
|---|
| 801 |                 }
 | 
|---|
| 802 |         }
 | 
|---|
| 803 | 
 | 
|---|
| 804 |         return err;
 | 
|---|
| 805 | }
 | 
|---|
| 806 | 
 | 
|---|
| 807 | static WERROR reg_value_exists(struct registry_key *key, const char *name)
 | 
|---|
| 808 | {
 | 
|---|
| 809 |         struct regval_blob *blob;
 | 
|---|
| 810 | 
 | 
|---|
| 811 |         blob = regval_ctr_getvalue(key->values, name);
 | 
|---|
| 812 | 
 | 
|---|
| 813 |         if (blob == NULL) {
 | 
|---|
| 814 |                 return WERR_BADFILE;
 | 
|---|
| 815 |         } else {
 | 
|---|
| 816 |                 return WERR_OK;
 | 
|---|
| 817 |         }
 | 
|---|
| 818 | }
 | 
|---|
| 819 | 
 | 
|---|
| 820 | WERROR reg_deletevalue(struct registry_key *key, const char *name)
 | 
|---|
| 821 | {
 | 
|---|
| 822 |         WERROR err;
 | 
|---|
| 823 | 
 | 
|---|
| 824 |         if (!(key->key->access_granted & KEY_SET_VALUE)) {
 | 
|---|
| 825 |                 return WERR_ACCESS_DENIED;
 | 
|---|
| 826 |         }
 | 
|---|
| 827 | 
 | 
|---|
| 828 |         err = regdb_transaction_start();
 | 
|---|
| 829 |         if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 830 |                 DEBUG(0, ("reg_deletevalue: Failed to start transaction: %s\n",
 | 
|---|
| 831 |                           win_errstr(err)));
 | 
|---|
| 832 |                 return err;
 | 
|---|
| 833 |         }
 | 
|---|
| 834 | 
 | 
|---|
| 835 |         err = fill_value_cache(key);
 | 
|---|
| 836 |         if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 837 |                 DEBUG(0, ("reg_deletevalue; Error filling value cache: %s\n",
 | 
|---|
| 838 |                           win_errstr(err)));
 | 
|---|
| 839 |                 goto done;
 | 
|---|
| 840 |         }
 | 
|---|
| 841 | 
 | 
|---|
| 842 |         err = reg_value_exists(key, name);
 | 
|---|
| 843 |         if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 844 |                 goto done;
 | 
|---|
| 845 |         }
 | 
|---|
| 846 | 
 | 
|---|
| 847 |         regval_ctr_delvalue(key->values, name);
 | 
|---|
| 848 | 
 | 
|---|
| 849 |         if (!store_reg_values(key->key, key->values)) {
 | 
|---|
| 850 |                 TALLOC_FREE(key->values);
 | 
|---|
| 851 |                 err = WERR_REG_IO_FAILURE;
 | 
|---|
| 852 |                 DEBUG(0, ("reg_deletevalue: store_reg_values failed\n"));
 | 
|---|
| 853 |                 goto done;
 | 
|---|
| 854 |         }
 | 
|---|
| 855 | 
 | 
|---|
| 856 |         err = WERR_OK;
 | 
|---|
| 857 | 
 | 
|---|
| 858 | done:
 | 
|---|
| 859 |         if (W_ERROR_IS_OK(err)) {
 | 
|---|
| 860 |                 err = regdb_transaction_commit();
 | 
|---|
| 861 |                 if (!W_ERROR_IS_OK(err)) {
 | 
|---|
| 862 |                         DEBUG(0, ("reg_deletevalue: Error committing transaction: %s\n", win_errstr(err)));
 | 
|---|
| 863 |                 }
 | 
|---|
| 864 |         } else {
 | 
|---|
| 865 |                 WERROR err1 = regdb_transaction_cancel();
 | 
|---|
| 866 |                 if (!W_ERROR_IS_OK(err1)) {
 | 
|---|
| 867 |                         DEBUG(0, ("reg_deletevalue: Error cancelling transaction: %s\n", win_errstr(err1)));
 | 
|---|
| 868 |                 }
 | 
|---|
| 869 |         }
 | 
|---|
| 870 | 
 | 
|---|
| 871 |         return err;
 | 
|---|
| 872 | }
 | 
|---|
| 873 | 
 | 
|---|
| 874 | WERROR reg_getkeysecurity(TALLOC_CTX *mem_ctx, struct registry_key *key,
 | 
|---|
| 875 |                           struct security_descriptor **psecdesc)
 | 
|---|
| 876 | {
 | 
|---|
| 877 |         return regkey_get_secdesc(mem_ctx, key->key, psecdesc);
 | 
|---|
| 878 | }
 | 
|---|
| 879 | 
 | 
|---|
| 880 | WERROR reg_setkeysecurity(struct registry_key *key,
 | 
|---|
| 881 |                           struct security_descriptor *psecdesc)
 | 
|---|
| 882 | {
 | 
|---|
| 883 |         return regkey_set_secdesc(key->key, psecdesc);
 | 
|---|
| 884 | }
 | 
|---|
| 885 | 
 | 
|---|
| 886 | WERROR reg_getversion(uint32_t *version)
 | 
|---|
| 887 | {
 | 
|---|
| 888 |         if (version == NULL) {
 | 
|---|
| 889 |                 return WERR_INVALID_PARAM;
 | 
|---|
| 890 |         }
 | 
|---|
| 891 | 
 | 
|---|
| 892 |         *version = 0x00000005; /* Windows 2000 registry API version */
 | 
|---|
| 893 |         return WERR_OK;
 | 
|---|
| 894 | }
 | 
|---|
| 895 | 
 | 
|---|
| 896 | /**********************************************************************
 | 
|---|
| 897 |  * Higher level utility functions
 | 
|---|
| 898 |  **********************************************************************/
 | 
|---|
| 899 | 
 | 
|---|
| 900 | WERROR reg_deleteallvalues(struct registry_key *key)
 | 
|---|
| 901 | {
 | 
|---|
| 902 |         WERROR err;
 | 
|---|
| 903 |         int i;
 | 
|---|
| 904 | 
 | 
|---|
| 905 |         if (!(key->key->access_granted & KEY_SET_VALUE)) {
 | 
|---|
| 906 |                 return WERR_ACCESS_DENIED;
 | 
|---|
| 907 |         }
 | 
|---|
| 908 | 
 | 
|---|
| 909 |         if (!W_ERROR_IS_OK(err = fill_value_cache(key))) {
 | 
|---|
| 910 |                 return err;
 | 
|---|
| 911 |         }
 | 
|---|
| 912 | 
 | 
|---|
| 913 |         for (i=0; i < regval_ctr_numvals(key->values); i++) {
 | 
|---|
| 914 |                 struct regval_blob *blob;
 | 
|---|
| 915 |                 blob = regval_ctr_specific_value(key->values, i);
 | 
|---|
| 916 |                 regval_ctr_delvalue(key->values, regval_name(blob));
 | 
|---|
| 917 |         }
 | 
|---|
| 918 | 
 | 
|---|
| 919 |         if (!store_reg_values(key->key, key->values)) {
 | 
|---|
| 920 |                 TALLOC_FREE(key->values);
 | 
|---|
| 921 |                 return WERR_REG_IO_FAILURE;
 | 
|---|
| 922 |         }
 | 
|---|
| 923 | 
 | 
|---|
| 924 |         return WERR_OK;
 | 
|---|
| 925 | }
 | 
|---|
| 926 | 
 | 
|---|
| 927 | /*
 | 
|---|
| 928 |  * Utility function to delete a registry key with all its subkeys.
 | 
|---|
| 929 |  * Note that reg_deletekey returns ACCESS_DENIED when called on a
 | 
|---|
| 930 |  * key that has subkeys.
 | 
|---|
| 931 |  */
 | 
|---|
| 932 | static WERROR reg_deletekey_recursive_internal(struct registry_key *parent,
 | 
|---|
| 933 |                                                const char *path,
 | 
|---|
| 934 |                                                bool del_key)
 | 
|---|
| 935 | {
 | 
|---|
| 936 |         WERROR werr = WERR_OK;
 | 
|---|
| 937 |         struct registry_key *key;
 | 
|---|
| 938 |         char *subkey_name = NULL;
 | 
|---|
| 939 |         uint32 i;
 | 
|---|
| 940 |         TALLOC_CTX *mem_ctx = talloc_stackframe();
 | 
|---|
| 941 | 
 | 
|---|
| 942 |         /* recurse through subkeys first */
 | 
|---|
| 943 |         werr = reg_openkey(mem_ctx, parent, path, REG_KEY_ALL, &key);
 | 
|---|
| 944 |         if (!W_ERROR_IS_OK(werr)) {
 | 
|---|
| 945 |                 goto done;
 | 
|---|
| 946 |         }
 | 
|---|
| 947 | 
 | 
|---|
| 948 |         werr = fill_subkey_cache(key);
 | 
|---|
| 949 |         W_ERROR_NOT_OK_GOTO_DONE(werr);
 | 
|---|
| 950 | 
 | 
|---|
| 951 |         /*
 | 
|---|
| 952 |          * loop from top to bottom for perfomance:
 | 
|---|
| 953 |          * this way, we need to rehash the regsubkey containers less
 | 
|---|
| 954 |          */
 | 
|---|
| 955 |         for (i = regsubkey_ctr_numkeys(key->subkeys) ; i > 0; i--) {
 | 
|---|
| 956 |                 subkey_name = regsubkey_ctr_specific_key(key->subkeys, i-1);
 | 
|---|
| 957 |                 werr = reg_deletekey_recursive_internal(key, subkey_name, true);
 | 
|---|
| 958 |                 W_ERROR_NOT_OK_GOTO_DONE(werr);
 | 
|---|
| 959 |         }
 | 
|---|
| 960 | 
 | 
|---|
| 961 |         if (del_key) {
 | 
|---|
| 962 |                 /* now delete the actual key */
 | 
|---|
| 963 |                 werr = reg_deletekey(parent, path);
 | 
|---|
| 964 |         }
 | 
|---|
| 965 | 
 | 
|---|
| 966 | done:
 | 
|---|
| 967 |         TALLOC_FREE(mem_ctx);
 | 
|---|
| 968 |         return werr;
 | 
|---|
| 969 | }
 | 
|---|
| 970 | 
 | 
|---|
| 971 | static WERROR reg_deletekey_recursive_trans(struct registry_key *parent,
 | 
|---|
| 972 |                                             const char *path,
 | 
|---|
| 973 |                                             bool del_key)
 | 
|---|
| 974 | {
 | 
|---|
| 975 |         WERROR werr;
 | 
|---|
| 976 | 
 | 
|---|
| 977 |         werr = regdb_transaction_start();
 | 
|---|
| 978 |         if (!W_ERROR_IS_OK(werr)) {
 | 
|---|
| 979 |                 DEBUG(0, ("reg_deletekey_recursive_trans: "
 | 
|---|
| 980 |                           "error starting transaction: %s\n",
 | 
|---|
| 981 |                           win_errstr(werr)));
 | 
|---|
| 982 |                 return werr;
 | 
|---|
| 983 |         }
 | 
|---|
| 984 | 
 | 
|---|
| 985 |         werr = reg_deletekey_recursive_internal(parent, path, del_key);
 | 
|---|
| 986 | 
 | 
|---|
| 987 |         if (!W_ERROR_IS_OK(werr)) {
 | 
|---|
| 988 |                 WERROR werr2;
 | 
|---|
| 989 | 
 | 
|---|
| 990 |                 DEBUG(1, (__location__ " failed to delete key '%s' from key "
 | 
|---|
| 991 |                           "'%s': %s\n", path, parent->key->name,
 | 
|---|
| 992 |                           win_errstr(werr)));
 | 
|---|
| 993 | 
 | 
|---|
| 994 |                 werr2 = regdb_transaction_cancel();
 | 
|---|
| 995 |                 if (!W_ERROR_IS_OK(werr2)) {
 | 
|---|
| 996 |                         DEBUG(0, ("reg_deletekey_recursive_trans: "
 | 
|---|
| 997 |                                   "error cancelling transaction: %s\n",
 | 
|---|
| 998 |                                   win_errstr(werr2)));
 | 
|---|
| 999 |                         /*
 | 
|---|
| 1000 |                          * return the original werr or the
 | 
|---|
| 1001 |                          * error from cancelling the transaction?
 | 
|---|
| 1002 |                          */
 | 
|---|
| 1003 |                 }
 | 
|---|
| 1004 |         } else {
 | 
|---|
| 1005 |                 werr = regdb_transaction_commit();
 | 
|---|
| 1006 |                 if (!W_ERROR_IS_OK(werr)) {
 | 
|---|
| 1007 |                         DEBUG(0, ("reg_deletekey_recursive_trans: "
 | 
|---|
| 1008 |                                   "error committing transaction: %s\n",
 | 
|---|
| 1009 |                                   win_errstr(werr)));
 | 
|---|
| 1010 |                 }
 | 
|---|
| 1011 |         }
 | 
|---|
| 1012 | 
 | 
|---|
| 1013 |         return werr;
 | 
|---|
| 1014 | }
 | 
|---|
| 1015 | 
 | 
|---|
| 1016 | WERROR reg_deletekey_recursive(struct registry_key *parent,
 | 
|---|
| 1017 |                                const char *path)
 | 
|---|
| 1018 | {
 | 
|---|
| 1019 |         return reg_deletekey_recursive_trans(parent, path, true);
 | 
|---|
| 1020 | }
 | 
|---|
| 1021 | 
 | 
|---|
| 1022 | WERROR reg_deletesubkeys_recursive(struct registry_key *parent,
 | 
|---|
| 1023 |                                    const char *path)
 | 
|---|
| 1024 | {
 | 
|---|
| 1025 |         return reg_deletekey_recursive_trans(parent, path, false);
 | 
|---|
| 1026 | }
 | 
|---|
| 1027 | 
 | 
|---|