2 * Unix SMB/CIFS implementation.
4 * SVCCTL RPC server keys initialization
6 * Copyright (c) 2005 Marcin Krzysztof Porwit
7 * Copyright (c) 2005 Gerald (Jerry) Carter
8 * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
25 #include "services/services.h"
26 #include "services/svc_winreg_glue.h"
27 #include "../librpc/gen_ndr/ndr_winreg_c.h"
28 #include "rpc_client/cli_winreg_int.h"
29 #include "rpc_client/cli_winreg.h"
30 #include "rpc_server/svcctl/srv_svcctl_reg.h"
33 #define DBGC_CLASS DBGC_REGISTRY
35 #define TOP_LEVEL_SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services"
37 struct rcinit_file_information {
41 struct service_display_info {
42 const char *servicename;
45 const char *description;
48 static struct service_display_info builtin_svcs[] = {
53 "Internal service for spooling files to print devices"
59 "File service providing access to policy and profile data (not"
60 "remotely manageable)"
65 "Remote Registry Service",
66 "Internal service providing remote access to the Samba registry"
71 "Windows Internet Name Service (WINS)",
72 "Internal service providing a NetBIOS point-to-point name server"
73 "(not remotely manageable)"
75 { NULL, NULL, NULL, NULL }
78 static struct service_display_info common_unix_svcs[] = {
79 { "cups", NULL, "Common Unix Printing System","Provides unified printing support for all operating systems" },
80 { "postfix", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
81 { "sendmail", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
82 { "portmap", NULL, "TCP Port to RPC PortMapper",NULL },
83 { "xinetd", NULL, "Internet Meta-Daemon", NULL },
84 { "inet", NULL, "Internet Meta-Daemon", NULL },
85 { "xntpd", NULL, "Network Time Service", NULL },
86 { "ntpd", NULL, "Network Time Service", NULL },
87 { "lpd", NULL, "BSD Print Spooler", NULL },
88 { "nfsserver", NULL, "Network File Service", NULL },
89 { "cron", NULL, "Scheduling Service", NULL },
90 { "at", NULL, "Scheduling Service", NULL },
91 { "nscd", NULL, "Name Service Cache Daemon", NULL },
92 { "slapd", NULL, "LDAP Directory Service", NULL },
93 { "ldap", NULL, "LDAP DIrectory Service", NULL },
94 { "ypbind", NULL, "NIS Directory Service", NULL },
95 { "courier-imap", NULL, "IMAP4 Mail Service", NULL },
96 { "courier-pop3", NULL, "POP3 Mail Service", NULL },
97 { "named", NULL, "Domain Name Service", NULL },
98 { "bind", NULL, "Domain Name Service", NULL },
99 { "httpd", NULL, "HTTP Server", NULL },
100 { "apache", NULL, "HTTP Server", "Provides s highly scalable and flexible web server "
101 "capable of implementing various protocols incluing "
102 "but not limited to HTTP" },
103 { "autofs", NULL, "Automounter", NULL },
104 { "squid", NULL, "Web Cache Proxy ", NULL },
105 { "perfcountd", NULL, "Performance Monitoring Daemon", NULL },
106 { "pgsql", NULL, "PgSQL Database Server", "Provides service for SQL database from Postgresql.org" },
107 { "arpwatch", NULL, "ARP Tables watcher", "Provides service for monitoring ARP tables for changes" },
108 { "dhcpd", NULL, "DHCP Server", "Provides service for dynamic host configuration and IP assignment" },
109 { "nwserv", NULL, "NetWare Server Emulator", "Provides service for emulating Novell NetWare 3.12 server" },
110 { "proftpd", NULL, "Professional FTP Server", "Provides high configurable service for FTP connection and "
111 "file transferring" },
112 { "ssh2", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
113 { "sshd", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
114 { NULL, NULL, NULL, NULL }
117 /********************************************************************
118 This is where we do the dirty work of filling in things like the
119 Display name, Description, etc...
120 ********************************************************************/
121 static char *svcctl_get_common_service_dispname(TALLOC_CTX *mem_ctx,
122 const char *servicename)
126 for (i = 0; common_unix_svcs[i].servicename; i++) {
127 if (strequal(servicename, common_unix_svcs[i].servicename)) {
129 dispname = talloc_asprintf(mem_ctx, "%s (%s)",
130 common_unix_svcs[i].dispname,
131 common_unix_svcs[i].servicename);
132 if (dispname == NULL) {
139 return talloc_strdup(mem_ctx, servicename);
142 /********************************************************************
143 ********************************************************************/
144 static char *svcctl_cleanup_string(TALLOC_CTX *mem_ctx,
150 clean = talloc_strdup(mem_ctx, string);
156 /* trim any beginning whilespace */
157 while (isspace(*begin)) {
161 if (*begin == '\0') {
165 /* trim any trailing whitespace or carriage returns.
166 Start at the end and move backwards */
168 end = begin + strlen(begin) - 1;
170 while (isspace(*end) || *end=='\n' || *end=='\r') {
178 /********************************************************************
179 ********************************************************************/
180 static bool read_init_file(TALLOC_CTX *mem_ctx,
181 const char *servicename,
182 struct rcinit_file_information **service_info)
184 struct rcinit_file_information *info = NULL;
185 char *filepath = NULL;
190 info = talloc_zero(mem_ctx, struct rcinit_file_information);
195 /* attempt the file open */
197 filepath = talloc_asprintf(mem_ctx,
199 get_dyn_MODULESDIR(),
202 if (filepath == NULL) {
205 f = x_fopen( filepath, O_RDONLY, 0 );
207 DEBUG(0,("read_init_file: failed to open [%s]\n", filepath));
211 while ((x_fgets(str, sizeof(str) - 1, f)) != NULL) {
212 /* ignore everything that is not a full line
213 comment starting with a '#' */
219 /* Look for a line like '^#.*Description:' */
221 p = strstr(str, "Description:");
225 p += strlen( "Description:" ) + 1;
230 desc = svcctl_cleanup_string(mem_ctx, p);
232 info->description = talloc_strdup(info, desc);
239 if (info->description == NULL) {
240 info->description = talloc_strdup(info,
241 "External Unix Service");
242 if (info->description == NULL) {
247 *service_info = info;
252 static bool svcctl_add_service(TALLOC_CTX *mem_ctx,
253 struct dcerpc_binding_handle *h,
254 struct policy_handle *hive_hnd,
256 uint32_t access_mask,
259 enum winreg_CreateAction action = REG_ACTION_NONE;
260 struct security_descriptor *sd = NULL;
261 struct policy_handle key_hnd;
262 struct winreg_String wkey;
263 struct winreg_String wkeyclass;
264 char *description = NULL;
270 WERROR result = WERR_OK;
272 ZERO_STRUCT(key_hnd);
275 wkey.name = talloc_asprintf(mem_ctx, "%s\\%s", key, name);
276 if (wkey.name == NULL) {
280 ZERO_STRUCT(wkeyclass);
283 status = dcerpc_winreg_CreateKey(h,
294 if (!NT_STATUS_IS_OK(status)) {
295 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
296 wkey.name, nt_errstr(status)));
299 if (!W_ERROR_IS_OK(result)) {
300 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
301 wkey.name, win_errstr(result)));
305 /* These values are hardcoded in all QueryServiceConfig() replies.
306 I'm just storing them here for cosmetic purposes */
307 status = dcerpc_winreg_set_dword(mem_ctx,
313 if (!NT_STATUS_IS_OK(status)) {
314 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
318 if (!W_ERROR_IS_OK(result)) {
319 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
320 win_errstr(result)));
324 status = dcerpc_winreg_set_dword(mem_ctx,
328 SERVICE_TYPE_WIN32_OWN_PROCESS,
330 if (!NT_STATUS_IS_OK(status)) {
331 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
335 if (!W_ERROR_IS_OK(result)) {
336 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
337 win_errstr(result)));
341 status = dcerpc_winreg_set_dword(mem_ctx,
345 SVCCTL_SVC_ERROR_NORMAL,
347 if (!NT_STATUS_IS_OK(status)) {
348 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
352 if (!W_ERROR_IS_OK(result)) {
353 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
354 win_errstr(result)));
358 status = dcerpc_winreg_set_sz(mem_ctx,
364 if (!NT_STATUS_IS_OK(status)) {
365 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
369 if (!W_ERROR_IS_OK(result)) {
370 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
371 win_errstr(result)));
376 * Special considerations for internal services and the DisplayName
379 for (i = 0; builtin_svcs[i].servicename; i++) {
380 if (strequal(name, builtin_svcs[i].servicename)) {
381 ipath = talloc_asprintf(mem_ctx,
383 get_dyn_MODULESDIR(),
385 builtin_svcs[i].daemon);
386 description = talloc_strdup(mem_ctx, builtin_svcs[i].description);
387 dname = talloc_strdup(mem_ctx, builtin_svcs[i].dispname);
392 if (ipath == NULL || dname == NULL || description == NULL) {
396 /* Default to an external service if we haven't found a match */
397 if (builtin_svcs[i].servicename == NULL) {
398 struct rcinit_file_information *init_info = NULL;
399 char *dispname = NULL;
401 ipath = talloc_asprintf(mem_ctx,
403 get_dyn_MODULESDIR(),
407 /* lookup common unix display names */
408 dispname = svcctl_get_common_service_dispname(mem_ctx, name);
409 dname = talloc_strdup(mem_ctx, dispname ? dispname : "");
411 /* get info from init file itself */
412 if (read_init_file(mem_ctx, name, &init_info)) {
413 description = talloc_strdup(mem_ctx,
414 init_info->description);
416 description = talloc_strdup(mem_ctx,
417 "External Unix Service");
421 if (ipath == NULL || dname == NULL || description == NULL) {
425 status = dcerpc_winreg_set_sz(mem_ctx,
431 if (!NT_STATUS_IS_OK(status)) {
432 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
436 if (!W_ERROR_IS_OK(result)) {
437 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
438 win_errstr(result)));
442 status = dcerpc_winreg_set_sz(mem_ctx,
448 if (!NT_STATUS_IS_OK(status)) {
449 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
453 if (!W_ERROR_IS_OK(result)) {
454 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
455 win_errstr(result)));
459 status = dcerpc_winreg_set_sz(mem_ctx,
465 if (!NT_STATUS_IS_OK(status)) {
466 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
470 if (!W_ERROR_IS_OK(result)) {
471 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
472 win_errstr(result)));
476 sd = svcctl_gen_service_sd(mem_ctx);
478 DEBUG(0, ("add_new_svc_name: Failed to create default "
483 if (is_valid_policy_hnd(&key_hnd)) {
484 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
486 ZERO_STRUCT(key_hnd);
489 wkey.name = talloc_asprintf(mem_ctx, "%s\\%s\\Security", key, name);
490 if (wkey.name == NULL) {
495 ZERO_STRUCT(wkeyclass);
498 status = dcerpc_winreg_CreateKey(h,
509 if (!NT_STATUS_IS_OK(status)) {
510 DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n",
511 wkey.name, nt_errstr(status)));
514 if (!W_ERROR_IS_OK(result)) {
515 DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n",
516 wkey.name, win_errstr(result)));
520 status = dcerpc_winreg_set_sd(mem_ctx,
526 if (!NT_STATUS_IS_OK(status)) {
527 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
531 if (!W_ERROR_IS_OK(result)) {
532 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
533 win_errstr(result)));
539 if (is_valid_policy_hnd(&key_hnd)) {
540 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
546 bool svcctl_init_winreg(struct messaging_context *msg_ctx)
548 struct dcerpc_binding_handle *h = NULL;
549 uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
550 struct policy_handle hive_hnd, key_hnd;
551 const char **service_list = lp_svcctl_list();
552 const char **subkeys = NULL;
553 uint32_t num_subkeys = 0;
557 WERROR result = WERR_OK;
561 tmp_ctx = talloc_stackframe();
562 if (tmp_ctx == NULL) {
566 DEBUG(3, ("Initialise the svcctl registry keys if needed.\n"));
568 ZERO_STRUCT(hive_hnd);
569 ZERO_STRUCT(key_hnd);
571 key = talloc_strdup(tmp_ctx, TOP_LEVEL_SERVICES_KEY);
576 status = dcerpc_winreg_int_hklm_openkey(tmp_ctx,
577 get_server_info_system(),
586 if (!NT_STATUS_IS_OK(status)) {
587 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
588 key, nt_errstr(status)));
591 if (!W_ERROR_IS_OK(result)) {
592 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
593 key, win_errstr(result)));
597 /* get all subkeys */
598 status = dcerpc_winreg_enum_keys(tmp_ctx,
604 if (!NT_STATUS_IS_OK(status)) {
605 DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n",
606 key, nt_errstr(status)));
609 if (!W_ERROR_IS_OK(result)) {
610 DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n",
611 key, win_errstr(result)));
615 for (i = 0; builtin_svcs[i].servicename != NULL; i++) {
619 for (j = 0; j < num_subkeys; j++) {
620 if (strequal(subkeys[i], builtin_svcs[i].servicename)) {
629 ok = svcctl_add_service(tmp_ctx,
634 builtin_svcs[i].servicename);
640 for (i = 0; service_list && service_list[i]; i++) {
644 for (j = 0; j < num_subkeys; j++) {
645 if (strequal(subkeys[i], service_list[i])) {
654 ok = svcctl_add_service(tmp_ctx,
660 if (is_valid_policy_hnd(&key_hnd)) {
661 dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
663 ZERO_STRUCT(key_hnd);
671 if (is_valid_policy_hnd(&key_hnd)) {
672 dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
678 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */