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:");
227 size_t len
= strlen(p
);
233 desc
= svcctl_cleanup_string(mem_ctx
, p
+ 12);
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 /* Default to an external service if we haven't found a match */
396 if (builtin_svcs
[i
].servicename
== NULL
) {
397 struct rcinit_file_information
*init_info
= NULL
;
398 char *dispname
= NULL
;
400 ipath
= talloc_asprintf(mem_ctx
,
402 get_dyn_MODULESDIR(),
406 /* lookup common unix display names */
407 dispname
= svcctl_get_common_service_dispname(mem_ctx
, name
);
408 dname
= talloc_strdup(mem_ctx
, dispname
? dispname
: "");
410 /* get info from init file itself */
411 if (read_init_file(mem_ctx
, name
, &init_info
)) {
412 description
= talloc_strdup(mem_ctx
,
413 init_info
->description
);
415 description
= talloc_strdup(mem_ctx
,
416 "External Unix Service");
420 if (ipath
== NULL
|| dname
== NULL
|| description
== NULL
) {
424 status
= dcerpc_winreg_set_sz(mem_ctx
,
430 if (!NT_STATUS_IS_OK(status
)) {
431 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
435 if (!W_ERROR_IS_OK(result
)) {
436 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
437 win_errstr(result
)));
441 status
= dcerpc_winreg_set_sz(mem_ctx
,
447 if (!NT_STATUS_IS_OK(status
)) {
448 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
452 if (!W_ERROR_IS_OK(result
)) {
453 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
454 win_errstr(result
)));
458 status
= dcerpc_winreg_set_sz(mem_ctx
,
464 if (!NT_STATUS_IS_OK(status
)) {
465 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
469 if (!W_ERROR_IS_OK(result
)) {
470 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
471 win_errstr(result
)));
475 sd
= svcctl_gen_service_sd(mem_ctx
);
477 DEBUG(0, ("add_new_svc_name: Failed to create default "
482 if (is_valid_policy_hnd(&key_hnd
)) {
483 dcerpc_winreg_CloseKey(h
, mem_ctx
, &key_hnd
, &result
);
485 ZERO_STRUCT(key_hnd
);
488 wkey
.name
= talloc_asprintf(mem_ctx
, "%s\\%s\\Security", key
, name
);
489 if (wkey
.name
== NULL
) {
494 ZERO_STRUCT(wkeyclass
);
497 status
= dcerpc_winreg_CreateKey(h
,
508 if (!NT_STATUS_IS_OK(status
)) {
509 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
510 wkey
.name
, nt_errstr(status
)));
513 if (!W_ERROR_IS_OK(result
)) {
514 DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n",
515 wkey
.name
, win_errstr(result
)));
519 status
= dcerpc_winreg_set_sd(mem_ctx
,
525 if (!NT_STATUS_IS_OK(status
)) {
526 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
530 if (!W_ERROR_IS_OK(result
)) {
531 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
532 win_errstr(result
)));
538 if (is_valid_policy_hnd(&key_hnd
)) {
539 dcerpc_winreg_CloseKey(h
, mem_ctx
, &key_hnd
, &result
);
545 bool svcctl_init_winreg(struct messaging_context
*msg_ctx
)
547 struct dcerpc_binding_handle
*h
= NULL
;
548 uint32_t access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
549 struct policy_handle hive_hnd
, key_hnd
;
550 const char **service_list
= lp_svcctl_list();
551 const char **subkeys
= NULL
;
552 uint32_t num_subkeys
= 0;
556 WERROR result
= WERR_OK
;
560 tmp_ctx
= talloc_stackframe();
561 if (tmp_ctx
== NULL
) {
565 DEBUG(3, ("Initialise the svcctl registry keys if needed.\n"));
567 ZERO_STRUCT(hive_hnd
);
568 ZERO_STRUCT(key_hnd
);
570 key
= talloc_strdup(tmp_ctx
, TOP_LEVEL_SERVICES_KEY
);
575 result
= regdb_open();
576 if (!W_ERROR_IS_OK(result
)) {
577 DEBUG(10, ("regdb_open failed: %s\n",
578 win_errstr(result
)));
581 result
= regdb_transaction_start();
582 if (!W_ERROR_IS_OK(result
)) {
583 DEBUG(10, ("regdb_transaction_start failed: %s\n",
584 win_errstr(result
)));
588 status
= dcerpc_winreg_int_hklm_openkey(tmp_ctx
,
589 get_session_info_system(),
598 if (!NT_STATUS_IS_OK(status
)) {
599 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
600 key
, nt_errstr(status
)));
603 if (!W_ERROR_IS_OK(result
)) {
604 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
605 key
, win_errstr(result
)));
609 /* get all subkeys */
610 status
= dcerpc_winreg_enum_keys(tmp_ctx
,
616 if (!NT_STATUS_IS_OK(status
)) {
617 DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n",
618 key
, nt_errstr(status
)));
621 if (!W_ERROR_IS_OK(result
)) {
622 DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n",
623 key
, win_errstr(result
)));
627 for (i
= 0; builtin_svcs
[i
].servicename
!= NULL
; i
++) {
631 for (j
= 0; j
< num_subkeys
; j
++) {
632 if (strequal(subkeys
[i
], builtin_svcs
[i
].servicename
)) {
641 ok
= svcctl_add_service(tmp_ctx
,
646 builtin_svcs
[i
].servicename
);
652 for (i
= 0; service_list
&& service_list
[i
]; i
++) {
656 for (j
= 0; j
< num_subkeys
; j
++) {
657 if (strequal(subkeys
[i
], service_list
[i
])) {
666 ok
= svcctl_add_service(tmp_ctx
,
672 if (is_valid_policy_hnd(&key_hnd
)) {
673 dcerpc_winreg_CloseKey(h
, tmp_ctx
, &key_hnd
, &result
);
675 ZERO_STRUCT(key_hnd
);
683 if (is_valid_policy_hnd(&key_hnd
)) {
684 dcerpc_winreg_CloseKey(h
, tmp_ctx
, &key_hnd
, &result
);
688 result
= regdb_transaction_commit();
689 if (!W_ERROR_IS_OK(result
)) {
690 DEBUG(10, ("regdb_transaction_commit failed: %s\n",
691 win_errstr(result
)));
694 result
= regdb_transaction_cancel();
695 if (!W_ERROR_IS_OK(result
)) {
696 DEBUG(10, ("regdb_transaction_cancel failed: %s\n",
697 win_errstr(result
)));
701 talloc_free(tmp_ctx
);
705 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */