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 "system/filesys.h"
26 #include "services/services.h"
27 #include "services/svc_winreg_glue.h"
28 #include "../librpc/gen_ndr/ndr_winreg_c.h"
29 #include "rpc_client/cli_winreg_int.h"
30 #include "rpc_client/cli_winreg.h"
31 #include "rpc_server/svcctl/srv_svcctl_reg.h"
35 #define DBGC_CLASS DBGC_REGISTRY
37 #define TOP_LEVEL_SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services"
39 struct rcinit_file_information {
43 struct service_display_info {
44 const char *servicename;
47 const char *description;
50 static struct service_display_info builtin_svcs[] = {
55 "Internal service for spooling files to print devices"
61 "File service providing access to policy and profile data (not"
62 "remotely manageable)"
67 "Remote Registry Service",
68 "Internal service providing remote access to the Samba registry"
73 "Windows Internet Name Service (WINS)",
74 "Internal service providing a NetBIOS point-to-point name server"
75 "(not remotely manageable)"
77 { NULL, NULL, NULL, NULL }
80 static struct service_display_info common_unix_svcs[] = {
81 { "cups", NULL, "Common Unix Printing System","Provides unified printing support for all operating systems" },
82 { "postfix", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
83 { "sendmail", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
84 { "portmap", NULL, "TCP Port to RPC PortMapper",NULL },
85 { "xinetd", NULL, "Internet Meta-Daemon", NULL },
86 { "inet", NULL, "Internet Meta-Daemon", NULL },
87 { "xntpd", NULL, "Network Time Service", NULL },
88 { "ntpd", NULL, "Network Time Service", NULL },
89 { "lpd", NULL, "BSD Print Spooler", NULL },
90 { "nfsserver", NULL, "Network File Service", NULL },
91 { "cron", NULL, "Scheduling Service", NULL },
92 { "at", NULL, "Scheduling Service", NULL },
93 { "nscd", NULL, "Name Service Cache Daemon", NULL },
94 { "slapd", NULL, "LDAP Directory Service", NULL },
95 { "ldap", NULL, "LDAP DIrectory Service", NULL },
96 { "ypbind", NULL, "NIS Directory Service", NULL },
97 { "courier-imap", NULL, "IMAP4 Mail Service", NULL },
98 { "courier-pop3", NULL, "POP3 Mail Service", NULL },
99 { "named", NULL, "Domain Name Service", NULL },
100 { "bind", NULL, "Domain Name Service", NULL },
101 { "httpd", NULL, "HTTP Server", NULL },
102 { "apache", NULL, "HTTP Server", "Provides s highly scalable and flexible web server "
103 "capable of implementing various protocols incluing "
104 "but not limited to HTTP" },
105 { "autofs", NULL, "Automounter", NULL },
106 { "squid", NULL, "Web Cache Proxy ", NULL },
107 { "perfcountd", NULL, "Performance Monitoring Daemon", NULL },
108 { "pgsql", NULL, "PgSQL Database Server", "Provides service for SQL database from Postgresql.org" },
109 { "arpwatch", NULL, "ARP Tables watcher", "Provides service for monitoring ARP tables for changes" },
110 { "dhcpd", NULL, "DHCP Server", "Provides service for dynamic host configuration and IP assignment" },
111 { "nwserv", NULL, "NetWare Server Emulator", "Provides service for emulating Novell NetWare 3.12 server" },
112 { "proftpd", NULL, "Professional FTP Server", "Provides high configurable service for FTP connection and "
113 "file transferring" },
114 { "ssh2", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
115 { "sshd", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
116 { NULL, NULL, NULL, NULL }
119 /********************************************************************
120 This is where we do the dirty work of filling in things like the
121 Display name, Description, etc...
122 ********************************************************************/
123 static char *svcctl_get_common_service_dispname(TALLOC_CTX *mem_ctx,
124 const char *servicename)
128 for (i = 0; common_unix_svcs[i].servicename; i++) {
129 if (strequal(servicename, common_unix_svcs[i].servicename)) {
131 dispname = talloc_asprintf(mem_ctx, "%s (%s)",
132 common_unix_svcs[i].dispname,
133 common_unix_svcs[i].servicename);
134 if (dispname == NULL) {
141 return talloc_strdup(mem_ctx, servicename);
144 /********************************************************************
145 ********************************************************************/
146 static char *svcctl_cleanup_string(TALLOC_CTX *mem_ctx,
152 clean = talloc_strdup(mem_ctx, string);
158 /* trim any beginning whilespace */
159 while (isspace(*begin)) {
163 if (*begin == '\0') {
167 /* trim any trailing whitespace or carriage returns.
168 Start at the end and move backwards */
170 end = begin + strlen(begin) - 1;
172 while (isspace(*end) || *end=='\n' || *end=='\r') {
180 /********************************************************************
181 ********************************************************************/
182 static bool read_init_file(TALLOC_CTX *mem_ctx,
183 const char *servicename,
184 struct rcinit_file_information **service_info)
186 struct rcinit_file_information *info = NULL;
187 char *filepath = NULL;
192 info = talloc_zero(mem_ctx, struct rcinit_file_information);
197 /* attempt the file open */
199 filepath = talloc_asprintf(mem_ctx,
201 get_dyn_MODULESDIR(),
204 if (filepath == NULL) {
207 f = x_fopen( filepath, O_RDONLY, 0 );
209 DEBUG(0,("read_init_file: failed to open [%s]\n", filepath));
213 while ((x_fgets(str, sizeof(str) - 1, f)) != NULL) {
214 /* ignore everything that is not a full line
215 comment starting with a '#' */
221 /* Look for a line like '^#.*Description:' */
223 p = strstr(str, "Description:");
227 p += strlen( "Description:" ) + 1;
232 desc = svcctl_cleanup_string(mem_ctx, p);
234 info->description = talloc_strdup(info, desc);
241 if (info->description == NULL) {
242 info->description = talloc_strdup(info,
243 "External Unix Service");
244 if (info->description == NULL) {
249 *service_info = info;
254 static bool svcctl_add_service(TALLOC_CTX *mem_ctx,
255 struct dcerpc_binding_handle *h,
256 struct policy_handle *hive_hnd,
258 uint32_t access_mask,
261 enum winreg_CreateAction action = REG_ACTION_NONE;
262 struct security_descriptor *sd = NULL;
263 struct policy_handle key_hnd;
264 struct winreg_String wkey;
265 struct winreg_String wkeyclass;
266 char *description = NULL;
272 WERROR result = WERR_OK;
274 ZERO_STRUCT(key_hnd);
277 wkey.name = talloc_asprintf(mem_ctx, "%s\\%s", key, name);
278 if (wkey.name == NULL) {
282 ZERO_STRUCT(wkeyclass);
285 status = dcerpc_winreg_CreateKey(h,
296 if (!NT_STATUS_IS_OK(status)) {
297 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
298 wkey.name, nt_errstr(status)));
301 if (!W_ERROR_IS_OK(result)) {
302 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
303 wkey.name, win_errstr(result)));
307 /* These values are hardcoded in all QueryServiceConfig() replies.
308 I'm just storing them here for cosmetic purposes */
309 status = dcerpc_winreg_set_dword(mem_ctx,
315 if (!NT_STATUS_IS_OK(status)) {
316 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
320 if (!W_ERROR_IS_OK(result)) {
321 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
322 win_errstr(result)));
326 status = dcerpc_winreg_set_dword(mem_ctx,
330 SERVICE_TYPE_WIN32_OWN_PROCESS,
332 if (!NT_STATUS_IS_OK(status)) {
333 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
337 if (!W_ERROR_IS_OK(result)) {
338 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
339 win_errstr(result)));
343 status = dcerpc_winreg_set_dword(mem_ctx,
347 SVCCTL_SVC_ERROR_NORMAL,
349 if (!NT_STATUS_IS_OK(status)) {
350 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
354 if (!W_ERROR_IS_OK(result)) {
355 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
356 win_errstr(result)));
360 status = dcerpc_winreg_set_sz(mem_ctx,
366 if (!NT_STATUS_IS_OK(status)) {
367 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
371 if (!W_ERROR_IS_OK(result)) {
372 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
373 win_errstr(result)));
378 * Special considerations for internal services and the DisplayName
381 for (i = 0; builtin_svcs[i].servicename; i++) {
382 if (strequal(name, builtin_svcs[i].servicename)) {
383 ipath = talloc_asprintf(mem_ctx,
385 get_dyn_MODULESDIR(),
387 builtin_svcs[i].daemon);
388 description = talloc_strdup(mem_ctx, builtin_svcs[i].description);
389 dname = talloc_strdup(mem_ctx, builtin_svcs[i].dispname);
394 if (ipath == NULL || dname == NULL || description == NULL) {
398 /* Default to an external service if we haven't found a match */
399 if (builtin_svcs[i].servicename == NULL) {
400 struct rcinit_file_information *init_info = NULL;
401 char *dispname = NULL;
403 ipath = talloc_asprintf(mem_ctx,
405 get_dyn_MODULESDIR(),
409 /* lookup common unix display names */
410 dispname = svcctl_get_common_service_dispname(mem_ctx, name);
411 dname = talloc_strdup(mem_ctx, dispname ? dispname : "");
413 /* get info from init file itself */
414 if (read_init_file(mem_ctx, name, &init_info)) {
415 description = talloc_strdup(mem_ctx,
416 init_info->description);
418 description = talloc_strdup(mem_ctx,
419 "External Unix Service");
423 if (ipath == NULL || dname == NULL || description == NULL) {
427 status = dcerpc_winreg_set_sz(mem_ctx,
433 if (!NT_STATUS_IS_OK(status)) {
434 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
438 if (!W_ERROR_IS_OK(result)) {
439 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
440 win_errstr(result)));
444 status = dcerpc_winreg_set_sz(mem_ctx,
450 if (!NT_STATUS_IS_OK(status)) {
451 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
455 if (!W_ERROR_IS_OK(result)) {
456 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
457 win_errstr(result)));
461 status = dcerpc_winreg_set_sz(mem_ctx,
467 if (!NT_STATUS_IS_OK(status)) {
468 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
472 if (!W_ERROR_IS_OK(result)) {
473 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
474 win_errstr(result)));
478 sd = svcctl_gen_service_sd(mem_ctx);
480 DEBUG(0, ("add_new_svc_name: Failed to create default "
485 if (is_valid_policy_hnd(&key_hnd)) {
486 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
488 ZERO_STRUCT(key_hnd);
491 wkey.name = talloc_asprintf(mem_ctx, "%s\\%s\\Security", key, name);
492 if (wkey.name == NULL) {
497 ZERO_STRUCT(wkeyclass);
500 status = dcerpc_winreg_CreateKey(h,
511 if (!NT_STATUS_IS_OK(status)) {
512 DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n",
513 wkey.name, nt_errstr(status)));
516 if (!W_ERROR_IS_OK(result)) {
517 DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n",
518 wkey.name, win_errstr(result)));
522 status = dcerpc_winreg_set_sd(mem_ctx,
528 if (!NT_STATUS_IS_OK(status)) {
529 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
533 if (!W_ERROR_IS_OK(result)) {
534 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
535 win_errstr(result)));
541 if (is_valid_policy_hnd(&key_hnd)) {
542 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
548 bool svcctl_init_winreg(struct messaging_context *msg_ctx)
550 struct dcerpc_binding_handle *h = NULL;
551 uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
552 struct policy_handle hive_hnd, key_hnd;
553 const char **service_list = lp_svcctl_list();
554 const char **subkeys = NULL;
555 uint32_t num_subkeys = 0;
559 WERROR result = WERR_OK;
563 tmp_ctx = talloc_stackframe();
564 if (tmp_ctx == NULL) {
568 DEBUG(3, ("Initialise the svcctl registry keys if needed.\n"));
570 ZERO_STRUCT(hive_hnd);
571 ZERO_STRUCT(key_hnd);
573 key = talloc_strdup(tmp_ctx, TOP_LEVEL_SERVICES_KEY);
578 status = dcerpc_winreg_int_hklm_openkey(tmp_ctx,
579 get_session_info_system(),
588 if (!NT_STATUS_IS_OK(status)) {
589 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
590 key, nt_errstr(status)));
593 if (!W_ERROR_IS_OK(result)) {
594 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
595 key, win_errstr(result)));
599 /* get all subkeys */
600 status = dcerpc_winreg_enum_keys(tmp_ctx,
606 if (!NT_STATUS_IS_OK(status)) {
607 DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n",
608 key, nt_errstr(status)));
611 if (!W_ERROR_IS_OK(result)) {
612 DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n",
613 key, win_errstr(result)));
617 for (i = 0; builtin_svcs[i].servicename != NULL; i++) {
621 for (j = 0; j < num_subkeys; j++) {
622 if (strequal(subkeys[i], builtin_svcs[i].servicename)) {
631 ok = svcctl_add_service(tmp_ctx,
636 builtin_svcs[i].servicename);
642 for (i = 0; service_list && service_list[i]; i++) {
646 for (j = 0; j < num_subkeys; j++) {
647 if (strequal(subkeys[i], service_list[i])) {
656 ok = svcctl_add_service(tmp_ctx,
662 if (is_valid_policy_hnd(&key_hnd)) {
663 dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
665 ZERO_STRUCT(key_hnd);
673 if (is_valid_policy_hnd(&key_hnd)) {
674 dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
680 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */