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 3 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, see <http://www.gnu.org/licenses/>.
25
struct rcinit_file_information {
29
struct service_display_info {
30
const char *servicename;
33
const char *description;
36
struct service_display_info builtin_svcs[] = {
37
{ "Spooler", "smbd", "Print Spooler", "Internal service for spooling files to print devices" },
38
{ "NETLOGON", "smbd", "Net Logon", "File service providing access to policy and profile data (not remotely manageable)" },
39
{ "RemoteRegistry", "smbd", "Remote Registry Service", "Internal service providing remote access to "
40
"the Samba registry" },
41
{ "WINS", "nmbd", "Windows Internet Name Service (WINS)", "Internal service providing a "
42
"NetBIOS point-to-point name server (not remotely manageable)" },
43
{ NULL, NULL, NULL, NULL }
46
struct service_display_info common_unix_svcs[] = {
47
{ "cups", NULL, "Common Unix Printing System","Provides unified printing support for all operating systems" },
48
{ "postfix", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
49
{ "sendmail", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
50
{ "portmap", NULL, "TCP Port to RPC PortMapper",NULL },
51
{ "xinetd", NULL, "Internet Meta-Daemon", NULL },
52
{ "inet", NULL, "Internet Meta-Daemon", NULL },
53
{ "xntpd", NULL, "Network Time Service", NULL },
54
{ "ntpd", NULL, "Network Time Service", NULL },
55
{ "lpd", NULL, "BSD Print Spooler", NULL },
56
{ "nfsserver", NULL, "Network File Service", NULL },
57
{ "cron", NULL, "Scheduling Service", NULL },
58
{ "at", NULL, "Scheduling Service", NULL },
59
{ "nscd", NULL, "Name Service Cache Daemon", NULL },
60
{ "slapd", NULL, "LDAP Directory Service", NULL },
61
{ "ldap", NULL, "LDAP DIrectory Service", NULL },
62
{ "ypbind", NULL, "NIS Directory Service", NULL },
63
{ "courier-imap", NULL, "IMAP4 Mail Service", NULL },
64
{ "courier-pop3", NULL, "POP3 Mail Service", NULL },
65
{ "named", NULL, "Domain Name Service", NULL },
66
{ "bind", NULL, "Domain Name Service", NULL },
67
{ "httpd", NULL, "HTTP Server", NULL },
68
{ "apache", NULL, "HTTP Server", "Provides s highly scalable and flexible web server "
69
"capable of implementing various protocols incluing "
70
"but not limited to HTTP" },
71
{ "autofs", NULL, "Automounter", NULL },
72
{ "squid", NULL, "Web Cache Proxy ", NULL },
73
{ "perfcountd", NULL, "Performance Monitoring Daemon", NULL },
74
{ "pgsql", NULL, "PgSQL Database Server", "Provides service for SQL database from Postgresql.org" },
75
{ "arpwatch", NULL, "ARP Tables watcher", "Provides service for monitoring ARP tables for changes" },
76
{ "dhcpd", NULL, "DHCP Server", "Provides service for dynamic host configuration and IP assignment" },
77
{ "nwserv", NULL, "NetWare Server Emulator", "Provides service for emulating Novell NetWare 3.12 server" },
78
{ "proftpd", NULL, "Professional FTP Server", "Provides high configurable service for FTP connection and "
79
"file transferring" },
80
{ "ssh2", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
81
{ "sshd", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
82
{ NULL, NULL, NULL, NULL }
86
/********************************************************************
87
********************************************************************/
89
static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx )
94
SEC_ACL *theacl = NULL;
97
/* basic access for Everyone */
99
init_sec_ace(&ace[i++], &global_sid_World,
100
SEC_ACE_TYPE_ACCESS_ALLOWED, SERVICE_READ_ACCESS, 0);
102
init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users,
103
SEC_ACE_TYPE_ACCESS_ALLOWED, SERVICE_EXECUTE_ACCESS, 0);
105
init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators,
106
SEC_ACE_TYPE_ACCESS_ALLOWED, SERVICE_ALL_ACCESS, 0);
107
init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
108
SEC_ACE_TYPE_ACCESS_ALLOWED, SERVICE_ALL_ACCESS, 0);
110
/* create the security descriptor */
112
if ( !(theacl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
115
if ( !(sd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
116
SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL,
123
/********************************************************************
124
This is where we do the dirty work of filling in things like the
125
Display name, Description, etc...
126
********************************************************************/
128
static char *get_common_service_dispname( const char *servicename )
132
for ( i=0; common_unix_svcs[i].servicename; i++ ) {
133
if (strequal(servicename, common_unix_svcs[i].servicename)) {
135
if (asprintf(&dispname,
137
common_unix_svcs[i].dispname,
138
common_unix_svcs[i].servicename) < 0) {
145
return SMB_STRDUP(servicename );
148
/********************************************************************
149
********************************************************************/
151
static char *cleanup_string( const char *string )
155
TALLOC_CTX *ctx = talloc_tos();
157
clean = talloc_strdup(ctx, string);
163
/* trim any beginning whilespace */
165
while (isspace(*begin)) {
169
if (*begin == '\0') {
173
/* trim any trailing whitespace or carriage returns.
174
Start at the end and move backwards */
176
end = begin + strlen(begin) - 1;
178
while ( isspace(*end) || *end=='\n' || *end=='\r' ) {
186
/********************************************************************
187
********************************************************************/
189
static bool read_init_file( const char *servicename, struct rcinit_file_information **service_info )
191
struct rcinit_file_information *info = NULL;
192
char *filepath = NULL;
197
if ( !(info = TALLOC_ZERO_P( NULL, struct rcinit_file_information ) ) )
200
/* attempt the file open */
202
filepath = talloc_asprintf(info, "%s/%s/%s", get_dyn_MODULESDIR(),
203
SVCCTL_SCRIPT_DIR, servicename);
208
if (!(f = x_fopen( filepath, O_RDONLY, 0 ))) {
209
DEBUG(0,("read_init_file: failed to open [%s]\n", filepath));
214
while ( (x_fgets( str, sizeof(str)-1, f )) != NULL ) {
215
/* ignore everything that is not a full line
216
comment starting with a '#' */
221
/* Look for a line like '^#.*Description:' */
223
if ( (p = strstr( str, "Description:" )) != NULL ) {
226
p += strlen( "Description:" ) + 1;
230
if ( (desc = cleanup_string(p)) != NULL )
231
info->description = talloc_strdup( info, desc );
237
if ( !info->description )
238
info->description = talloc_strdup( info, "External Unix Service" );
240
*service_info = info;
241
TALLOC_FREE(filepath);
246
/********************************************************************
247
This is where we do the dirty work of filling in things like the
248
Display name, Description, etc...
249
********************************************************************/
251
static void fill_service_values( const char *name, REGVAL_CTR *values )
253
UNISTR2 data, dname, ipath, description;
257
/* These values are hardcoded in all QueryServiceConfig() replies.
258
I'm just storing them here for cosmetic purposes */
260
dword = SVCCTL_AUTO_START;
261
regval_ctr_addvalue( values, "Start", REG_DWORD, (char*)&dword, sizeof(uint32));
263
dword = SERVICE_TYPE_WIN32_OWN_PROCESS;
264
regval_ctr_addvalue( values, "Type", REG_DWORD, (char*)&dword, sizeof(uint32));
266
dword = SVCCTL_SVC_ERROR_NORMAL;
267
regval_ctr_addvalue( values, "ErrorControl", REG_DWORD, (char*)&dword, sizeof(uint32));
269
/* everything runs as LocalSystem */
271
init_unistr2( &data, "LocalSystem", UNI_STR_TERMINATE );
272
regval_ctr_addvalue( values, "ObjectName", REG_SZ, (char*)data.buffer, data.uni_str_len*2);
274
/* special considerations for internal services and the DisplayName value */
276
for ( i=0; builtin_svcs[i].servicename; i++ ) {
277
if ( strequal( name, builtin_svcs[i].servicename ) ) {
279
if (asprintf(&pstr, "%s/%s/%s",
280
get_dyn_MODULESDIR(), SVCCTL_SCRIPT_DIR,
281
builtin_svcs[i].daemon) > 0) {
282
init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
285
init_unistr2( &ipath, "", UNI_STR_TERMINATE );
287
init_unistr2( &description, builtin_svcs[i].description, UNI_STR_TERMINATE );
288
init_unistr2( &dname, builtin_svcs[i].dispname, UNI_STR_TERMINATE );
293
/* default to an external service if we haven't found a match */
295
if ( builtin_svcs[i].servicename == NULL ) {
297
char *dispname = NULL;
298
struct rcinit_file_information *init_info = NULL;
300
if (asprintf(&pstr, "%s/%s/%s",get_dyn_MODULESDIR(),
301
SVCCTL_SCRIPT_DIR, name) > 0) {
302
init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
305
init_unistr2( &ipath, "", UNI_STR_TERMINATE );
308
/* lookup common unix display names */
309
dispname = get_common_service_dispname(name);
310
init_unistr2( &dname, dispname ? dispname : "", UNI_STR_TERMINATE );
313
/* get info from init file itself */
314
if ( read_init_file( name, &init_info ) ) {
315
init_unistr2( &description, init_info->description, UNI_STR_TERMINATE );
316
TALLOC_FREE( init_info );
319
init_unistr2( &description, "External Unix Service", UNI_STR_TERMINATE );
323
/* add the new values */
325
regval_ctr_addvalue( values, "DisplayName", REG_SZ, (char*)dname.buffer, dname.uni_str_len*2);
326
regval_ctr_addvalue( values, "ImagePath", REG_SZ, (char*)ipath.buffer, ipath.uni_str_len*2);
327
regval_ctr_addvalue( values, "Description", REG_SZ, (char*)description.buffer, description.uni_str_len*2);
332
/********************************************************************
333
********************************************************************/
335
static void add_new_svc_name( REGISTRY_KEY *key_parent, struct regsubkey_ctr *subkeys,
338
REGISTRY_KEY *key_service = NULL, *key_secdesc = NULL;
341
REGVAL_CTR *values = NULL;
342
struct regsubkey_ctr *svc_subkeys = NULL;
347
/* add to the list and create the subkey path */
349
regsubkey_ctr_addkey( subkeys, name );
350
store_reg_keys( key_parent, subkeys );
352
/* open the new service key */
354
if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
357
wresult = regkey_open_internal( NULL, &key_service, path,
358
get_root_nt_token(), REG_KEY_ALL );
359
if ( !W_ERROR_IS_OK(wresult) ) {
360
DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
361
path, win_errstr(wresult)));
367
/* add the 'Security' key */
369
wresult = regsubkey_ctr_init(key_service, &svc_subkeys);
370
if (!W_ERROR_IS_OK(wresult)) {
371
DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
372
TALLOC_FREE( key_service );
376
fetch_reg_keys( key_service, svc_subkeys );
377
regsubkey_ctr_addkey( svc_subkeys, "Security" );
378
store_reg_keys( key_service, svc_subkeys );
380
/* now for the service values */
382
if ( !(values = TALLOC_ZERO_P( key_service, REGVAL_CTR )) ) {
383
DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
384
TALLOC_FREE( key_service );
388
fill_service_values( name, values );
389
store_reg_values( key_service, values );
391
/* cleanup the service key*/
393
TALLOC_FREE( key_service );
395
/* now add the security descriptor */
397
if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
400
wresult = regkey_open_internal( NULL, &key_secdesc, path,
401
get_root_nt_token(), REG_KEY_ALL );
402
if ( !W_ERROR_IS_OK(wresult) ) {
403
DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
404
path, win_errstr(wresult)));
405
TALLOC_FREE( key_secdesc );
411
if ( !(values = TALLOC_ZERO_P( key_secdesc, REGVAL_CTR )) ) {
412
DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
413
TALLOC_FREE( key_secdesc );
417
if ( !(sd = construct_service_sd(key_secdesc)) ) {
418
DEBUG(0,("add_new_svc_name: Failed to create default sec_desc!\n"));
419
TALLOC_FREE( key_secdesc );
423
status = marshall_sec_desc(key_secdesc, sd, &sd_blob.data,
425
if (!NT_STATUS_IS_OK(status)) {
426
DEBUG(0, ("marshall_sec_desc failed: %s\n",
428
TALLOC_FREE(key_secdesc);
432
regval_ctr_addvalue(values, "Security", REG_BINARY,
433
(const char *)sd_blob.data, sd_blob.length);
434
store_reg_values( key_secdesc, values );
436
TALLOC_FREE( key_secdesc );
441
/********************************************************************
442
********************************************************************/
444
void svcctl_init_keys( void )
446
const char **service_list = lp_svcctl_list();
448
struct regsubkey_ctr *subkeys = NULL;
449
REGISTRY_KEY *key = NULL;
452
/* bad mojo here if the lookup failed. Should not happen */
454
wresult = regkey_open_internal( NULL, &key, KEY_SERVICES,
455
get_root_nt_token(), REG_KEY_ALL );
457
if ( !W_ERROR_IS_OK(wresult) ) {
458
DEBUG(0,("svcctl_init_keys: key lookup failed! (%s)\n",
459
win_errstr(wresult)));
463
/* lookup the available subkeys */
465
wresult = regsubkey_ctr_init(key, &subkeys);
466
if (!W_ERROR_IS_OK(wresult)) {
467
DEBUG(0,("svcctl_init_keys: talloc() failed!\n"));
472
fetch_reg_keys( key, subkeys );
474
/* the builtin services exist */
476
for ( i=0; builtin_svcs[i].servicename; i++ )
477
add_new_svc_name( key, subkeys, builtin_svcs[i].servicename );
479
for ( i=0; service_list && service_list[i]; i++ ) {
481
/* only add new services */
482
if ( regsubkey_ctr_key_exists( subkeys, service_list[i] ) )
485
/* Add the new service key and initialize the appropriate values */
487
add_new_svc_name( key, subkeys, service_list[i] );
492
/* initialize the control hooks */
494
init_service_op_table();
499
/********************************************************************
500
This is where we do the dirty work of filling in things like the
501
Display name, Description, etc...Always return a default secdesc
502
in case of any failure.
503
********************************************************************/
505
SEC_DESC *svcctl_get_secdesc( TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
507
REGISTRY_KEY *key = NULL;
508
REGVAL_CTR *values = NULL;
509
REGISTRY_VALUE *val = NULL;
510
SEC_DESC *ret_sd = NULL;
515
/* now add the security descriptor */
517
if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
520
wresult = regkey_open_internal( NULL, &key, path, token,
522
if ( !W_ERROR_IS_OK(wresult) ) {
523
DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n",
524
path, win_errstr(wresult)));
528
if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
529
DEBUG(0,("svcctl_get_secdesc: talloc() failed!\n"));
533
if (fetch_reg_values( key, values ) == -1) {
534
DEBUG(0, ("Error getting registry values\n"));
538
if ( !(val = regval_ctr_getvalue( values, "Security" )) ) {
539
goto fallback_to_default_sd;
542
/* stream the service security descriptor */
544
status = unmarshall_sec_desc(ctx, regval_data_p(val),
545
regval_size(val), &ret_sd);
547
if (NT_STATUS_IS_OK(status)) {
551
fallback_to_default_sd:
552
DEBUG(6, ("svcctl_get_secdesc: constructing default secdesc for "
553
"service [%s]\n", name));
554
ret_sd = construct_service_sd(ctx);
562
/********************************************************************
563
Wrapper to make storing a Service sd easier
564
********************************************************************/
566
bool svcctl_set_secdesc( TALLOC_CTX *ctx, const char *name, SEC_DESC *sec_desc, NT_USER_TOKEN *token )
568
REGISTRY_KEY *key = NULL;
571
REGVAL_CTR *values = NULL;
576
/* now add the security descriptor */
578
if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
581
wresult = regkey_open_internal( NULL, &key, path, token,
583
if ( !W_ERROR_IS_OK(wresult) ) {
584
DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n",
585
path, win_errstr(wresult)));
591
if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
592
DEBUG(0,("svcctl_set_secdesc: talloc() failed!\n"));
597
/* stream the printer security descriptor */
599
status = marshall_sec_desc(ctx, sec_desc, &blob.data, &blob.length);
600
if (!NT_STATUS_IS_OK(status)) {
601
DEBUG(0,("svcctl_set_secdesc: ndr_push_struct_blob() failed!\n"));
606
regval_ctr_addvalue( values, "Security", REG_BINARY, (const char *)blob.data, blob.length);
607
ret = store_reg_values( key, values );
616
/********************************************************************
617
********************************************************************/
619
const char *svcctl_lookup_dispname(TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
621
char *display_name = NULL;
622
REGISTRY_KEY *key = NULL;
623
REGVAL_CTR *values = NULL;
624
REGISTRY_VALUE *val = NULL;
628
/* now add the security descriptor */
630
if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
633
wresult = regkey_open_internal( NULL, &key, path, token,
635
if ( !W_ERROR_IS_OK(wresult) ) {
636
DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n",
637
path, win_errstr(wresult)));
643
if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
644
DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n"));
649
fetch_reg_values( key, values );
651
if ( !(val = regval_ctr_getvalue( values, "DisplayName" )) )
654
rpcstr_pull_talloc(ctx, &display_name, regval_data_p(val), regval_size(val), 0 );
661
/* default to returning the service name */
663
return talloc_strdup(ctx, name);
666
/********************************************************************
667
********************************************************************/
669
const char *svcctl_lookup_description(TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
671
char *description = NULL;
672
REGISTRY_KEY *key = NULL;
673
REGVAL_CTR *values = NULL;
674
REGISTRY_VALUE *val = NULL;
678
/* now add the security descriptor */
680
if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
683
wresult = regkey_open_internal( NULL, &key, path, token,
685
if ( !W_ERROR_IS_OK(wresult) ) {
686
DEBUG(0,("svcctl_lookup_description: key lookup failed! [%s] (%s)\n",
687
path, win_errstr(wresult)));
693
if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
694
DEBUG(0,("svcctl_lookup_description: talloc() failed!\n"));
699
fetch_reg_values( key, values );
701
if ( !(val = regval_ctr_getvalue( values, "Description" )) ) {
703
return "Unix Service";
705
rpcstr_pull_talloc(ctx, &description, regval_data_p(val), regval_size(val), 0 );
712
/********************************************************************
713
********************************************************************/
715
REGVAL_CTR *svcctl_fetch_regvalues( const char *name, NT_USER_TOKEN *token )
717
REGISTRY_KEY *key = NULL;
718
REGVAL_CTR *values = NULL;
722
/* now add the security descriptor */
724
if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
727
wresult = regkey_open_internal( NULL, &key, path, token,
729
if ( !W_ERROR_IS_OK(wresult) ) {
730
DEBUG(0,("svcctl_fetch_regvalues: key lookup failed! [%s] (%s)\n",
731
path, win_errstr(wresult)));
737
if ( !(values = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
738
DEBUG(0,("svcctl_fetch_regvalues: talloc() failed!\n"));
742
fetch_reg_values( key, values );