1/*
2 *  Unix SMB/CIFS implementation.
3 *  Virtual Windows Registry Layer
4 *  Copyright (C) Gerald Carter                     2002-2005
5 *
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.
10 *
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.
15 *
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.
19 */
20
21/* Implementation of registry frontend view functions. */
22
23#include "includes.h"
24
25#undef DBGC_CLASS
26#define DBGC_CLASS DBGC_RPC_SRV
27
28extern REGISTRY_OPS printing_ops;
29extern REGISTRY_OPS eventlog_ops;
30extern REGISTRY_OPS shares_reg_ops;
31extern REGISTRY_OPS regdb_ops;		/* these are the default */
32
33/* array of REGISTRY_HOOK's which are read into a tree for easy access */
34/* #define REG_TDB_ONLY		1 */
35
36REGISTRY_HOOK reg_hooks[] = {
37#ifndef REG_TDB_ONLY
38  { KEY_PRINTING,    		&printing_ops },
39  { KEY_PRINTING_2K, 		&printing_ops },
40  { KEY_PRINTING_PORTS, 	&printing_ops },
41  { KEY_SHARES,      		&shares_reg_ops },
42#endif
43  { NULL, NULL }
44};
45
46
47static struct generic_mapping reg_generic_map =
48	{ REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
49
50/********************************************************************
51********************************************************************/
52
53static NTSTATUS registry_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token,
54                                     uint32 access_desired, uint32 *access_granted )
55{
56	NTSTATUS result;
57
58	if ( geteuid() == sec_initial_uid() ) {
59		DEBUG(5,("registry_access_check: using root's token\n"));
60		token = get_root_nt_token();
61	}
62
63	se_map_generic( &access_desired, &reg_generic_map );
64	se_access_check( sec_desc, token, access_desired, access_granted, &result );
65
66	return result;
67}
68
69/********************************************************************
70********************************************************************/
71
72static SEC_DESC* construct_registry_sd( TALLOC_CTX *ctx )
73{
74	SEC_ACE ace[2];
75	SEC_ACCESS mask;
76	size_t i = 0;
77	SEC_DESC *sd;
78	SEC_ACL *acl;
79	size_t sd_size;
80
81	/* basic access for Everyone */
82
83	init_sec_access(&mask, REG_KEY_READ );
84	init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
85
86	/* Full Access 'BUILTIN\Administrators' */
87
88	init_sec_access(&mask, REG_KEY_ALL );
89	init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
90
91
92	/* create the security descriptor */
93
94	if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
95		return NULL;
96
97	if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
98		return NULL;
99
100	return sd;
101}
102
103
104/***********************************************************************
105 Open the registry database and initialize the REGISTRY_HOOK cache
106 ***********************************************************************/
107
108BOOL init_registry( void )
109{
110	int i;
111
112
113	if ( !regdb_init() ) {
114		DEBUG(0,("init_registry: failed to initialize the registry tdb!\n"));
115		return False;
116	}
117
118	/* build the cache tree of registry hooks */
119
120	reghook_cache_init();
121
122	for ( i=0; reg_hooks[i].keyname; i++ ) {
123		if ( !reghook_cache_add(&reg_hooks[i]) )
124			return False;
125	}
126
127	if ( DEBUGLEVEL >= 20 )
128		reghook_dump_cache(20);
129
130	/* add any keys for other services */
131
132	svcctl_init_keys();
133	eventlog_init_keys();
134	perfcount_init_keys();
135
136	/* close and let each smbd open up as necessary */
137
138	regdb_close();
139
140	return True;
141}
142
143/***********************************************************************
144 High level wrapper function for storing registry subkeys
145 ***********************************************************************/
146
147BOOL store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys )
148{
149	if ( key->hook && key->hook->ops && key->hook->ops->store_subkeys )
150		return key->hook->ops->store_subkeys( key->name, subkeys );
151
152	return False;
153
154}
155
156/***********************************************************************
157 High level wrapper function for storing registry values
158 ***********************************************************************/
159
160BOOL store_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
161{
162	if ( check_dynamic_reg_values( key ) )
163		return False;
164
165	if ( key->hook && key->hook->ops && key->hook->ops->store_values )
166		return key->hook->ops->store_values( key->name, val );
167
168	return False;
169}
170
171
172/***********************************************************************
173 High level wrapper function for enumerating registry subkeys
174 Initialize the TALLOC_CTX if necessary
175 ***********************************************************************/
176
177int fetch_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkey_ctr )
178{
179	int result = -1;
180
181	if ( key->hook && key->hook->ops && key->hook->ops->fetch_subkeys )
182		result = key->hook->ops->fetch_subkeys( key->name, subkey_ctr );
183
184	return result;
185}
186
187/***********************************************************************
188 retreive a specific subkey specified by index.  Caller is
189 responsible for freeing memory
190 ***********************************************************************/
191
192BOOL fetch_reg_keys_specific( REGISTRY_KEY *key, char** subkey, uint32 key_index )
193{
194	static REGSUBKEY_CTR *ctr = NULL;
195	static pstring save_path;
196	char *s;
197
198	*subkey = NULL;
199
200	/* simple caching for performance; very basic heuristic */
201
202	DEBUG(8,("fetch_reg_keys_specific: Looking for key [%d] of  [%s]\n", key_index, key->name));
203
204	if ( !ctr ) {
205		DEBUG(8,("fetch_reg_keys_specific: Initializing cache of subkeys for [%s]\n", key->name));
206
207		if ( !(ctr = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) ) {
208			DEBUG(0,("fetch_reg_keys_specific: talloc() failed!\n"));
209			return False;
210		}
211
212		pstrcpy( save_path, key->name );
213
214		if ( fetch_reg_keys( key, ctr) == -1 )
215			return False;
216
217	}
218	/* clear the cache when key_index == 0 or the path has changed */
219	else if ( !key_index || StrCaseCmp( save_path, key->name) ) {
220
221		DEBUG(8,("fetch_reg_keys_specific: Updating cache of subkeys for [%s]\n", key->name));
222
223		TALLOC_FREE( ctr );
224
225		if ( !(ctr = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) ) {
226			DEBUG(0,("fetch_reg_keys_specific: talloc() failed!\n"));
227			return False;
228		}
229
230		pstrcpy( save_path, key->name );
231
232		if ( fetch_reg_keys( key, ctr) == -1 )
233			return False;
234	}
235
236	if ( !(s = regsubkey_ctr_specific_key( ctr, key_index )) )
237		return False;
238
239	*subkey = SMB_STRDUP( s );
240
241	return True;
242}
243
244/***********************************************************************
245 High level wrapper function for enumerating registry values
246 ***********************************************************************/
247
248int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
249{
250	int result = -1;
251
252	if ( key->hook && key->hook->ops && key->hook->ops->fetch_values )
253		result = key->hook->ops->fetch_values( key->name, val );
254
255	/* if the backend lookup returned no data, try the dynamic overlay */
256
257	if ( result == 0 ) {
258		result = fetch_dynamic_reg_values( key, val );
259
260		return ( result != -1 ) ? result : 0;
261	}
262
263	return result;
264}
265
266
267/***********************************************************************
268 retreive a specific subkey specified by index.  Caller is
269 responsible for freeing memory
270 ***********************************************************************/
271
272BOOL fetch_reg_values_specific( REGISTRY_KEY *key, REGISTRY_VALUE **val, uint32 val_index )
273{
274	static REGVAL_CTR 	*ctr = NULL;
275	static pstring		save_path;
276	REGISTRY_VALUE		*v;
277
278	*val = NULL;
279
280	/* simple caching for performance; very basic heuristic */
281
282	if ( !ctr ) {
283		DEBUG(8,("fetch_reg_values_specific: Initializing cache of values for [%s]\n", key->name));
284
285		if ( !(ctr = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
286			DEBUG(0,("fetch_reg_values_specific: talloc() failed!\n"));
287			return False;
288		}
289
290		pstrcpy( save_path, key->name );
291
292		if ( fetch_reg_values( key, ctr) == -1 )
293			return False;
294	}
295	/* clear the cache when val_index == 0 or the path has changed */
296	else if ( !val_index || !strequal(save_path, key->name) ) {
297
298		DEBUG(8,("fetch_reg_values_specific: Updating cache of values for [%s]\n", key->name));
299
300		TALLOC_FREE( ctr );
301
302		if ( !(ctr = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
303			DEBUG(0,("fetch_reg_values_specific: talloc() failed!\n"));
304			return False;
305		}
306
307		pstrcpy( save_path, key->name );
308
309		if ( fetch_reg_values( key, ctr) == -1 )
310			return False;
311	}
312
313	if ( !(v = regval_ctr_specific_value( ctr, val_index )) )
314		return False;
315
316	*val = dup_registry_value( v );
317
318	return True;
319}
320
321/***********************************************************************
322 High level access check for passing the required access mask to the
323 underlying registry backend
324 ***********************************************************************/
325
326BOOL regkey_access_check( REGISTRY_KEY *key, uint32 requested, uint32 *granted, NT_USER_TOKEN *token )
327{
328	/* use the default security check if the backend has not defined its own */
329
330	if ( !(key->hook && key->hook->ops && key->hook->ops->reg_access_check) ) {
331		SEC_DESC *sec_desc;
332		NTSTATUS status;
333
334		if ( !(sec_desc = construct_registry_sd( get_talloc_ctx() )) )
335			return False;
336
337		status = registry_access_check( sec_desc, token, requested, granted );
338
339		return NT_STATUS_IS_OK(status);
340	}
341
342	return key->hook->ops->reg_access_check( key->name, requested, granted, token );
343}
344
345/***********************************************************************
346***********************************************************************/
347
348WERROR regkey_open_internal( REGISTRY_KEY **regkey, const char *path,
349                             NT_USER_TOKEN *token, uint32 access_desired )
350{
351	WERROR     	result = WERR_OK;
352	REGISTRY_KEY    *keyinfo;
353	REGSUBKEY_CTR	*subkeys = NULL;
354	uint32 access_granted;
355
356	if ( !(W_ERROR_IS_OK(result = regdb_open()) ) )
357		return result;
358
359	DEBUG(7,("regkey_open_internal: name = [%s]\n", path));
360
361	if ( !(*regkey = TALLOC_ZERO_P(NULL, REGISTRY_KEY)) ) {
362		regdb_close();
363		return WERR_NOMEM;
364	}
365
366	keyinfo = *regkey;
367
368	/* initialization */
369
370	keyinfo->type = REG_KEY_GENERIC;
371	if (!(keyinfo->name = talloc_strdup(keyinfo, path))) {
372		result = WERR_NOMEM;
373		goto done;
374	}
375
376	/* Tag this as a Performance Counter Key */
377
378	if( StrnCaseCmp(path, KEY_HKPD, strlen(KEY_HKPD)) == 0 )
379		keyinfo->type = REG_KEY_HKPD;
380
381	/* Look up the table of registry I/O operations */
382
383	if ( !(keyinfo->hook = reghook_cache_find( keyinfo->name )) ) {
384		DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
385			keyinfo->name ));
386		result = WERR_BADFILE;
387		goto done;
388	}
389
390	/* check if the path really exists; failed is indicated by -1 */
391	/* if the subkey count failed, bail out */
392
393	if ( !(subkeys = TALLOC_ZERO_P( keyinfo, REGSUBKEY_CTR )) ) {
394		result = WERR_NOMEM;
395		goto done;
396	}
397
398	if ( fetch_reg_keys( keyinfo, subkeys ) == -1 )  {
399		result = WERR_BADFILE;
400		goto done;
401	}
402
403	TALLOC_FREE( subkeys );
404
405	if ( !regkey_access_check( keyinfo, access_desired, &access_granted, token ) ) {
406		result = WERR_ACCESS_DENIED;
407		goto done;
408	}
409
410	keyinfo->access_granted = access_granted;
411
412done:
413	if ( !W_ERROR_IS_OK(result) ) {
414		regkey_close_internal( *regkey );
415	}
416
417	return result;
418}
419
420/*******************************************************************
421*******************************************************************/
422
423WERROR regkey_close_internal( REGISTRY_KEY *key )
424{
425	TALLOC_FREE( key );
426	regdb_close();
427
428	return WERR_OK;
429}
430