r10819: merging a couple of fixes from trunk
[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_SHARES,                 &shares_reg_ops },
42 #endif
43   { NULL, NULL }
44 };
45
46
47 static struct generic_mapping reg_generic_map = 
48         { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
49
50 /********************************************************************
51 ********************************************************************/
52
53 static 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
72 static 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  
108 BOOL 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
135         /* close and let each smbd open up as necessary */
136
137         regdb_close();
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         if ( !(W_ERROR_IS_OK(result = regdb_open()) ) )
356                 return result;
357
358         DEBUG(7,("regkey_open_internal: name = [%s]\n", path));
359
360         if ( !(*regkey = TALLOC_ZERO_P(NULL, REGISTRY_KEY)) ) {
361                 regdb_close();
362                 return WERR_NOMEM;
363         }
364                 
365         keyinfo = *regkey;
366                 
367         /* initialization */
368         
369         keyinfo->type = REG_KEY_GENERIC;
370         keyinfo->name = talloc_strdup( keyinfo, path );
371         
372         
373         /* Tag this as a Performance Counter Key */
374
375         if( StrnCaseCmp(path, KEY_HKPD, strlen(KEY_HKPD)) == 0 )
376                 keyinfo->type = REG_KEY_HKPD;
377         
378         /* Look up the table of registry I/O operations */
379
380         if ( !(keyinfo->hook = reghook_cache_find( keyinfo->name )) ) {
381                 DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
382                         keyinfo->name ));
383                 result = WERR_BADFILE;
384                 goto done;
385         }
386         
387         /* check if the path really exists; failed is indicated by -1 */
388         /* if the subkey count failed, bail out */
389
390         if ( !(subkeys = TALLOC_ZERO_P( keyinfo, REGSUBKEY_CTR )) ) {
391                 result = WERR_NOMEM;
392                 goto done;
393         }
394
395         if ( fetch_reg_keys( keyinfo, subkeys ) == -1 )  {
396                 result = WERR_BADFILE;
397                 goto done;
398         }
399         
400         TALLOC_FREE( subkeys );
401
402         if ( !regkey_access_check( keyinfo, access_desired, &access_granted, token ) ) {
403                 result = WERR_ACCESS_DENIED;
404                 goto done;
405         }
406         
407         keyinfo->access_granted = access_granted;
408
409 done:
410         if ( !W_ERROR_IS_OK(result) ) {
411                 regkey_close_internal( *regkey );
412         }
413
414         return result;
415 }
416
417 /*******************************************************************
418 *******************************************************************/
419
420 WERROR regkey_close_internal( REGISTRY_KEY *key )
421 {
422         TALLOC_FREE( key );
423         regdb_close();
424
425         return WERR_OK;
426 }