r10656: BIG merge from trunk. Features not copied over
[vlendec/samba-autobuild/.git] / source3 / services / services_db.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Service Control API Implementation
4  * 
5  *  Copyright (C) Marcin Krzysztof Porwit         2005.
6  *  Largely Rewritten by:
7  *  Copyright (C) Gerald (Jerry) Carter           2005.
8  *  
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *  
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *  
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #include "includes.h"
25
26 /********************************************************************
27 ********************************************************************/
28
29 static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx )
30 {
31         SEC_ACE ace[4]; 
32         SEC_ACCESS mask;
33         size_t i = 0;
34         SEC_DESC *sd;
35         SEC_ACL *acl;
36         size_t sd_size;
37         
38         /* basic access for Everyone */
39         
40         init_sec_access(&mask, SERVICE_READ_ACCESS );
41         init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
42                 
43         init_sec_access(&mask,SERVICE_EXECUTE_ACCESS );
44         init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
45         
46         init_sec_access(&mask,SERVICE_ALL_ACCESS );
47         init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
48         init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
49         
50         /* create the security descriptor */
51         
52         if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
53                 return NULL;
54
55         if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
56                 return NULL;
57
58         return sd;
59 }
60
61 /********************************************************************
62  This is where we do the dirty work of filling in things like the
63  Display name, Description, etc...
64 ********************************************************************/
65
66 static void fill_service_values( const char *name, REGVAL_CTR *values )
67 {
68         UNISTR2 data, dname, ipath, description;
69         uint32 dword;
70         pstring pstr;
71         
72         /* These values are hardcoded in all QueryServiceConfig() replies.
73            I'm just storing them here for cosmetic purposes */
74         
75         dword = SVCCTL_AUTO_START;
76         regval_ctr_addvalue( values, "Start", REG_DWORD, (char*)&dword, sizeof(uint32));
77         
78         dword = SVCCTL_WIN32_OWN_PROC;
79         regval_ctr_addvalue( values, "Type", REG_DWORD, (char*)&dword, sizeof(uint32));
80
81         dword = SVCCTL_SVC_ERROR_NORMAL;
82         regval_ctr_addvalue( values, "ErrorControl", REG_DWORD, (char*)&dword, sizeof(uint32));
83         
84         /* everything runs as LocalSystem */
85         
86         init_unistr2( &data, "LocalSystem", UNI_STR_TERMINATE );
87         regval_ctr_addvalue( values, "ObjectName", REG_SZ, (char*)data.buffer, data.uni_str_len*2);
88         
89         /* special considerations for internal services and the DisplayName value */
90         
91         if ( strequal(name, "Spooler") ) {
92                 pstr_sprintf( pstr, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR );
93                 init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
94                 init_unistr2( &description, "Internal service for spooling files to print devices", UNI_STR_TERMINATE );
95                 init_unistr2( &dname, "Print Spooler", UNI_STR_TERMINATE );
96         } 
97         else if ( strequal(name, "NETLOGON") ) {
98                 pstr_sprintf( pstr, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR );
99                 init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
100                 init_unistr2( &description, "File service providing access to policy and profile data", UNI_STR_TERMINATE );
101                 init_unistr2( &dname, "Net Logon", UNI_STR_TERMINATE );
102         } 
103         else if ( strequal(name, "RemoteRegistry") ) {
104                 pstr_sprintf( pstr, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR );
105                 init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
106                 init_unistr2( &description, "Internal service providing remote access to the Samba registry", UNI_STR_TERMINATE );
107                 init_unistr2( &dname, "Remote Registry Service", UNI_STR_TERMINATE );
108         } 
109         else {
110                 pstr_sprintf( pstr, "%s/%s/%s",dyn_LIBDIR, SVCCTL_SCRIPT_DIR, name );
111                 init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
112                 init_unistr2( &description, "External Unix Service", UNI_STR_TERMINATE );
113                 init_unistr2( &dname, name, UNI_STR_TERMINATE );
114         }
115         regval_ctr_addvalue( values, "DisplayName", REG_SZ, (char*)dname.buffer, dname.uni_str_len*2);
116         regval_ctr_addvalue( values, "ImagePath", REG_SZ, (char*)ipath.buffer, ipath.uni_str_len*2);
117         regval_ctr_addvalue( values, "Description", REG_SZ, (char*)description.buffer, description.uni_str_len*2);
118         
119         return;
120 }
121
122 /********************************************************************
123 ********************************************************************/
124
125 static void add_new_svc_name( REGISTRY_KEY *key_parent, REGSUBKEY_CTR *subkeys, 
126                               const char *name )
127 {
128         REGISTRY_KEY *key_service, *key_secdesc;
129         WERROR wresult;
130         pstring path;
131         REGVAL_CTR *values;
132         REGSUBKEY_CTR *svc_subkeys;
133         SEC_DESC *sd;
134         prs_struct ps;
135
136         /* add to the list and create the subkey path */
137
138         regsubkey_ctr_addkey( subkeys, name );
139         store_reg_keys( key_parent, subkeys );
140
141         /* open the new service key */
142
143         pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name );
144         wresult = regkey_open_internal( &key_service, path, get_root_nt_token(), 
145                 REG_KEY_ALL );
146         if ( !W_ERROR_IS_OK(wresult) ) {
147                 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n", 
148                         path, dos_errstr(wresult)));
149                 return;
150         }
151         
152         /* add the 'Security' key */
153
154         if ( !(svc_subkeys = TALLOC_ZERO_P( key_service, REGSUBKEY_CTR )) ) {
155                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
156                 return;
157         }
158         
159         fetch_reg_keys( key_service, svc_subkeys );
160         regsubkey_ctr_addkey( svc_subkeys, "Security" );
161         store_reg_keys( key_service, svc_subkeys );
162
163         /* now for the service values */
164         
165         if ( !(values = TALLOC_ZERO_P( key_service, REGVAL_CTR )) ) {
166                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
167                 return;
168         }
169
170         fill_service_values( name, values );
171         store_reg_values( key_service, values );
172
173         /* cleanup the service key*/
174
175         TALLOC_FREE( key_service );
176
177         /* now add the security descriptor */
178
179         pstr_sprintf( path, "%s\\%s\\%s", KEY_SERVICES, name, "Security" );
180         wresult = regkey_open_internal( &key_secdesc, path, get_root_nt_token(), 
181                 REG_KEY_ALL );
182         if ( !W_ERROR_IS_OK(wresult) ) {
183                 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n", 
184                         path, dos_errstr(wresult)));
185                 return;
186         }
187
188         if ( !(values = TALLOC_ZERO_P( key_secdesc, REGVAL_CTR )) ) {
189                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
190                 return;
191         }
192
193         if ( !(sd = construct_service_sd(key_secdesc)) ) {
194                 DEBUG(0,("add_new_svc_name: Failed to create default sec_desc!\n"));
195                 TALLOC_FREE( key_secdesc );
196                 return;
197         }
198         
199         /* stream the printer security descriptor */
200         
201         prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, key_secdesc, MARSHALL);
202         
203         if ( sec_io_desc("sec_desc", &sd, &ps, 0 ) ) {
204                 uint32 offset = prs_offset( &ps );
205                 regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&ps), offset );
206                 store_reg_values( key_secdesc, values );
207         }
208         
209         /* finally cleanup the Security key */
210         
211         prs_mem_free( &ps );
212         TALLOC_FREE( key_secdesc );
213
214         return;
215 }
216
217 /********************************************************************
218 ********************************************************************/
219
220 void svcctl_init_keys( void )
221 {
222         const char **service_list = lp_svcctl_list();
223         int i;
224         REGSUBKEY_CTR *subkeys;
225         REGISTRY_KEY *key = NULL;
226         WERROR wresult;
227         BOOL new_services = False;
228         
229         /* bad mojo here if the lookup failed.  Should not happen */
230         
231         wresult = regkey_open_internal( &key, KEY_SERVICES, get_root_nt_token(), 
232                 REG_KEY_ALL );
233
234         if ( !W_ERROR_IS_OK(wresult) ) {
235                 DEBUG(0,("init_services_keys: key lookup failed! (%s)\n", 
236                         dos_errstr(wresult)));
237                 return;
238         }
239         
240         /* lookup the available subkeys */      
241         
242         if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) {
243                 DEBUG(0,("init_services_keys: talloc() failed!\n"));
244                 return;
245         }
246         
247         fetch_reg_keys( key, subkeys );
248         
249         /* the builting services exist */
250         
251         add_new_svc_name( key, subkeys, "Spooler" );
252         add_new_svc_name( key, subkeys, "NETLOGON" );
253         add_new_svc_name( key, subkeys, "RemoteRegistry" );
254                 
255         for ( i=0; service_list[i]; i++ ) {
256         
257                 /* only add new services */
258                 if ( regsubkey_ctr_key_exists( subkeys, service_list[i] ) )
259                         continue;
260
261                 /* Add the new service key and initialize the appropriate values */
262
263                 add_new_svc_name( key, subkeys, service_list[i] );
264
265                 new_services = True;
266         }
267
268         TALLOC_FREE( key );
269
270         /* initialize the control hooks */
271
272         init_service_op_table();
273
274         return;
275 }
276
277 /********************************************************************
278  This is where we do the dirty work of filling in things like the
279  Display name, Description, etc...Always return a default secdesc 
280  in case of any failure.
281 ********************************************************************/
282
283 SEC_DESC* svcctl_get_secdesc( TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
284 {
285         REGISTRY_KEY *key;
286         prs_struct ps;
287         REGVAL_CTR *values;
288         REGISTRY_VALUE *val;
289         SEC_DESC *sd = NULL;
290         SEC_DESC *ret_sd = NULL;
291         pstring path;
292         WERROR wresult;
293         
294         /* now add the security descriptor */
295
296         pstr_sprintf( path, "%s\\%s\\%s", KEY_SERVICES, name, "Security" );
297         wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL );
298         if ( !W_ERROR_IS_OK(wresult) ) {
299                 DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n", 
300                         path, dos_errstr(wresult)));
301                 return NULL;
302         }
303
304         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
305                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
306                 TALLOC_FREE( key );
307                 return NULL;
308         }
309
310         fetch_reg_values( key, values );
311         
312         if ( !(val = regval_ctr_getvalue( values, "Security" )) ) {
313                 DEBUG(6,("svcctl_get_secdesc: constructing default secdesc for service [%s]\n", 
314                         name));
315                 TALLOC_FREE( key );
316                 return construct_service_sd( ctx );
317         }
318         
319
320         /* stream the printer security descriptor */
321         
322         prs_init( &ps, 0, key, UNMARSHALL);
323         prs_give_memory( &ps, regval_data_p(val), regval_size(val), False );
324         
325         if ( !sec_io_desc("sec_desc", &sd, &ps, 0 ) ) {
326                 TALLOC_FREE( key );
327                 return construct_service_sd( ctx );
328         }
329         
330         ret_sd = dup_sec_desc( ctx, sd );
331         
332         /* finally cleanup the Security key */
333         
334         prs_mem_free( &ps );
335         TALLOC_FREE( key );
336
337         return ret_sd;
338 }
339
340 /********************************************************************
341 ********************************************************************/
342
343 char* svcctl_lookup_dispname( const char *name, NT_USER_TOKEN *token )
344 {
345         static fstring display_name;
346         REGISTRY_KEY *key;
347         REGVAL_CTR *values;
348         REGISTRY_VALUE *val;
349         pstring path;
350         WERROR wresult;
351         
352         /* now add the security descriptor */
353
354         pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name );
355         wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL );
356         if ( !W_ERROR_IS_OK(wresult) ) {
357                 DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", 
358                         path, dos_errstr(wresult)));
359                 return NULL;
360         }
361
362         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
363                 DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n"));
364                 TALLOC_FREE( key );
365                 return NULL;
366         }
367
368         fetch_reg_values( key, values );
369         
370         if ( !(val = regval_ctr_getvalue( values, "DisplayName" )) )
371                 fstrcpy( display_name, name );
372         else
373                 rpcstr_pull( display_name, regval_data_p(val), sizeof(display_name), regval_size(val), 0 );
374
375         TALLOC_FREE( key );
376         
377         return display_name;
378 }
379
380 /********************************************************************
381 ********************************************************************/
382
383 char* svcctl_lookup_description( const char *name, NT_USER_TOKEN *token )
384 {
385         static fstring description;
386         REGISTRY_KEY *key;
387         REGVAL_CTR *values;
388         REGISTRY_VALUE *val;
389         pstring path;
390         WERROR wresult;
391         
392         /* now add the security descriptor */
393
394         pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name );
395         wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL );
396         if ( !W_ERROR_IS_OK(wresult) ) {
397                 DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", 
398                         path, dos_errstr(wresult)));
399                 return NULL;
400         }
401
402         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
403                 DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n"));
404                 TALLOC_FREE( key );
405                 return NULL;
406         }
407
408         fetch_reg_values( key, values );
409         
410         if ( !(val = regval_ctr_getvalue( values, "Description" )) )
411                 fstrcpy( description, "Unix Service");
412         else
413                 rpcstr_pull( description, regval_data_p(val), sizeof(description), regval_size(val), 0 );
414
415         TALLOC_FREE( key );
416         
417         return description;
418 }
419
420
421 /********************************************************************
422 ********************************************************************/
423
424 REGVAL_CTR* svcctl_fetch_regvalues( const char *name, NT_USER_TOKEN *token )
425 {
426         REGISTRY_KEY *key;
427         REGVAL_CTR *values;
428         pstring path;
429         WERROR wresult;
430         
431         /* now add the security descriptor */
432
433         pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name );
434         wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL );
435         if ( !W_ERROR_IS_OK(wresult) ) {
436                 DEBUG(0,("svcctl_fetch_regvalues: key lookup failed! [%s] (%s)\n", 
437                         path, dos_errstr(wresult)));
438                 return NULL;
439         }
440
441         if ( !(values = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
442                 DEBUG(0,("svcctl_fetch_regvalues: talloc() failed!\n"));
443                 TALLOC_FREE( key );
444                 return NULL;
445         }
446         
447         fetch_reg_values( key, values );
448
449         TALLOC_FREE( key );
450         
451         return values;
452 }
453