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