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"
33 #include "registry/reg_backend_db.h"
36 #define DBGC_CLASS DBGC_REGISTRY
38 #define TOP_LEVEL_SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services"
40 struct rcinit_file_information {
44 struct service_display_info {
45 const char *servicename;
48 const char *description;
51 static struct service_display_info builtin_svcs[] = {
56 "Internal service for spooling files to print devices"
62 "File service providing access to policy and profile data (not"
63 "remotely manageable)"
68 "Remote Registry Service",
69 "Internal service providing remote access to the Samba registry"
74 "Windows Internet Name Service (WINS)",
75 "Internal service providing a NetBIOS point-to-point name server"
76 "(not remotely manageable)"
78 { NULL, NULL, NULL, NULL }
81 static struct service_display_info common_unix_svcs[] = {
82 { "cups", NULL, "Common Unix Printing System","Provides unified printing support for all operating systems" },
83 { "postfix", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
84 { "sendmail", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" },
85 { "portmap", NULL, "TCP Port to RPC PortMapper",NULL },
86 { "xinetd", NULL, "Internet Meta-Daemon", NULL },
87 { "inet", NULL, "Internet Meta-Daemon", NULL },
88 { "xntpd", NULL, "Network Time Service", NULL },
89 { "ntpd", NULL, "Network Time Service", NULL },
90 { "lpd", NULL, "BSD Print Spooler", NULL },
91 { "nfsserver", NULL, "Network File Service", NULL },
92 { "cron", NULL, "Scheduling Service", NULL },
93 { "at", NULL, "Scheduling Service", NULL },
94 { "nscd", NULL, "Name Service Cache Daemon", NULL },
95 { "slapd", NULL, "LDAP Directory Service", NULL },
96 { "ldap", NULL, "LDAP DIrectory Service", NULL },
97 { "ypbind", NULL, "NIS Directory Service", NULL },
98 { "courier-imap", NULL, "IMAP4 Mail Service", NULL },
99 { "courier-pop3", NULL, "POP3 Mail Service", NULL },
100 { "named", NULL, "Domain Name Service", NULL },
101 { "bind", NULL, "Domain Name Service", NULL },
102 { "httpd", NULL, "HTTP Server", NULL },
103 { "apache", NULL, "HTTP Server", "Provides s highly scalable and flexible web server "
104 "capable of implementing various protocols incluing "
105 "but not limited to HTTP" },
106 { "autofs", NULL, "Automounter", NULL },
107 { "squid", NULL, "Web Cache Proxy ", NULL },
108 { "perfcountd", NULL, "Performance Monitoring Daemon", NULL },
109 { "pgsql", NULL, "PgSQL Database Server", "Provides service for SQL database from Postgresql.org" },
110 { "arpwatch", NULL, "ARP Tables watcher", "Provides service for monitoring ARP tables for changes" },
111 { "dhcpd", NULL, "DHCP Server", "Provides service for dynamic host configuration and IP assignment" },
112 { "nwserv", NULL, "NetWare Server Emulator", "Provides service for emulating Novell NetWare 3.12 server" },
113 { "proftpd", NULL, "Professional FTP Server", "Provides high configurable service for FTP connection and "
114 "file transferring" },
115 { "ssh2", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
116 { "sshd", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" },
117 { NULL, NULL, NULL, NULL }
120 /********************************************************************
121 This is where we do the dirty work of filling in things like the
122 Display name, Description, etc...
123 ********************************************************************/
124 static char *svcctl_get_common_service_dispname(TALLOC_CTX *mem_ctx,
125 const char *servicename)
129 for (i = 0; common_unix_svcs[i].servicename; i++) {
130 if (strequal(servicename, common_unix_svcs[i].servicename)) {
132 dispname = talloc_asprintf(mem_ctx, "%s (%s)",
133 common_unix_svcs[i].dispname,
134 common_unix_svcs[i].servicename);
135 if (dispname == NULL) {
142 return talloc_strdup(mem_ctx, servicename);
145 /********************************************************************
146 ********************************************************************/
147 static char *svcctl_cleanup_string(TALLOC_CTX *mem_ctx,
153 clean = talloc_strdup(mem_ctx, string);
159 /* trim any beginning whilespace */
160 while (isspace(*begin)) {
164 if (*begin == '\0') {
168 /* trim any trailing whitespace or carriage returns.
169 Start at the end and move backwards */
171 end = begin + strlen(begin) - 1;
173 while (isspace(*end) || *end=='\n' || *end=='\r') {
181 /********************************************************************
182 ********************************************************************/
183 static bool read_init_file(TALLOC_CTX *mem_ctx,
184 const char *servicename,
185 struct rcinit_file_information **service_info)
187 struct rcinit_file_information *info = NULL;
188 char *filepath = NULL;
193 info = talloc_zero(mem_ctx, struct rcinit_file_information);
198 /* attempt the file open */
200 filepath = talloc_asprintf(mem_ctx,
202 get_dyn_MODULESDIR(),
205 if (filepath == NULL) {
208 f = x_fopen( filepath, O_RDONLY, 0 );
210 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 '#' */
222 /* Look for a line like '^#.*Description:' */
224 p = strstr(str, "Description:");
228 p += strlen( "Description:" ) + 1;
233 desc = svcctl_cleanup_string(mem_ctx, p);
235 info->description = talloc_strdup(info, desc);
242 if (info->description == NULL) {
243 info->description = talloc_strdup(info,
244 "External Unix Service");
245 if (info->description == NULL) {
250 *service_info = info;
255 static bool svcctl_add_service(TALLOC_CTX *mem_ctx,
256 struct dcerpc_binding_handle *h,
257 struct policy_handle *hive_hnd,
259 uint32_t access_mask,
262 enum winreg_CreateAction action = REG_ACTION_NONE;
263 struct security_descriptor *sd = NULL;
264 struct policy_handle key_hnd;
265 struct winreg_String wkey;
266 struct winreg_String wkeyclass;
267 char *description = NULL;
273 WERROR result = WERR_OK;
275 ZERO_STRUCT(key_hnd);
278 wkey.name = talloc_asprintf(mem_ctx, "%s\\%s", key, name);
279 if (wkey.name == NULL) {
283 ZERO_STRUCT(wkeyclass);
286 status = dcerpc_winreg_CreateKey(h,
297 if (!NT_STATUS_IS_OK(status)) {
298 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
299 wkey.name, nt_errstr(status)));
302 if (!W_ERROR_IS_OK(result)) {
303 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
304 wkey.name, win_errstr(result)));
308 /* These values are hardcoded in all QueryServiceConfig() replies.
309 I'm just storing them here for cosmetic purposes */
310 status = dcerpc_winreg_set_dword(mem_ctx,
316 if (!NT_STATUS_IS_OK(status)) {
317 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
321 if (!W_ERROR_IS_OK(result)) {
322 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
323 win_errstr(result)));
327 status = dcerpc_winreg_set_dword(mem_ctx,
331 SERVICE_TYPE_WIN32_OWN_PROCESS,
333 if (!NT_STATUS_IS_OK(status)) {
334 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
338 if (!W_ERROR_IS_OK(result)) {
339 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
340 win_errstr(result)));
344 status = dcerpc_winreg_set_dword(mem_ctx,
348 SVCCTL_SVC_ERROR_NORMAL,
350 if (!NT_STATUS_IS_OK(status)) {
351 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
355 if (!W_ERROR_IS_OK(result)) {
356 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
357 win_errstr(result)));
361 status = dcerpc_winreg_set_sz(mem_ctx,
367 if (!NT_STATUS_IS_OK(status)) {
368 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
372 if (!W_ERROR_IS_OK(result)) {
373 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
374 win_errstr(result)));
379 * Special considerations for internal services and the DisplayName
382 for (i = 0; builtin_svcs[i].servicename; i++) {
383 if (strequal(name, builtin_svcs[i].servicename)) {
384 ipath = talloc_asprintf(mem_ctx,
386 get_dyn_MODULESDIR(),
388 builtin_svcs[i].daemon);
389 description = talloc_strdup(mem_ctx, builtin_svcs[i].description);
390 dname = talloc_strdup(mem_ctx, builtin_svcs[i].dispname);
395 if (ipath == NULL || dname == NULL || description == NULL) {
399 /* Default to an external service if we haven't found a match */
400 if (builtin_svcs[i].servicename == NULL) {
401 struct rcinit_file_information *init_info = NULL;
402 char *dispname = NULL;
404 ipath = talloc_asprintf(mem_ctx,
406 get_dyn_MODULESDIR(),
410 /* lookup common unix display names */
411 dispname = svcctl_get_common_service_dispname(mem_ctx, name);
412 dname = talloc_strdup(mem_ctx, dispname ? dispname : "");
414 /* get info from init file itself */
415 if (read_init_file(mem_ctx, name, &init_info)) {
416 description = talloc_strdup(mem_ctx,
417 init_info->description);
419 description = talloc_strdup(mem_ctx,
420 "External Unix Service");
424 if (ipath == NULL || dname == NULL || description == NULL) {
428 status = dcerpc_winreg_set_sz(mem_ctx,
434 if (!NT_STATUS_IS_OK(status)) {
435 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
439 if (!W_ERROR_IS_OK(result)) {
440 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
441 win_errstr(result)));
445 status = dcerpc_winreg_set_sz(mem_ctx,
451 if (!NT_STATUS_IS_OK(status)) {
452 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
456 if (!W_ERROR_IS_OK(result)) {
457 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
458 win_errstr(result)));
462 status = dcerpc_winreg_set_sz(mem_ctx,
468 if (!NT_STATUS_IS_OK(status)) {
469 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
473 if (!W_ERROR_IS_OK(result)) {
474 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
475 win_errstr(result)));
479 sd = svcctl_gen_service_sd(mem_ctx);
481 DEBUG(0, ("add_new_svc_name: Failed to create default "
486 if (is_valid_policy_hnd(&key_hnd)) {
487 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
489 ZERO_STRUCT(key_hnd);
492 wkey.name = talloc_asprintf(mem_ctx, "%s\\%s\\Security", key, name);
493 if (wkey.name == NULL) {
498 ZERO_STRUCT(wkeyclass);
501 status = dcerpc_winreg_CreateKey(h,
512 if (!NT_STATUS_IS_OK(status)) {
513 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
514 wkey.name, nt_errstr(status)));
517 if (!W_ERROR_IS_OK(result)) {
518 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
519 wkey.name, win_errstr(result)));
523 status = dcerpc_winreg_set_sd(mem_ctx,
529 if (!NT_STATUS_IS_OK(status)) {
530 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
534 if (!W_ERROR_IS_OK(result)) {
535 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
536 win_errstr(result)));
542 if (is_valid_policy_hnd(&key_hnd)) {
543 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
549 bool svcctl_init_winreg(struct messaging_context *msg_ctx)
551 struct dcerpc_binding_handle *h = NULL;
552 uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
553 struct policy_handle hive_hnd, key_hnd;
554 const char **service_list = lp_svcctl_list();
555 const char **subkeys = NULL;
556 uint32_t num_subkeys = 0;
560 WERROR result = WERR_OK;
564 tmp_ctx = talloc_stackframe();
565 if (tmp_ctx == NULL) {
569 DEBUG(3, ("Initialise the svcctl registry keys if needed.\n"));
571 ZERO_STRUCT(hive_hnd);
572 ZERO_STRUCT(key_hnd);
574 key = talloc_strdup(tmp_ctx, TOP_LEVEL_SERVICES_KEY);
579 result = regdb_open();
580 if (!W_ERROR_IS_OK(result)) {
581 DEBUG(10, ("regdb_open failed: %s\n",
582 win_errstr(result)));
585 result = regdb_transaction_start();
586 if (!W_ERROR_IS_OK(result)) {
587 DEBUG(10, ("regdb_transaction_start failed: %s\n",
588 win_errstr(result)));
592 status = dcerpc_winreg_int_hklm_openkey(tmp_ctx,
593 get_session_info_system(),
602 if (!NT_STATUS_IS_OK(status)) {
603 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
604 key, nt_errstr(status)));
607 if (!W_ERROR_IS_OK(result)) {
608 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
609 key, win_errstr(result)));
613 /* get all subkeys */
614 status = dcerpc_winreg_enum_keys(tmp_ctx,
620 if (!NT_STATUS_IS_OK(status)) {
621 DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n",
622 key, nt_errstr(status)));
625 if (!W_ERROR_IS_OK(result)) {
626 DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n",
627 key, win_errstr(result)));
631 for (i = 0; builtin_svcs[i].servicename != NULL; i++) {
635 for (j = 0; j < num_subkeys; j++) {
636 if (strequal(subkeys[i], builtin_svcs[i].servicename)) {
645 ok = svcctl_add_service(tmp_ctx,
650 builtin_svcs[i].servicename);
656 for (i = 0; service_list && service_list[i]; i++) {
660 for (j = 0; j < num_subkeys; j++) {
661 if (strequal(subkeys[i], service_list[i])) {
670 ok = svcctl_add_service(tmp_ctx,
676 if (is_valid_policy_hnd(&key_hnd)) {
677 dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
679 ZERO_STRUCT(key_hnd);
687 if (is_valid_policy_hnd(&key_hnd)) {
688 dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
692 result = regdb_transaction_commit();
693 if (!W_ERROR_IS_OK(result)) {
694 DEBUG(10, ("regdb_transaction_commit failed: %s\n",
695 win_errstr(result)));
698 result = regdb_transaction_cancel();
699 if (!W_ERROR_IS_OK(result)) {
700 DEBUG(10, ("regdb_transaction_cancel failed: %s\n",
701 win_errstr(result)));
705 talloc_free(tmp_ctx);
709 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */