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/>.
24 #include "services/services.h"
26 #include "registry/reg_util_legacy.h"
27 #include "registry/reg_dispatcher.h"
28 #include "registry/reg_objects.h"
29 #include "registry/reg_api_util.h"
31 struct rcinit_file_information
{
35 struct service_display_info
{
36 const char *servicename
;
39 const char *description
;
42 struct service_display_info builtin_svcs
[] = {
43 { "Spooler", "smbd", "Print Spooler", "Internal service for spooling files to print devices" },
44 { "NETLOGON", "smbd", "Net Logon", "File service providing access to policy and profile data (not remotely manageable)" },
45 { "RemoteRegistry", "smbd", "Remote Registry Service", "Internal service providing remote access to "
46 "the Samba registry" },
47 { "WINS", "nmbd", "Windows Internet Name Service (WINS)", "Internal service providing a "
48 "NetBIOS point-to-point name server (not remotely manageable)" },
49 { NULL
, NULL
, NULL
, NULL
}
52 struct service_display_info common_unix_svcs
[] = {
53 { "cups", NULL
, "Common Unix Printing System","Provides unified printing support for all operating systems" },
54 { "postfix", NULL
, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
55 { "sendmail", NULL
, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
56 { "portmap", NULL
, "TCP Port to RPC PortMapper",NULL
},
57 { "xinetd", NULL
, "Internet Meta-Daemon", NULL
},
58 { "inet", NULL
, "Internet Meta-Daemon", NULL
},
59 { "xntpd", NULL
, "Network Time Service", NULL
},
60 { "ntpd", NULL
, "Network Time Service", NULL
},
61 { "lpd", NULL
, "BSD Print Spooler", NULL
},
62 { "nfsserver", NULL
, "Network File Service", NULL
},
63 { "cron", NULL
, "Scheduling Service", NULL
},
64 { "at", NULL
, "Scheduling Service", NULL
},
65 { "nscd", NULL
, "Name Service Cache Daemon", NULL
},
66 { "slapd", NULL
, "LDAP Directory Service", NULL
},
67 { "ldap", NULL
, "LDAP DIrectory Service", NULL
},
68 { "ypbind", NULL
, "NIS Directory Service", NULL
},
69 { "courier-imap", NULL
, "IMAP4 Mail Service", NULL
},
70 { "courier-pop3", NULL
, "POP3 Mail Service", NULL
},
71 { "named", NULL
, "Domain Name Service", NULL
},
72 { "bind", NULL
, "Domain Name Service", NULL
},
73 { "httpd", NULL
, "HTTP Server", NULL
},
74 { "apache", NULL
, "HTTP Server", "Provides s highly scalable and flexible web server "
75 "capable of implementing various protocols incluing "
76 "but not limited to HTTP" },
77 { "autofs", NULL
, "Automounter", NULL
},
78 { "squid", NULL
, "Web Cache Proxy ", NULL
},
79 { "perfcountd", NULL
, "Performance Monitoring Daemon", NULL
},
80 { "pgsql", NULL
, "PgSQL Database Server", "Provides service for SQL database from Postgresql.org" },
81 { "arpwatch", NULL
, "ARP Tables watcher", "Provides service for monitoring ARP tables for changes" },
82 { "dhcpd", NULL
, "DHCP Server", "Provides service for dynamic host configuration and IP assignment" },
83 { "nwserv", NULL
, "NetWare Server Emulator", "Provides service for emulating Novell NetWare 3.12 server" },
84 { "proftpd", NULL
, "Professional FTP Server", "Provides high configurable service for FTP connection and "
85 "file transferring" },
86 { "ssh2", NULL
, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
87 { "sshd", NULL
, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
88 { NULL
, NULL
, NULL
, NULL
}
92 /********************************************************************
93 ********************************************************************/
95 static struct security_descriptor
* construct_service_sd( TALLOC_CTX
*ctx
)
97 struct security_ace ace
[4];
99 struct security_descriptor
*sd
= NULL
;
100 struct security_acl
*theacl
= NULL
;
103 /* basic access for Everyone */
105 init_sec_ace(&ace
[i
++], &global_sid_World
,
106 SEC_ACE_TYPE_ACCESS_ALLOWED
, SERVICE_READ_ACCESS
, 0);
108 init_sec_ace(&ace
[i
++], &global_sid_Builtin_Power_Users
,
109 SEC_ACE_TYPE_ACCESS_ALLOWED
, SERVICE_EXECUTE_ACCESS
, 0);
111 init_sec_ace(&ace
[i
++], &global_sid_Builtin_Server_Operators
,
112 SEC_ACE_TYPE_ACCESS_ALLOWED
, SERVICE_ALL_ACCESS
, 0);
113 init_sec_ace(&ace
[i
++], &global_sid_Builtin_Administrators
,
114 SEC_ACE_TYPE_ACCESS_ALLOWED
, SERVICE_ALL_ACCESS
, 0);
116 /* create the security descriptor */
118 theacl
= make_sec_acl(ctx
, NT4_ACL_REVISION
, i
, ace
);
119 if (theacl
== NULL
) {
123 sd
= make_sec_desc(ctx
, SECURITY_DESCRIPTOR_REVISION_1
,
124 SEC_DESC_SELF_RELATIVE
, NULL
, NULL
, NULL
,
133 /********************************************************************
134 This is where we do the dirty work of filling in things like the
135 Display name, Description, etc...
136 ********************************************************************/
138 static char *get_common_service_dispname( const char *servicename
)
142 for ( i
=0; common_unix_svcs
[i
].servicename
; i
++ ) {
143 if (strequal(servicename
, common_unix_svcs
[i
].servicename
)) {
145 if (asprintf(&dispname
,
147 common_unix_svcs
[i
].dispname
,
148 common_unix_svcs
[i
].servicename
) < 0) {
155 return SMB_STRDUP(servicename
);
158 /********************************************************************
159 ********************************************************************/
161 static char *cleanup_string( const char *string
)
165 TALLOC_CTX
*ctx
= talloc_tos();
167 clean
= talloc_strdup(ctx
, string
);
173 /* trim any beginning whilespace */
175 while (isspace(*begin
)) {
179 if (*begin
== '\0') {
183 /* trim any trailing whitespace or carriage returns.
184 Start at the end and move backwards */
186 end
= begin
+ strlen(begin
) - 1;
188 while ( isspace(*end
) || *end
=='\n' || *end
=='\r' ) {
196 /********************************************************************
197 ********************************************************************/
199 static bool read_init_file( const char *servicename
, struct rcinit_file_information
**service_info
)
201 struct rcinit_file_information
*info
= NULL
;
202 char *filepath
= NULL
;
207 info
= TALLOC_ZERO_P( NULL
, struct rcinit_file_information
);
212 /* attempt the file open */
214 filepath
= talloc_asprintf(info
, "%s/%s/%s", get_dyn_MODULESDIR(),
215 SVCCTL_SCRIPT_DIR
, servicename
);
220 f
= x_fopen( filepath
, O_RDONLY
, 0 );
222 DEBUG(0,("read_init_file: failed to open [%s]\n", filepath
));
227 while ( (x_fgets( str
, sizeof(str
)-1, f
)) != NULL
) {
228 /* ignore everything that is not a full line
229 comment starting with a '#' */
234 /* Look for a line like '^#.*Description:' */
236 p
= strstr( str
, "Description:" );
240 p
+= strlen( "Description:" ) + 1;
244 desc
= cleanup_string(p
);
246 info
->description
= talloc_strdup( info
, desc
);
252 if ( !info
->description
)
253 info
->description
= talloc_strdup( info
, "External Unix Service" );
255 *service_info
= info
;
256 TALLOC_FREE(filepath
);
261 /********************************************************************
262 This is where we do the dirty work of filling in things like the
263 Display name, Description, etc...
264 ********************************************************************/
266 static void fill_service_values(const char *name
, struct regval_ctr
*values
)
268 char *dname
, *ipath
, *description
;
272 /* These values are hardcoded in all QueryServiceConfig() replies.
273 I'm just storing them here for cosmetic purposes */
275 dword
= SVCCTL_AUTO_START
;
276 regval_ctr_addvalue( values
, "Start", REG_DWORD
, (uint8
*)&dword
, sizeof(uint32
));
278 dword
= SERVICE_TYPE_WIN32_OWN_PROCESS
;
279 regval_ctr_addvalue( values
, "Type", REG_DWORD
, (uint8
*)&dword
, sizeof(uint32
));
281 dword
= SVCCTL_SVC_ERROR_NORMAL
;
282 regval_ctr_addvalue( values
, "ErrorControl", REG_DWORD
, (uint8
*)&dword
, sizeof(uint32
));
284 /* everything runs as LocalSystem */
286 regval_ctr_addvalue_sz(values
, "ObjectName", "LocalSystem");
288 /* special considerations for internal services and the DisplayName value */
290 for ( i
=0; builtin_svcs
[i
].servicename
; i
++ ) {
291 if ( strequal( name
, builtin_svcs
[i
].servicename
) ) {
292 ipath
= talloc_asprintf(talloc_tos(), "%s/%s/%s",
293 get_dyn_MODULESDIR(), SVCCTL_SCRIPT_DIR
,
294 builtin_svcs
[i
].daemon
);
295 description
= talloc_strdup(talloc_tos(), builtin_svcs
[i
].description
);
296 dname
= talloc_strdup(talloc_tos(), builtin_svcs
[i
].dispname
);
301 /* default to an external service if we haven't found a match */
303 if ( builtin_svcs
[i
].servicename
== NULL
) {
304 char *dispname
= NULL
;
305 struct rcinit_file_information
*init_info
= NULL
;
307 ipath
= talloc_asprintf(talloc_tos(), "%s/%s/%s",
308 get_dyn_MODULESDIR(), SVCCTL_SCRIPT_DIR
,
311 /* lookup common unix display names */
312 dispname
= get_common_service_dispname(name
);
313 dname
= talloc_strdup(talloc_tos(), dispname
? dispname
: "");
316 /* get info from init file itself */
317 if ( read_init_file( name
, &init_info
) ) {
318 description
= talloc_strdup(talloc_tos(), init_info
->description
);
319 TALLOC_FREE( init_info
);
322 description
= talloc_strdup(talloc_tos(), "External Unix Service");
326 /* add the new values */
328 regval_ctr_addvalue_sz(values
, "DisplayName", dname
);
329 regval_ctr_addvalue_sz(values
, "ImagePath", ipath
);
330 regval_ctr_addvalue_sz(values
, "Description", description
);
334 TALLOC_FREE(description
);
339 /********************************************************************
340 ********************************************************************/
342 static void add_new_svc_name(struct registry_key_handle
*key_parent
,
343 struct regsubkey_ctr
*subkeys
,
346 struct registry_key_handle
*key_service
= NULL
, *key_secdesc
= NULL
;
349 struct regval_ctr
*values
= NULL
;
350 struct regsubkey_ctr
*svc_subkeys
= NULL
;
351 struct security_descriptor
*sd
= NULL
;
355 /* add to the list and create the subkey path */
357 regsubkey_ctr_addkey( subkeys
, name
);
358 store_reg_keys( key_parent
, subkeys
);
360 /* open the new service key */
362 if (asprintf(&path
, "%s\\%s", KEY_SERVICES
, name
) < 0) {
365 wresult
= regkey_open_internal( NULL
, &key_service
, path
,
366 get_root_nt_token(), REG_KEY_ALL
);
367 if ( !W_ERROR_IS_OK(wresult
) ) {
368 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
369 path
, win_errstr(wresult
)));
375 /* add the 'Security' key */
377 wresult
= regsubkey_ctr_init(key_service
, &svc_subkeys
);
378 if (!W_ERROR_IS_OK(wresult
)) {
379 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
380 TALLOC_FREE( key_service
);
384 fetch_reg_keys( key_service
, svc_subkeys
);
385 regsubkey_ctr_addkey( svc_subkeys
, "Security" );
386 store_reg_keys( key_service
, svc_subkeys
);
388 /* now for the service values */
390 wresult
= regval_ctr_init(key_service
, &values
);
391 if (!W_ERROR_IS_OK(wresult
)) {
392 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
393 TALLOC_FREE( key_service
);
397 fill_service_values( name
, values
);
398 store_reg_values( key_service
, values
);
400 /* cleanup the service key*/
402 TALLOC_FREE( key_service
);
404 /* now add the security descriptor */
406 if (asprintf(&path
, "%s\\%s\\%s", KEY_SERVICES
, name
, "Security") < 0) {
409 wresult
= regkey_open_internal( NULL
, &key_secdesc
, path
,
410 get_root_nt_token(), REG_KEY_ALL
);
411 if ( !W_ERROR_IS_OK(wresult
) ) {
412 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
413 path
, win_errstr(wresult
)));
414 TALLOC_FREE( key_secdesc
);
420 wresult
= regval_ctr_init(key_secdesc
, &values
);
421 if (!W_ERROR_IS_OK(wresult
)) {
422 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
423 TALLOC_FREE( key_secdesc
);
427 if ( !(sd
= construct_service_sd(key_secdesc
)) ) {
428 DEBUG(0,("add_new_svc_name: Failed to create default sec_desc!\n"));
429 TALLOC_FREE( key_secdesc
);
433 status
= marshall_sec_desc(key_secdesc
, sd
, &sd_blob
.data
,
435 if (!NT_STATUS_IS_OK(status
)) {
436 DEBUG(0, ("marshall_sec_desc failed: %s\n",
438 TALLOC_FREE(key_secdesc
);
442 regval_ctr_addvalue(values
, "Security", REG_BINARY
,
443 sd_blob
.data
, sd_blob
.length
);
444 store_reg_values( key_secdesc
, values
);
446 TALLOC_FREE( key_secdesc
);
451 /********************************************************************
452 ********************************************************************/
454 void svcctl_init_keys( void )
456 const char **service_list
= lp_svcctl_list();
458 struct regsubkey_ctr
*subkeys
= NULL
;
459 struct registry_key_handle
*key
= NULL
;
462 /* bad mojo here if the lookup failed. Should not happen */
464 wresult
= regkey_open_internal( NULL
, &key
, KEY_SERVICES
,
465 get_root_nt_token(), REG_KEY_ALL
);
467 if ( !W_ERROR_IS_OK(wresult
) ) {
468 DEBUG(0,("svcctl_init_keys: key lookup failed! (%s)\n",
469 win_errstr(wresult
)));
473 /* lookup the available subkeys */
475 wresult
= regsubkey_ctr_init(key
, &subkeys
);
476 if (!W_ERROR_IS_OK(wresult
)) {
477 DEBUG(0,("svcctl_init_keys: talloc() failed!\n"));
482 fetch_reg_keys( key
, subkeys
);
484 /* the builtin services exist */
486 for ( i
=0; builtin_svcs
[i
].servicename
; i
++ )
487 add_new_svc_name( key
, subkeys
, builtin_svcs
[i
].servicename
);
489 for ( i
=0; service_list
&& service_list
[i
]; i
++ ) {
491 /* only add new services */
492 if ( regsubkey_ctr_key_exists( subkeys
, service_list
[i
] ) )
495 /* Add the new service key and initialize the appropriate values */
497 add_new_svc_name( key
, subkeys
, service_list
[i
] );
502 /* initialize the control hooks */
504 init_service_op_table();
509 /********************************************************************
510 This is where we do the dirty work of filling in things like the
511 Display name, Description, etc...Always return a default secdesc
512 in case of any failure.
513 ********************************************************************/
515 struct security_descriptor
*svcctl_get_secdesc( TALLOC_CTX
*ctx
, const char *name
, struct security_token
*token
)
517 struct registry_key
*key
= NULL
;
518 struct registry_value
*value
;
519 struct security_descriptor
*ret_sd
= NULL
;
523 TALLOC_CTX
*mem_ctx
= talloc_stackframe();
525 path
= talloc_asprintf(mem_ctx
, "%s\\%s\\%s", KEY_SERVICES
, name
,
531 wresult
= reg_open_path(mem_ctx
, path
, REG_KEY_ALL
, token
, &key
);
532 if ( !W_ERROR_IS_OK(wresult
) ) {
533 DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n",
534 path
, win_errstr(wresult
)));
538 wresult
= reg_queryvalue(mem_ctx
, key
, "Security", &value
);
539 if (W_ERROR_EQUAL(wresult
, WERR_BADFILE
)) {
540 goto fallback_to_default_sd
;
541 } else if (!W_ERROR_IS_OK(wresult
)) {
542 DEBUG(0, ("svcctl_get_secdesc: error getting value 'Security': "
543 "%s\n", win_errstr(wresult
)));
547 status
= unmarshall_sec_desc(ctx
, value
->data
.data
,
548 value
->data
.length
, &ret_sd
);
550 if (NT_STATUS_IS_OK(status
)) {
554 fallback_to_default_sd
:
555 DEBUG(6, ("svcctl_get_secdesc: constructing default secdesc for "
556 "service [%s]\n", name
));
557 ret_sd
= construct_service_sd(ctx
);
560 talloc_free(mem_ctx
);
564 /********************************************************************
565 Wrapper to make storing a Service sd easier
566 ********************************************************************/
568 bool svcctl_set_secdesc(const char *name
, struct security_descriptor
*sec_desc
,
569 struct security_token
*token
)
571 struct registry_key
*key
= NULL
;
574 struct registry_value value
;
577 TALLOC_CTX
*mem_ctx
= talloc_stackframe();
579 /* now add the security descriptor */
581 path
= talloc_asprintf(mem_ctx
, "%s\\%s\\%s", KEY_SERVICES
, name
,
587 wresult
= reg_open_path(mem_ctx
, path
, REG_KEY_ALL
, token
, &key
);
589 if ( !W_ERROR_IS_OK(wresult
) ) {
590 DEBUG(0, ("svcctl_set_secdesc: key lookup failed! [%s] (%s)\n",
591 path
, win_errstr(wresult
)));
595 /* stream the printer security descriptor */
597 status
= marshall_sec_desc(mem_ctx
, sec_desc
, &value
.data
.data
,
599 if (!NT_STATUS_IS_OK(status
)) {
600 DEBUG(0,("svcctl_set_secdesc: ndr_push_struct_blob() failed!\n"));
604 value
.type
= REG_BINARY
;
606 wresult
= reg_setvalue(key
, "Security", &value
);
607 if (!W_ERROR_IS_OK(wresult
)) {
608 DEBUG(0, ("svcctl_set_secdesc: reg_setvalue failed: %s\n",
609 win_errstr(wresult
)));
616 talloc_free(mem_ctx
);
620 const char *svcctl_get_string_value(TALLOC_CTX
*ctx
, const char *key_name
,
621 const char *value_name
,
622 struct security_token
*token
)
624 const char *result
= NULL
;
625 struct registry_key
*key
= NULL
;
626 struct registry_value
*value
= NULL
;
629 TALLOC_CTX
*mem_ctx
= talloc_stackframe();
631 path
= talloc_asprintf(mem_ctx
, "%s\\%s", KEY_SERVICES
, key_name
);
636 wresult
= reg_open_path(mem_ctx
, path
, REG_KEY_READ
, token
, &key
);
637 if (!W_ERROR_IS_OK(wresult
)) {
638 DEBUG(0, ("svcctl_get_string_value: key lookup failed! "
639 "[%s] (%s)\n", path
, win_errstr(wresult
)));
643 wresult
= reg_queryvalue(mem_ctx
, key
, value_name
, &value
);
644 if (!W_ERROR_IS_OK(wresult
)) {
645 DEBUG(0, ("svcctl_get_string_value: error getting value "
646 "'%s': %s\n", value_name
, win_errstr(wresult
)));
650 if (value
->type
!= REG_SZ
) {
654 pull_reg_sz(ctx
, &value
->data
, &result
);
659 talloc_free(mem_ctx
);
663 /********************************************************************
664 ********************************************************************/
666 const char *svcctl_lookup_dispname(TALLOC_CTX
*ctx
, const char *name
, struct security_token
*token
)
668 const char *display_name
= NULL
;
670 display_name
= svcctl_get_string_value(ctx
, name
, "DisplayName", token
);
672 if (display_name
== NULL
) {
673 display_name
= talloc_strdup(ctx
, name
);
679 /********************************************************************
680 ********************************************************************/
682 const char *svcctl_lookup_description(TALLOC_CTX
*ctx
, const char *name
, struct security_token
*token
)
684 const char *description
= NULL
;
686 description
= svcctl_get_string_value(ctx
, name
, "Description", token
);
688 if (description
== NULL
) {
689 description
= talloc_strdup(ctx
, "Unix Service");
695 /********************************************************************
696 ********************************************************************/
698 struct regval_ctr
*svcctl_fetch_regvalues(const char *name
, struct security_token
*token
)
700 struct registry_key_handle
*key
= NULL
;
701 struct regval_ctr
*values
= NULL
;
705 /* now add the security descriptor */
707 if (asprintf(&path
, "%s\\%s", KEY_SERVICES
, name
) < 0) {
710 wresult
= regkey_open_internal( NULL
, &key
, path
, token
,
712 if ( !W_ERROR_IS_OK(wresult
) ) {
713 DEBUG(0,("svcctl_fetch_regvalues: key lookup failed! [%s] (%s)\n",
714 path
, win_errstr(wresult
)));
720 wresult
= regval_ctr_init(NULL
, &values
);
721 if (!W_ERROR_IS_OK(wresult
)) {
722 DEBUG(0,("svcctl_fetch_regvalues: talloc() failed!\n"));
726 fetch_reg_values( key
, values
);