2 * Unix SMB/CIFS implementation.
3 * Service Control API Implementation
5 * Copyright (C) Marcin Krzysztof Porwit 2005.
6 * Largely Rewritten by:
7 * Copyright (C) Gerald (Jerry) Carter 2005.
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.
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.
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.
26 /********************************************************************
27 ********************************************************************/
29 static SEC_DESC
* construct_service_sd( TALLOC_CTX
*ctx
)
38 /* basic access for Everyone */
40 init_sec_access(&mask
, SERVICE_READ_ACCESS
);
41 init_sec_ace(&ace
[i
++], &global_sid_World
, SEC_ACE_TYPE_ACCESS_ALLOWED
, mask
, 0);
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);
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);
50 /* create the security descriptor */
52 if ( !(acl
= make_sec_acl(ctx
, NT4_ACL_REVISION
, i
, ace
)) )
55 if ( !(sd
= make_sec_desc(ctx
, SEC_DESC_REVISION
, SEC_DESC_SELF_RELATIVE
, NULL
, NULL
, NULL
, acl
, &sd_size
)) )
61 /********************************************************************
62 This is where we do the dirty work of filling in things like the
63 Display name, Description, etc...
64 ********************************************************************/
66 static void fill_service_values( const char *name
, REGVAL_CTR
*values
)
68 UNISTR2 data
, dname
, ipath
, description
;
72 /* These values are hardcoded in all QueryServiceConfig() replies.
73 I'm just storing them here for cosmetic purposes */
75 dword
= SVCCTL_DEMAND_START
;
76 regval_ctr_addvalue( values
, "Start", REG_DWORD
, (char*)&dword
, sizeof(uint32
));
78 dword
= SVCCTL_WIN32_OWN_PROC
;
79 regval_ctr_addvalue( values
, "Type", REG_DWORD
, (char*)&dword
, sizeof(uint32
));
81 dword
= SVCCTL_SVC_ERROR_NORMAL
;
82 regval_ctr_addvalue( values
, "ErrorControl", REG_DWORD
, (char*)&dword
, sizeof(uint32
));
84 /* everything runs as LocalSystem */
86 init_unistr2( &data
, "LocalSystem", UNI_STR_TERMINATE
);
87 regval_ctr_addvalue( values
, "ObjectName", REG_SZ
, (char*)data
.buffer
, data
.uni_str_len
*2);
89 /* special considerations for internal services and the DisplayName value */
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
);
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
);
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
);
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
);
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);
122 /********************************************************************
123 ********************************************************************/
125 static void add_new_svc_name( REGISTRY_KEY
*key_parent
, REGSUBKEY_CTR
*subkeys
,
128 REGISTRY_KEY
*key_service
, *key_secdesc
;
132 REGSUBKEY_CTR
*svc_subkeys
;
136 /* add to the list and create the subkey path */
138 regsubkey_ctr_addkey( subkeys
, name
);
139 store_reg_keys( key_parent
, subkeys
);
141 /* open the new service key */
143 pstr_sprintf( path
, "%s\\%s", KEY_SERVICES
, name
);
144 wresult
= regkey_open_internal( &key_service
, path
, get_root_nt_token(),
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
)));
152 /* add the 'Security' key */
154 if ( !(svc_subkeys
= TALLOC_ZERO_P( key_service
, REGSUBKEY_CTR
)) ) {
155 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
159 fetch_reg_keys( key_service
, svc_subkeys
);
160 regsubkey_ctr_addkey( svc_subkeys
, "Security" );
161 store_reg_keys( key_service
, svc_subkeys
);
163 /* now for the service values */
165 if ( !(values
= TALLOC_ZERO_P( key_service
, REGVAL_CTR
)) ) {
166 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
170 fill_service_values( name
, values
);
171 store_reg_values( key_service
, values
);
173 /* cleanup the service key*/
175 TALLOC_FREE( key_service
);
177 /* now add the security descriptor */
179 pstr_sprintf( path
, "%s\\%s\\%s", KEY_SERVICES
, name
, "Security" );
180 wresult
= regkey_open_internal( &key_secdesc
, path
, get_root_nt_token(),
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
)));
188 if ( !(values
= TALLOC_ZERO_P( key_secdesc
, REGVAL_CTR
)) ) {
189 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
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
);
199 /* stream the printer security descriptor */
201 prs_init( &ps
, RPC_MAX_PDU_FRAG_LEN
, key_secdesc
, MARSHALL
);
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
);
209 /* finally cleanup the Security key */
212 TALLOC_FREE( key_secdesc
);
217 /********************************************************************
218 ********************************************************************/
220 void svcctl_init_keys( void )
222 const char **service_list
= lp_svcctl_list();
224 REGSUBKEY_CTR
*subkeys
;
225 REGISTRY_KEY
*key
= NULL
;
227 BOOL new_services
= False
;
229 /* bad mojo here if the lookup failed. Should not happen */
231 wresult
= regkey_open_internal( &key
, KEY_SERVICES
, get_root_nt_token(),
234 if ( !W_ERROR_IS_OK(wresult
) ) {
235 DEBUG(0,("init_services_keys: key lookup failed! (%s)\n",
236 dos_errstr(wresult
)));
240 /* lookup the available subkeys */
242 if ( !(subkeys
= TALLOC_ZERO_P( key
, REGSUBKEY_CTR
)) ) {
243 DEBUG(0,("init_services_keys: talloc() failed!\n"));
247 fetch_reg_keys( key
, subkeys
);
249 /* the builting services exist */
251 add_new_svc_name( key
, subkeys
, "Spooler" );
252 add_new_svc_name( key
, subkeys
, "NETLOGON" );
253 add_new_svc_name( key
, subkeys
, "RemoteRegistry" );
255 for ( i
=0; service_list
[i
]; i
++ ) {
257 /* only add new services */
258 if ( regsubkey_ctr_key_exists( subkeys
, service_list
[i
] ) )
261 /* Add the new service key and initialize the appropriate values */
263 add_new_svc_name( key
, subkeys
, service_list
[i
] );
270 /* initialize the control hooks */
272 init_service_op_table();
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 ********************************************************************/
283 SEC_DESC
* svcctl_get_secdesc( TALLOC_CTX
*ctx
, const char *name
, NT_USER_TOKEN
*token
)
290 SEC_DESC
*ret_sd
= NULL
;
294 /* now add the security descriptor */
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
)));
304 if ( !(values
= TALLOC_ZERO_P( key
, REGVAL_CTR
)) ) {
305 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
310 fetch_reg_values( key
, values
);
312 if ( !(val
= regval_ctr_getvalue( values
, "Security" )) ) {
313 DEBUG(6,("svcctl_get_secdesc: constructing default secdesc for service [%s]\n",
316 return construct_service_sd( ctx
);
320 /* stream the printer security descriptor */
322 prs_init( &ps
, 0, key
, UNMARSHALL
);
323 prs_give_memory( &ps
, regval_data_p(val
), regval_size(val
), False
);
325 if ( !sec_io_desc("sec_desc", &sd
, &ps
, 0 ) ) {
327 return construct_service_sd( ctx
);
330 ret_sd
= dup_sec_desc( ctx
, sd
);
332 /* finally cleanup the Security key */
340 /********************************************************************
341 ********************************************************************/
343 char* svcctl_lookup_dispname( const char *name
, NT_USER_TOKEN
*token
)
345 static fstring display_name
;
352 /* now add the security descriptor */
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
)));
362 if ( !(values
= TALLOC_ZERO_P( key
, REGVAL_CTR
)) ) {
363 DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n"));
368 fetch_reg_values( key
, values
);
370 if ( !(val
= regval_ctr_getvalue( values
, "DisplayName" )) )
371 fstrcpy( display_name
, name
);
373 rpcstr_pull( display_name
, regval_data_p(val
), sizeof(display_name
), regval_size(val
), 0 );
380 /********************************************************************
381 ********************************************************************/
383 char* svcctl_lookup_description( const char *name
, NT_USER_TOKEN
*token
)
385 static fstring description
;
392 /* now add the security descriptor */
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
)));
402 if ( !(values
= TALLOC_ZERO_P( key
, REGVAL_CTR
)) ) {
403 DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n"));
408 fetch_reg_values( key
, values
);
410 if ( !(val
= regval_ctr_getvalue( values
, "Description" )) )
411 fstrcpy( description
, "Unix Service");
413 rpcstr_pull( description
, regval_data_p(val
), sizeof(description
), regval_size(val
), 0 );
421 /********************************************************************
422 ********************************************************************/
424 REGVAL_CTR
* svcctl_fetch_regvalues( const char *name
, NT_USER_TOKEN
*token
)
431 /* now add the security descriptor */
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
)));
441 if ( !(values
= TALLOC_ZERO_P( NULL
, REGVAL_CTR
)) ) {
442 DEBUG(0,("svcctl_fetch_regvalues: talloc() failed!\n"));
447 fetch_reg_values( key
, values
);