f5284e9e88f2904c6ebffafe68d76239a90f3f72
[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 ( !init_registry_db() ) {
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         return True;
136 }
137
138 /***********************************************************************
139  High level wrapper function for storing registry subkeys
140  ***********************************************************************/
141  
142 BOOL store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys )
143 {
144         if ( key->hook && key->hook->ops && key->hook->ops->store_subkeys )
145                 return key->hook->ops->store_subkeys( key->name, subkeys );
146                 
147         return False;
148
149 }
150
151 /***********************************************************************
152  High level wrapper function for storing registry values
153  ***********************************************************************/
154  
155 BOOL store_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
156 {
157         if ( check_dynamic_reg_values( key ) )
158                 return False;
159
160         if ( key->hook && key->hook->ops && key->hook->ops->store_values )
161                 return key->hook->ops->store_values( key->name, val );
162
163         return False;
164 }
165
166
167 /***********************************************************************
168  High level wrapper function for enumerating registry subkeys
169  Initialize the TALLOC_CTX if necessary
170  ***********************************************************************/
171
172 int fetch_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkey_ctr )
173 {
174         int result = -1;
175         
176         if ( key->hook && key->hook->ops && key->hook->ops->fetch_subkeys )
177                 result = key->hook->ops->fetch_subkeys( key->name, subkey_ctr );
178
179         return result;
180 }
181
182 /***********************************************************************
183  retreive a specific subkey specified by index.  Caller is 
184  responsible for freeing memory
185  ***********************************************************************/
186
187 BOOL fetch_reg_keys_specific( REGISTRY_KEY *key, char** subkey, uint32 key_index )
188 {
189         static REGSUBKEY_CTR *ctr = NULL;
190         static pstring save_path;
191         char *s;
192         
193         *subkey = NULL;
194         
195         /* simple caching for performance; very basic heuristic */
196
197         DEBUG(8,("fetch_reg_keys_specific: Looking for key [%d] of  [%s]\n", key_index, key->name));
198         
199         if ( !ctr ) {
200                 DEBUG(8,("fetch_reg_keys_specific: Initializing cache of subkeys for [%s]\n", key->name));
201
202                 if ( !(ctr = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) ) {
203                         DEBUG(0,("fetch_reg_keys_specific: talloc() failed!\n"));
204                         return False;
205                 }
206                 
207                 pstrcpy( save_path, key->name );
208                 
209                 if ( fetch_reg_keys( key, ctr) == -1 )
210                         return False;
211                         
212         }
213         /* clear the cache when key_index == 0 or the path has changed */
214         else if ( !key_index || StrCaseCmp( save_path, key->name) ) {
215
216                 DEBUG(8,("fetch_reg_keys_specific: Updating cache of subkeys for [%s]\n", key->name));
217                 
218                 TALLOC_FREE( ctr );
219
220                 if ( !(ctr = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) ) {
221                         DEBUG(0,("fetch_reg_keys_specific: talloc() failed!\n"));
222                         return False;
223                 }
224                 
225                 pstrcpy( save_path, key->name );
226                 
227                 if ( fetch_reg_keys( key, ctr) == -1 )
228                         return False;
229         }
230         
231         if ( !(s = regsubkey_ctr_specific_key( ctr, key_index )) )
232                 return False;
233
234         *subkey = SMB_STRDUP( s );
235
236         return True;
237 }
238
239 /***********************************************************************
240  High level wrapper function for enumerating registry values
241  ***********************************************************************/
242
243 int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
244 {
245         int result = -1;
246         
247         if ( key->hook && key->hook->ops && key->hook->ops->fetch_values )
248                 result = key->hook->ops->fetch_values( key->name, val );
249         
250         /* if the backend lookup returned no data, try the dynamic overlay */
251         
252         if ( result == 0 ) {
253                 result = fetch_dynamic_reg_values( key, val );
254
255                 return ( result != -1 ) ? result : 0;
256         }
257         
258         return result;
259 }
260
261
262 /***********************************************************************
263  retreive a specific subkey specified by index.  Caller is 
264  responsible for freeing memory
265  ***********************************************************************/
266
267 BOOL fetch_reg_values_specific( REGISTRY_KEY *key, REGISTRY_VALUE **val, uint32 val_index )
268 {
269         static REGVAL_CTR       *ctr = NULL;
270         static pstring          save_path;
271         REGISTRY_VALUE          *v;
272         
273         *val = NULL;
274         
275         /* simple caching for performance; very basic heuristic */
276         
277         if ( !ctr ) {
278                 DEBUG(8,("fetch_reg_values_specific: Initializing cache of values for [%s]\n", key->name));
279
280                 if ( !(ctr = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
281                         DEBUG(0,("fetch_reg_values_specific: talloc() failed!\n"));
282                         return False;
283                 }
284
285                 pstrcpy( save_path, key->name );
286                 
287                 if ( fetch_reg_values( key, ctr) == -1 )
288                         return False;
289         }
290         /* clear the cache when val_index == 0 or the path has changed */
291         else if ( !val_index || !strequal(save_path, key->name) ) {
292
293                 DEBUG(8,("fetch_reg_values_specific: Updating cache of values for [%s]\n", key->name));         
294                 
295                 TALLOC_FREE( ctr );
296
297                 if ( !(ctr = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
298                         DEBUG(0,("fetch_reg_values_specific: talloc() failed!\n"));
299                         return False;
300                 }
301
302                 pstrcpy( save_path, key->name );
303                 
304                 if ( fetch_reg_values( key, ctr) == -1 )
305                         return False;
306         }
307         
308         if ( !(v = regval_ctr_specific_value( ctr, val_index )) )
309                 return False;
310
311         *val = dup_registry_value( v );
312
313         return True;
314 }
315
316 /***********************************************************************
317  High level access check for passing the required access mask to the 
318  underlying registry backend
319  ***********************************************************************/
320
321 BOOL regkey_access_check( REGISTRY_KEY *key, uint32 requested, uint32 *granted, NT_USER_TOKEN *token )
322 {
323         /* use the default security check if the backend has not defined its own */
324         
325         if ( !(key->hook && key->hook->ops && key->hook->ops->reg_access_check) ) {
326                 SEC_DESC *sec_desc;
327                 NTSTATUS status;
328                 
329                 if ( !(sec_desc = construct_registry_sd( get_talloc_ctx() )) )
330                         return False;
331                 
332                 status = registry_access_check( sec_desc, token, requested, granted );          
333                 
334                 return NT_STATUS_IS_OK(status);
335         }
336         
337         return key->hook->ops->reg_access_check( key->name, requested, granted, token );
338 }
339
340 /***********************************************************************
341 ***********************************************************************/
342
343 WERROR regkey_open_internal( REGISTRY_KEY **regkey, const char *path, 
344                              NT_USER_TOKEN *token, uint32 access_desired )
345 {
346         WERROR          result = WERR_OK;
347         REGISTRY_KEY    *keyinfo;
348         REGSUBKEY_CTR   *subkeys = NULL;
349         uint32 access_granted;
350         
351         DEBUG(7,("regkey_open_internal: name = [%s]\n", path));
352
353         if ( !(*regkey = TALLOC_ZERO_P(NULL, REGISTRY_KEY)) )
354                 return WERR_NOMEM;
355                 
356         keyinfo = *regkey;
357                 
358         /* initialization */
359         
360         keyinfo->type = REG_KEY_GENERIC;
361         keyinfo->name = talloc_strdup( keyinfo, path );
362         
363         
364         /* Tag this as a Performance Counter Key */
365
366         if( StrnCaseCmp(path, KEY_HKPD, strlen(KEY_HKPD)) == 0 )
367                 keyinfo->type = REG_KEY_HKPD;
368         
369         /* Look up the table of registry I/O operations */
370
371         if ( !(keyinfo->hook = reghook_cache_find( keyinfo->name )) ) {
372                 DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
373                         keyinfo->name ));
374                 result = WERR_BADFILE;
375                 goto done;
376         }
377         
378         /* check if the path really exists; failed is indicated by -1 */
379         /* if the subkey count failed, bail out */
380
381         if ( !(subkeys = TALLOC_ZERO_P( keyinfo, REGSUBKEY_CTR )) ) {
382                 result = WERR_NOMEM;
383                 goto done;
384         }
385
386         if ( fetch_reg_keys( keyinfo, subkeys ) == -1 )  {
387                 result = WERR_BADFILE;
388                 goto done;
389         }
390         
391         TALLOC_FREE( subkeys );
392
393         if ( !regkey_access_check( keyinfo, access_desired, &access_granted, token ) ) {
394                 result = WERR_ACCESS_DENIED;
395                 goto done;
396         }
397         
398         keyinfo->access_granted = access_granted;
399
400 done:
401         if ( !W_ERROR_IS_OK(result) ) {
402                 TALLOC_FREE( *regkey );
403         }
404
405         return result;
406 }