2 * Unix SMB/CIFS implementation.
3 * Virtual Windows Registry Layer
4 * Copyright (C) Volker Lendecke 2006
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 /* Attempt to wrap the existing API in a more winreg.idl-like way */
25 #define DBGC_CLASS DBGC_REGISTRY
27 static WERROR
fill_value_cache(struct registry_key
*key
)
29 if (key
->values
!= NULL
) {
33 if (!(key
->values
= TALLOC_ZERO_P(key
, REGVAL_CTR
))) {
36 if (fetch_reg_values(key
->key
, key
->values
) == -1) {
37 TALLOC_FREE(key
->values
);
44 static WERROR
fill_subkey_cache(struct registry_key
*key
)
46 if (key
->subkeys
!= NULL
) {
50 if (!(key
->subkeys
= TALLOC_ZERO_P(key
, REGSUBKEY_CTR
))) {
54 if (fetch_reg_keys(key
->key
, key
->subkeys
) == -1) {
55 TALLOC_FREE(key
->subkeys
);
56 return WERR_NO_MORE_ITEMS
;
62 static int regkey_destructor(REGISTRY_KEY
*key
)
67 static WERROR
regkey_open_onelevel(TALLOC_CTX
*mem_ctx
,
68 struct registry_key
*parent
,
70 const struct nt_user_token
*token
,
71 uint32 access_desired
,
72 struct registry_key
**pregkey
)
74 WERROR result
= WERR_OK
;
75 struct registry_key
*regkey
;
77 REGSUBKEY_CTR
*subkeys
= NULL
;
79 DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name
));
81 SMB_ASSERT(strchr(name
, '\\') == NULL
);
83 if (!(regkey
= TALLOC_ZERO_P(mem_ctx
, struct registry_key
)) ||
84 !(regkey
->token
= dup_nt_token(regkey
, token
)) ||
85 !(regkey
->key
= TALLOC_ZERO_P(regkey
, REGISTRY_KEY
))) {
90 if ( !(W_ERROR_IS_OK(result
= regdb_open())) ) {
95 talloc_set_destructor(key
, regkey_destructor
);
99 key
->type
= REG_KEY_GENERIC
;
101 if (name
[0] == '\0') {
103 * Open a copy of the parent key
106 result
= WERR_BADFILE
;
109 key
->name
= talloc_strdup(key
, parent
->key
->name
);
115 key
->name
= talloc_asprintf(key
, "%s%s%s",
116 parent
? parent
->key
->name
: "",
121 if (key
->name
== NULL
) {
126 /* Tag this as a Performance Counter Key */
128 if( StrnCaseCmp(key
->name
, KEY_HKPD
, strlen(KEY_HKPD
)) == 0 )
129 key
->type
= REG_KEY_HKPD
;
131 /* Look up the table of registry I/O operations */
133 if ( !(key
->hook
= reghook_cache_find( key
->name
)) ) {
134 DEBUG(0,("reg_open_onelevel: Failed to assigned a "
135 "REGISTRY_HOOK to [%s]\n", key
->name
));
136 result
= WERR_BADFILE
;
140 /* check if the path really exists; failed is indicated by -1 */
141 /* if the subkey count failed, bail out */
143 if ( !(subkeys
= TALLOC_ZERO_P( key
, REGSUBKEY_CTR
)) ) {
148 if ( fetch_reg_keys( key
, subkeys
) == -1 ) {
149 result
= WERR_BADFILE
;
153 TALLOC_FREE( subkeys
);
155 if ( !regkey_access_check( key
, access_desired
, &key
->access_granted
,
157 result
= WERR_ACCESS_DENIED
;
165 if ( !W_ERROR_IS_OK(result
) ) {
172 WERROR
reg_openhive(TALLOC_CTX
*mem_ctx
, const char *hive
,
173 uint32 desired_access
,
174 const struct nt_user_token
*token
,
175 struct registry_key
**pkey
)
177 SMB_ASSERT(hive
!= NULL
);
178 SMB_ASSERT(hive
[0] != '\0');
179 SMB_ASSERT(strchr(hive
, '\\') == NULL
);
181 return regkey_open_onelevel(mem_ctx
, NULL
, hive
, token
, desired_access
,
185 WERROR
reg_openkey(TALLOC_CTX
*mem_ctx
, struct registry_key
*parent
,
186 const char *name
, uint32 desired_access
,
187 struct registry_key
**pkey
)
189 struct registry_key
*direct_parent
= parent
;
191 char *p
, *path
, *to_free
;
194 if (!(path
= SMB_STRDUP(name
))) {
201 if ((len
> 0) && (path
[len
-1] == '\\')) {
205 while ((p
= strchr(path
, '\\')) != NULL
) {
206 char *name_component
;
207 struct registry_key
*tmp
;
209 if (!(name_component
= SMB_STRNDUP(path
, (p
- path
)))) {
214 err
= regkey_open_onelevel(mem_ctx
, direct_parent
,
215 name_component
, parent
->token
,
216 SEC_RIGHTS_ENUM_SUBKEYS
, &tmp
);
217 SAFE_FREE(name_component
);
219 if (!W_ERROR_IS_OK(err
)) {
222 if (direct_parent
!= parent
) {
223 TALLOC_FREE(direct_parent
);
230 err
= regkey_open_onelevel(mem_ctx
, direct_parent
, path
, parent
->token
,
231 desired_access
, pkey
);
233 if (direct_parent
!= parent
) {
234 TALLOC_FREE(direct_parent
);
240 WERROR
reg_enumkey(TALLOC_CTX
*mem_ctx
, struct registry_key
*key
,
241 uint32 idx
, char **name
, NTTIME
*last_write_time
)
245 if (!(key
->key
->access_granted
& SEC_RIGHTS_ENUM_SUBKEYS
)) {
246 return WERR_ACCESS_DENIED
;
249 if (!W_ERROR_IS_OK(err
= fill_subkey_cache(key
))) {
253 if (idx
>= key
->subkeys
->num_subkeys
) {
254 return WERR_NO_MORE_ITEMS
;
257 if (!(*name
= talloc_strdup(mem_ctx
, key
->subkeys
->subkeys
[idx
]))) {
261 if (last_write_time
) {
262 *last_write_time
= 0;
268 WERROR
reg_enumvalue(TALLOC_CTX
*mem_ctx
, struct registry_key
*key
,
269 uint32 idx
, char **pname
, struct registry_value
**pval
)
271 struct registry_value
*val
;
274 if (!(key
->key
->access_granted
& SEC_RIGHTS_QUERY_VALUE
)) {
275 return WERR_ACCESS_DENIED
;
278 if (!(W_ERROR_IS_OK(err
= fill_value_cache(key
)))) {
282 if (idx
>= key
->values
->num_values
) {
283 return WERR_NO_MORE_ITEMS
;
286 err
= registry_pull_value(mem_ctx
, &val
,
287 key
->values
->values
[idx
]->type
,
288 key
->values
->values
[idx
]->data_p
,
289 key
->values
->values
[idx
]->size
,
290 key
->values
->values
[idx
]->size
);
291 if (!W_ERROR_IS_OK(err
)) {
296 && !(*pname
= talloc_strdup(
297 mem_ctx
, key
->values
->values
[idx
]->valuename
))) {
306 WERROR
reg_queryvalue(TALLOC_CTX
*mem_ctx
, struct registry_key
*key
,
307 const char *name
, struct registry_value
**pval
)
312 if (!(key
->key
->access_granted
& SEC_RIGHTS_QUERY_VALUE
)) {
313 return WERR_ACCESS_DENIED
;
316 if (!(W_ERROR_IS_OK(err
= fill_value_cache(key
)))) {
320 for (i
=0; i
<key
->values
->num_values
; i
++) {
321 if (strequal(key
->values
->values
[i
]->valuename
, name
)) {
322 return reg_enumvalue(mem_ctx
, key
, i
, NULL
, pval
);
329 WERROR
reg_queryinfokey(struct registry_key
*key
, uint32_t *num_subkeys
,
330 uint32_t *max_subkeylen
, uint32_t *max_subkeysize
,
331 uint32_t *num_values
, uint32_t *max_valnamelen
,
332 uint32_t *max_valbufsize
, uint32_t *secdescsize
,
333 NTTIME
*last_changed_time
)
339 struct security_descriptor
*secdesc
;
341 if (!(key
->key
->access_granted
& SEC_RIGHTS_QUERY_VALUE
)) {
342 return WERR_ACCESS_DENIED
;
345 if (!W_ERROR_IS_OK(fill_subkey_cache(key
)) ||
346 !W_ERROR_IS_OK(fill_value_cache(key
))) {
351 for (i
=0; i
<key
->subkeys
->num_subkeys
; i
++) {
352 max_len
= MAX(max_len
, strlen(key
->subkeys
->subkeys
[i
]));
355 *num_subkeys
= key
->subkeys
->num_subkeys
;
356 *max_subkeylen
= max_len
;
357 *max_subkeysize
= 0; /* Class length? */
361 for (i
=0; i
<key
->values
->num_values
; i
++) {
362 max_len
= MAX(max_len
,
363 strlen(key
->values
->values
[i
]->valuename
));
364 max_size
= MAX(max_size
, key
->values
->values
[i
]->size
);
367 *num_values
= key
->values
->num_values
;
368 *max_valnamelen
= max_len
;
369 *max_valbufsize
= max_size
;
371 if (!(mem_ctx
= talloc_new(key
))) {
375 err
= regkey_get_secdesc(mem_ctx
, key
->key
, &secdesc
);
376 if (!W_ERROR_IS_OK(err
)) {
377 TALLOC_FREE(mem_ctx
);
381 *secdescsize
= sec_desc_size(secdesc
);
382 TALLOC_FREE(mem_ctx
);
384 *last_changed_time
= 0;
389 WERROR
reg_createkey(TALLOC_CTX
*ctx
, struct registry_key
*parent
,
390 const char *subkeypath
, uint32 desired_access
,
391 struct registry_key
**pkey
,
392 enum winreg_CreateAction
*paction
)
394 struct registry_key
*key
= parent
;
395 struct registry_key
*create_parent
;
399 REGSUBKEY_CTR
*subkeys
;
401 if (!(mem_ctx
= talloc_new(ctx
))) return WERR_NOMEM
;
403 if (!(path
= talloc_strdup(mem_ctx
, subkeypath
))) {
408 while ((end
= strchr(path
, '\\')) != NULL
) {
409 struct registry_key
*tmp
;
410 enum winreg_CreateAction action
;
414 err
= reg_createkey(mem_ctx
, key
, path
,
415 SEC_RIGHTS_ENUM_SUBKEYS
, &tmp
, &action
);
416 if (!W_ERROR_IS_OK(err
)) {
429 * At this point, "path" contains the one-element subkey of "key". We
430 * can try to open it.
433 err
= reg_openkey(ctx
, key
, path
, desired_access
, pkey
);
434 if (W_ERROR_IS_OK(err
)) {
435 if (paction
!= NULL
) {
436 *paction
= REG_OPENED_EXISTING_KEY
;
441 if (!W_ERROR_EQUAL(err
, WERR_BADFILE
)) {
443 * Something but "notfound" has happened, so bail out
449 * We have to make a copy of the current key, as we opened it only
450 * with ENUM_SUBKEY access.
453 err
= reg_openkey(mem_ctx
, key
, "", SEC_RIGHTS_CREATE_SUBKEY
,
455 if (!W_ERROR_IS_OK(err
)) {
460 * Actually create the subkey
463 if (!(subkeys
= TALLOC_ZERO_P(mem_ctx
, REGSUBKEY_CTR
))) {
468 err
= fill_subkey_cache(create_parent
);
469 if (!W_ERROR_IS_OK(err
)) goto done
;
471 err
= regsubkey_ctr_addkey(create_parent
->subkeys
, path
);
472 if (!W_ERROR_IS_OK(err
)) goto done
;
474 if (!store_reg_keys(create_parent
->key
, create_parent
->subkeys
)) {
475 TALLOC_FREE(create_parent
->subkeys
);
476 err
= WERR_REG_IO_FAILURE
;
481 * Now open the newly created key
484 err
= reg_openkey(ctx
, create_parent
, path
, desired_access
, pkey
);
485 if (W_ERROR_IS_OK(err
) && (paction
!= NULL
)) {
486 *paction
= REG_CREATED_NEW_KEY
;
490 TALLOC_FREE(mem_ctx
);
495 WERROR
reg_deletekey(struct registry_key
*parent
, const char *path
)
501 struct registry_key
*tmp_key
, *key
;
503 if (!(mem_ctx
= talloc_init("reg_createkey"))) return WERR_NOMEM
;
505 if (!(name
= talloc_strdup(mem_ctx
, path
))) {
510 /* check if the key has subkeys */
511 err
= reg_openkey(mem_ctx
, parent
, name
, REG_KEY_READ
, &key
);
512 if (!W_ERROR_IS_OK(err
)) {
515 if (!W_ERROR_IS_OK(err
= fill_subkey_cache(key
))) {
518 if (key
->subkeys
->num_subkeys
> 0) {
519 err
= WERR_ACCESS_DENIED
;
523 /* no subkeys - proceed with delete */
524 if ((end
= strrchr(name
, '\\')) != NULL
) {
527 err
= reg_openkey(mem_ctx
, parent
, name
,
528 SEC_RIGHTS_CREATE_SUBKEY
, &tmp_key
);
529 if (!W_ERROR_IS_OK(err
)) {
537 if (name
[0] == '\0') {
538 err
= WERR_INVALID_PARAM
;
542 if (!W_ERROR_IS_OK(err
= fill_subkey_cache(parent
))) {
546 num_subkeys
= parent
->subkeys
->num_subkeys
;
548 if (regsubkey_ctr_delkey(parent
->subkeys
, name
) == num_subkeys
) {
553 if (!store_reg_keys(parent
->key
, parent
->subkeys
)) {
554 TALLOC_FREE(parent
->subkeys
);
555 err
= WERR_REG_IO_FAILURE
;
559 regkey_set_secdesc(key
->key
, NULL
);
564 TALLOC_FREE(mem_ctx
);
568 WERROR
reg_setvalue(struct registry_key
*key
, const char *name
,
569 const struct registry_value
*val
)
572 DATA_BLOB value_data
;
575 if (!(key
->key
->access_granted
& SEC_RIGHTS_SET_VALUE
)) {
576 return WERR_ACCESS_DENIED
;
579 if (!W_ERROR_IS_OK(err
= fill_value_cache(key
))) {
583 err
= registry_push_value(key
, val
, &value_data
);
584 if (!W_ERROR_IS_OK(err
)) {
588 res
= regval_ctr_addvalue(key
->values
, name
, val
->type
,
589 (char *)value_data
.data
, value_data
.length
);
590 TALLOC_FREE(value_data
.data
);
593 TALLOC_FREE(key
->values
);
597 if (!store_reg_values(key
->key
, key
->values
)) {
598 TALLOC_FREE(key
->values
);
599 return WERR_REG_IO_FAILURE
;
605 WERROR
reg_deletevalue(struct registry_key
*key
, const char *name
)
609 if (!(key
->key
->access_granted
& SEC_RIGHTS_SET_VALUE
)) {
610 return WERR_ACCESS_DENIED
;
613 if (!W_ERROR_IS_OK(err
= fill_value_cache(key
))) {
617 regval_ctr_delvalue(key
->values
, name
);
619 if (!store_reg_values(key
->key
, key
->values
)) {
620 TALLOC_FREE(key
->values
);
621 return WERR_REG_IO_FAILURE
;
627 WERROR
reg_deleteallvalues(struct registry_key
*key
)
632 if (!(key
->key
->access_granted
& SEC_RIGHTS_SET_VALUE
)) {
633 return WERR_ACCESS_DENIED
;
636 if (!W_ERROR_IS_OK(err
= fill_value_cache(key
))) {
640 for (i
=0; i
<key
->values
->num_values
; i
++) {
641 regval_ctr_delvalue(key
->values
, key
->values
->values
[i
]->valuename
);
644 if (!store_reg_values(key
->key
, key
->values
)) {
645 TALLOC_FREE(key
->values
);
646 return WERR_REG_IO_FAILURE
;
653 * Utility function to open a complete registry path including the hive
654 * prefix. This should become the replacement function for
655 * regkey_open_internal.
658 WERROR
reg_open_path(TALLOC_CTX
*mem_ctx
, const char *orig_path
,
659 uint32 desired_access
, const struct nt_user_token
*token
,
660 struct registry_key
**pkey
)
662 struct registry_key
*hive
, *key
;
666 if (!(path
= SMB_STRDUP(orig_path
))) {
670 p
= strchr(path
, '\\');
672 if ((p
== NULL
) || (p
[1] == '\0')) {
674 * No key behind the hive, just return the hive
677 err
= reg_openhive(mem_ctx
, path
, desired_access
, token
,
679 if (!W_ERROR_IS_OK(err
)) {
690 err
= reg_openhive(mem_ctx
, path
, SEC_RIGHTS_ENUM_SUBKEYS
, token
,
692 if (!W_ERROR_IS_OK(err
)) {
697 err
= reg_openkey(mem_ctx
, hive
, p
+1, desired_access
, &key
);
702 if (!W_ERROR_IS_OK(err
)) {
711 * Utility function to delete a registry key with all its subkeys.
712 * Note that reg_deletekey returns ACCESS_DENIED when called on a
713 * key that has subkeys.
715 WERROR
reg_deletekey_recursive_internal(TALLOC_CTX
*ctx
,
716 struct registry_key
*parent
,
720 TALLOC_CTX
*mem_ctx
= NULL
;
721 WERROR werr
= WERR_OK
;
722 struct registry_key
*key
;
723 char *subkey_name
= NULL
;
725 mem_ctx
= talloc_new(ctx
);
726 if (mem_ctx
== NULL
) {
731 /* recurse through subkeys first */
732 werr
= reg_openkey(mem_ctx
, parent
, path
, REG_KEY_WRITE
, &key
);
733 if (!W_ERROR_IS_OK(werr
)) {
737 while (W_ERROR_IS_OK(werr
= reg_enumkey(mem_ctx
, key
, 0,
738 &subkey_name
, NULL
)))
740 werr
= reg_deletekey_recursive_internal(mem_ctx
, key
,
743 if (!W_ERROR_IS_OK(werr
)) {
747 if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS
, werr
)) {
748 DEBUG(1, ("reg_deletekey_recursive_internal: "
749 "Error enumerating subkeys: %s\n",
757 /* now delete the actual key */
758 werr
= reg_deletekey(parent
, path
);
762 TALLOC_FREE(mem_ctx
);
766 WERROR
reg_deletekey_recursive(TALLOC_CTX
*ctx
,
767 struct registry_key
*parent
,
770 return reg_deletekey_recursive_internal(ctx
, parent
, path
, True
);
773 WERROR
reg_deletesubkeys_recursive(TALLOC_CTX
*ctx
,
774 struct registry_key
*parent
,
777 return reg_deletekey_recursive_internal(ctx
, parent
, path
, False
);