2 * Unix SMB/CIFS implementation.
3 * Virtual Windows Registry Layer
4 * Copyright (C) Gerald Carter 2002-2005
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 2 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, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* Implementation of registry frontend view functions. */
26 #define DBGC_CLASS DBGC_RPC_SRV
28 extern REGISTRY_OPS printing_ops
;
29 extern REGISTRY_OPS eventlog_ops
;
30 extern REGISTRY_OPS shares_reg_ops
;
31 extern REGISTRY_OPS smbconf_reg_ops
;
32 extern REGISTRY_OPS regdb_ops
; /* these are the default */
34 /* array of REGISTRY_HOOK's which are read into a tree for easy access */
35 /* #define REG_TDB_ONLY 1 */
37 REGISTRY_HOOK reg_hooks
[] = {
39 { KEY_PRINTING
, &printing_ops
},
40 { KEY_PRINTING_2K
, &printing_ops
},
41 { KEY_PRINTING_PORTS
, &printing_ops
},
42 { KEY_SHARES
, &shares_reg_ops
},
43 { KEY_SMBCONF
, &smbconf_reg_ops
},
49 static struct generic_mapping reg_generic_map
=
50 { REG_KEY_READ
, REG_KEY_WRITE
, REG_KEY_EXECUTE
, REG_KEY_ALL
};
52 /********************************************************************
53 ********************************************************************/
55 static SEC_DESC
* construct_registry_sd( TALLOC_CTX
*ctx
)
64 /* basic access for Everyone */
66 init_sec_access(&mask
, REG_KEY_READ
);
67 init_sec_ace(&ace
[i
++], &global_sid_World
, SEC_ACE_TYPE_ACCESS_ALLOWED
, mask
, 0);
69 /* Full Access 'BUILTIN\Administrators' */
71 init_sec_access(&mask
, REG_KEY_ALL
);
72 init_sec_ace(&ace
[i
++], &global_sid_Builtin_Administrators
, SEC_ACE_TYPE_ACCESS_ALLOWED
, mask
, 0);
75 /* create the security descriptor */
77 if ( !(acl
= make_sec_acl(ctx
, NT4_ACL_REVISION
, i
, ace
)) )
80 if ( !(sd
= make_sec_desc(ctx
, SEC_DESC_REVISION
, SEC_DESC_SELF_RELATIVE
, NULL
, NULL
, NULL
, acl
, &sd_size
)) )
87 /***********************************************************************
88 Open the registry database and initialize the REGISTRY_HOOK cache
89 ***********************************************************************/
91 BOOL
init_registry( void )
96 if ( !regdb_init() ) {
97 DEBUG(0,("init_registry: failed to initialize the registry tdb!\n"));
101 /* build the cache tree of registry hooks */
103 reghook_cache_init();
105 for ( i
=0; reg_hooks
[i
].keyname
; i
++ ) {
106 if ( !reghook_cache_add(®_hooks
[i
]) )
110 if ( DEBUGLEVEL
>= 20 )
111 reghook_dump_cache(20);
113 /* add any keys for other services */
116 eventlog_init_keys();
117 perfcount_init_keys();
119 /* close and let each smbd open up as necessary */
126 /***********************************************************************
127 High level wrapper function for storing registry subkeys
128 ***********************************************************************/
130 BOOL
store_reg_keys( REGISTRY_KEY
*key
, REGSUBKEY_CTR
*subkeys
)
132 if ( key
->hook
&& key
->hook
->ops
&& key
->hook
->ops
->store_subkeys
)
133 return key
->hook
->ops
->store_subkeys( key
->name
, subkeys
);
139 /***********************************************************************
140 High level wrapper function for storing registry values
141 ***********************************************************************/
143 BOOL
store_reg_values( REGISTRY_KEY
*key
, REGVAL_CTR
*val
)
145 if ( check_dynamic_reg_values( key
) )
148 if ( key
->hook
&& key
->hook
->ops
&& key
->hook
->ops
->store_values
)
149 return key
->hook
->ops
->store_values( key
->name
, val
);
155 /***********************************************************************
156 High level wrapper function for enumerating registry subkeys
157 Initialize the TALLOC_CTX if necessary
158 ***********************************************************************/
160 int fetch_reg_keys( REGISTRY_KEY
*key
, REGSUBKEY_CTR
*subkey_ctr
)
164 if ( key
->hook
&& key
->hook
->ops
&& key
->hook
->ops
->fetch_subkeys
)
165 result
= key
->hook
->ops
->fetch_subkeys( key
->name
, subkey_ctr
);
170 /***********************************************************************
171 High level wrapper function for enumerating registry values
172 ***********************************************************************/
174 int fetch_reg_values( REGISTRY_KEY
*key
, REGVAL_CTR
*val
)
178 if ( key
->hook
&& key
->hook
->ops
&& key
->hook
->ops
->fetch_values
)
179 result
= key
->hook
->ops
->fetch_values( key
->name
, val
);
181 /* if the backend lookup returned no data, try the dynamic overlay */
184 result
= fetch_dynamic_reg_values( key
, val
);
186 return ( result
!= -1 ) ? result
: 0;
192 /***********************************************************************
193 High level access check for passing the required access mask to the
194 underlying registry backend
195 ***********************************************************************/
197 BOOL
regkey_access_check( REGISTRY_KEY
*key
, uint32 requested
, uint32
*granted
,
198 const struct nt_user_token
*token
)
205 /* use the default security check if the backend has not defined its
208 if (key
->hook
&& key
->hook
->ops
&& key
->hook
->ops
->reg_access_check
) {
209 return key
->hook
->ops
->reg_access_check( key
->name
, requested
,
214 * The secdesc routines can't yet cope with a NULL talloc ctx sanely.
217 if (!(mem_ctx
= talloc_init("regkey_access_check"))) {
221 err
= regkey_get_secdesc(mem_ctx
, key
, &sec_desc
);
223 if (!W_ERROR_IS_OK(err
)) {
224 TALLOC_FREE(mem_ctx
);
228 se_map_generic( &requested
, ®_generic_map
);
230 if (!se_access_check(sec_desc
, token
, requested
, granted
, &status
)) {
231 TALLOC_FREE(mem_ctx
);
235 TALLOC_FREE(mem_ctx
);
236 return NT_STATUS_IS_OK(status
);
239 /***********************************************************************
240 ***********************************************************************/
242 static int regkey_destructor(REGISTRY_KEY
*key
)
244 return regdb_close();
247 WERROR
regkey_open_onelevel( TALLOC_CTX
*mem_ctx
, struct registry_key
*parent
,
249 const struct nt_user_token
*token
,
250 uint32 access_desired
,
251 struct registry_key
**pregkey
)
253 WERROR result
= WERR_OK
;
254 struct registry_key
*regkey
;
256 REGSUBKEY_CTR
*subkeys
= NULL
;
258 DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name
));
260 SMB_ASSERT(strchr(name
, '\\') == NULL
);
262 if (!(regkey
= TALLOC_ZERO_P(mem_ctx
, struct registry_key
)) ||
263 !(regkey
->token
= dup_nt_token(regkey
, token
)) ||
264 !(regkey
->key
= TALLOC_ZERO_P(regkey
, REGISTRY_KEY
))) {
269 if ( !(W_ERROR_IS_OK(result
= regdb_open())) ) {
274 talloc_set_destructor(key
, regkey_destructor
);
278 key
->type
= REG_KEY_GENERIC
;
280 if (name
[0] == '\0') {
282 * Open a copy of the parent key
285 result
= WERR_BADFILE
;
288 key
->name
= talloc_strdup(key
, parent
->key
->name
);
294 key
->name
= talloc_asprintf(key
, "%s%s%s",
295 parent
? parent
->key
->name
: "",
300 if (key
->name
== NULL
) {
305 /* Tag this as a Performance Counter Key */
307 if( StrnCaseCmp(key
->name
, KEY_HKPD
, strlen(KEY_HKPD
)) == 0 )
308 key
->type
= REG_KEY_HKPD
;
310 /* Look up the table of registry I/O operations */
312 if ( !(key
->hook
= reghook_cache_find( key
->name
)) ) {
313 DEBUG(0,("reg_open_onelevel: Failed to assigned a "
314 "REGISTRY_HOOK to [%s]\n", key
->name
));
315 result
= WERR_BADFILE
;
319 /* check if the path really exists; failed is indicated by -1 */
320 /* if the subkey count failed, bail out */
322 if ( !(subkeys
= TALLOC_ZERO_P( key
, REGSUBKEY_CTR
)) ) {
327 if ( fetch_reg_keys( key
, subkeys
) == -1 ) {
328 result
= WERR_BADFILE
;
332 TALLOC_FREE( subkeys
);
334 if ( !regkey_access_check( key
, access_desired
, &key
->access_granted
,
336 result
= WERR_ACCESS_DENIED
;
344 if ( !W_ERROR_IS_OK(result
) ) {
351 WERROR
regkey_open_internal( TALLOC_CTX
*ctx
, REGISTRY_KEY
**regkey
,
353 const struct nt_user_token
*token
,
354 uint32 access_desired
)
356 struct registry_key
*key
;
359 err
= reg_open_path(NULL
, path
, access_desired
, token
, &key
);
360 if (!W_ERROR_IS_OK(err
)) {
364 *regkey
= talloc_move(ctx
, &key
->key
);
369 WERROR
regkey_get_secdesc(TALLOC_CTX
*mem_ctx
, REGISTRY_KEY
*key
,
370 struct security_descriptor
**psecdesc
)
372 struct security_descriptor
*secdesc
;
374 if (key
->hook
&& key
->hook
->ops
&& key
->hook
->ops
->get_secdesc
) {
377 err
= key
->hook
->ops
->get_secdesc(mem_ctx
, key
->name
,
379 if (W_ERROR_IS_OK(err
)) {
384 if (!(secdesc
= construct_registry_sd(mem_ctx
))) {
392 WERROR
regkey_set_secdesc(REGISTRY_KEY
*key
,
393 struct security_descriptor
*psecdesc
)
395 if (key
->hook
&& key
->hook
->ops
&& key
->hook
->ops
->set_secdesc
) {
396 return key
->hook
->ops
->set_secdesc(key
->name
, psecdesc
);
399 return WERR_ACCESS_DENIED
;
404 * Utility function to open a complete registry path including the hive
405 * prefix. This should become the replacement function for
406 * regkey_open_internal.
409 WERROR
reg_open_path(TALLOC_CTX
*mem_ctx
, const char *orig_path
,
410 uint32 desired_access
, const struct nt_user_token
*token
,
411 struct registry_key
**pkey
)
413 struct registry_key
*hive
, *key
;
417 if (!(path
= SMB_STRDUP(orig_path
))) {
421 p
= strchr(path
, '\\');
423 if ((p
== NULL
) || (p
[1] == '\0')) {
425 * No key behind the hive, just return the hive
428 err
= reg_openhive(mem_ctx
, path
, desired_access
, token
,
430 if (!W_ERROR_IS_OK(err
)) {
441 err
= reg_openhive(mem_ctx
, path
, SEC_RIGHTS_ENUM_SUBKEYS
, token
,
443 if (!W_ERROR_IS_OK(err
)) {
448 err
= reg_openkey(mem_ctx
, hive
, p
+1, desired_access
, &key
);
453 if (!W_ERROR_IS_OK(err
)) {
462 * Utility function to create a registry key without opening the hive
463 * before. Assumes the hive already exists.
466 WERROR
reg_create_path(TALLOC_CTX
*mem_ctx
, const char *orig_path
,
467 uint32 desired_access
,
468 const struct nt_user_token
*token
,
469 enum winreg_CreateAction
*paction
,
470 struct registry_key
**pkey
)
472 struct registry_key
*hive
;
476 if (!(path
= SMB_STRDUP(orig_path
))) {
480 p
= strchr(path
, '\\');
482 if ((p
== NULL
) || (p
[1] == '\0')) {
484 * No key behind the hive, just return the hive
487 err
= reg_openhive(mem_ctx
, path
, desired_access
, token
,
489 if (!W_ERROR_IS_OK(err
)) {
495 *paction
= REG_OPENED_EXISTING_KEY
;
501 err
= reg_openhive(mem_ctx
, path
,
502 (strchr(p
+1, '\\') != NULL
) ?
503 SEC_RIGHTS_ENUM_SUBKEYS
: SEC_RIGHTS_CREATE_SUBKEY
,
505 if (!W_ERROR_IS_OK(err
)) {
510 err
= reg_createkey(mem_ctx
, hive
, p
+1, desired_access
, pkey
, paction
);
517 * Utility function to create a registry key without opening the hive
518 * before. Will not delete a hive.
521 WERROR
reg_delete_path(const struct nt_user_token
*token
,
522 const char *orig_path
)
524 struct registry_key
*hive
;
528 if (!(path
= SMB_STRDUP(orig_path
))) {
532 p
= strchr(path
, '\\');
534 if ((p
== NULL
) || (p
[1] == '\0')) {
536 return WERR_INVALID_PARAM
;
541 err
= reg_openhive(NULL
, path
,
542 (strchr(p
+1, '\\') != NULL
) ?
543 SEC_RIGHTS_ENUM_SUBKEYS
: SEC_RIGHTS_CREATE_SUBKEY
,
545 if (!W_ERROR_IS_OK(err
)) {
550 err
= reg_deletekey(hive
, p
+1);