BUG 9817: Fix 'map untrusted to domain' with NTLMv2.
[Samba.git] / source3 / rpc_server / svcctl / srv_svcctl_reg.c
blob07b7ce6d4bed742411c5563ba81cdb42e4b91503
1 /*
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/>.
24 #include "includes.h"
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"
32 #include "auth.h"
33 #include "registry/reg_backend_db.h"
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_REGISTRY
38 #define TOP_LEVEL_SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services"
40 struct rcinit_file_information {
41 char *description;
44 struct service_display_info {
45 const char *servicename;
46 const char *daemon;
47 const char *dispname;
48 const char *description;
51 static struct service_display_info builtin_svcs[] = {
53 "Spooler",
54 "smbd",
55 "Print Spooler",
56 "Internal service for spooling files to print devices"
59 "NETLOGON",
60 "smbd",
61 "Net Logon",
62 "File service providing access to policy and profile data (not"
63 "remotely manageable)"
66 "RemoteRegistry",
67 "smbd",
68 "Remote Registry Service",
69 "Internal service providing remote access to the Samba registry"
72 "WINS",
73 "nmbd",
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)
127 uint32_t i;
129 for (i = 0; common_unix_svcs[i].servicename; i++) {
130 if (strequal(servicename, common_unix_svcs[i].servicename)) {
131 char *dispname;
132 dispname = talloc_asprintf(mem_ctx, "%s (%s)",
133 common_unix_svcs[i].dispname,
134 common_unix_svcs[i].servicename);
135 if (dispname == NULL) {
136 return NULL;
138 return dispname;
142 return talloc_strdup(mem_ctx, servicename);
145 /********************************************************************
146 ********************************************************************/
147 static char *svcctl_cleanup_string(TALLOC_CTX *mem_ctx,
148 const char *string)
150 char *clean = NULL;
151 char *begin, *end;
153 clean = talloc_strdup(mem_ctx, string);
154 if (clean == NULL) {
155 return NULL;
157 begin = clean;
159 /* trim any beginning whilespace */
160 while (isspace(*begin)) {
161 begin++;
164 if (*begin == '\0') {
165 return NULL;
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') {
174 *end = '\0';
175 end--;
178 return begin;
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;
189 char str[1024];
190 XFILE *f = NULL;
191 char *p = NULL;
193 info = talloc_zero(mem_ctx, struct rcinit_file_information);
194 if (info == NULL) {
195 return false;
198 /* attempt the file open */
200 filepath = talloc_asprintf(mem_ctx,
201 "%s/%s/%s",
202 get_dyn_MODULESDIR(),
203 SVCCTL_SCRIPT_DIR,
204 servicename);
205 if (filepath == NULL) {
206 return false;
208 f = x_fopen( filepath, O_RDONLY, 0 );
209 if (f == NULL) {
210 DEBUG(0,("read_init_file: failed to open [%s]\n", filepath));
211 return false;
214 while ((x_fgets(str, sizeof(str) - 1, f)) != NULL) {
215 /* ignore everything that is not a full line
216 comment starting with a '#' */
218 if (str[0] != '#') {
219 continue;
222 /* Look for a line like '^#.*Description:' */
224 p = strstr(str, "Description:");
225 if (p != NULL) {
226 char *desc;
227 size_t len = strlen(p);
229 if (len <= 12) {
230 break;
233 desc = svcctl_cleanup_string(mem_ctx, p + 12);
234 if (desc != NULL) {
235 info->description = talloc_strdup(info, desc);
240 x_fclose(f);
242 if (info->description == NULL) {
243 info->description = talloc_strdup(info,
244 "External Unix Service");
245 if (info->description == NULL) {
246 return false;
250 *service_info = info;
252 return true;
255 static bool svcctl_add_service(TALLOC_CTX *mem_ctx,
256 struct dcerpc_binding_handle *h,
257 struct policy_handle *hive_hnd,
258 const char *key,
259 uint32_t access_mask,
260 const char *name)
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;
268 char *dname = NULL;
269 char *ipath = NULL;
270 bool ok = false;
271 uint32_t i;
272 NTSTATUS status;
273 WERROR result = WERR_OK;
275 ZERO_STRUCT(key_hnd);
277 ZERO_STRUCT(wkey);
278 wkey.name = talloc_asprintf(mem_ctx, "%s\\%s", key, name);
279 if (wkey.name == NULL) {
280 goto done;
283 ZERO_STRUCT(wkeyclass);
284 wkeyclass.name = "";
286 status = dcerpc_winreg_CreateKey(h,
287 mem_ctx,
288 hive_hnd,
289 wkey,
290 wkeyclass,
292 access_mask,
293 NULL,
294 &key_hnd,
295 &action,
296 &result);
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)));
300 goto done;
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)));
305 goto done;
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,
312 &key_hnd,
313 "Start",
314 SVCCTL_AUTO_START,
315 &result);
316 if (!NT_STATUS_IS_OK(status)) {
317 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
318 nt_errstr(status)));
319 goto done;
321 if (!W_ERROR_IS_OK(result)) {
322 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
323 win_errstr(result)));
324 goto done;
327 status = dcerpc_winreg_set_dword(mem_ctx,
329 &key_hnd,
330 "Type",
331 SERVICE_TYPE_WIN32_OWN_PROCESS,
332 &result);
333 if (!NT_STATUS_IS_OK(status)) {
334 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
335 nt_errstr(status)));
336 goto done;
338 if (!W_ERROR_IS_OK(result)) {
339 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
340 win_errstr(result)));
341 goto done;
344 status = dcerpc_winreg_set_dword(mem_ctx,
346 &key_hnd,
347 "ErrorControl",
348 SVCCTL_SVC_ERROR_NORMAL,
349 &result);
350 if (!NT_STATUS_IS_OK(status)) {
351 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
352 nt_errstr(status)));
353 goto done;
355 if (!W_ERROR_IS_OK(result)) {
356 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
357 win_errstr(result)));
358 goto done;
361 status = dcerpc_winreg_set_sz(mem_ctx,
363 &key_hnd,
364 "ObjectName",
365 "LocalSystem",
366 &result);
367 if (!NT_STATUS_IS_OK(status)) {
368 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
369 nt_errstr(status)));
370 goto done;
372 if (!W_ERROR_IS_OK(result)) {
373 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
374 win_errstr(result)));
375 goto done;
379 * Special considerations for internal services and the DisplayName
380 * value.
382 for (i = 0; builtin_svcs[i].servicename; i++) {
383 if (strequal(name, builtin_svcs[i].servicename)) {
384 ipath = talloc_asprintf(mem_ctx,
385 "%s/%s/%s",
386 get_dyn_MODULESDIR(),
387 SVCCTL_SCRIPT_DIR,
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);
391 break;
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,
401 "%s/%s/%s",
402 get_dyn_MODULESDIR(),
403 SVCCTL_SCRIPT_DIR,
404 name);
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);
414 } else {
415 description = talloc_strdup(mem_ctx,
416 "External Unix Service");
420 if (ipath == NULL || dname == NULL || description == NULL) {
421 goto done;
424 status = dcerpc_winreg_set_sz(mem_ctx,
426 &key_hnd,
427 "DisplayName",
428 dname,
429 &result);
430 if (!NT_STATUS_IS_OK(status)) {
431 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
432 nt_errstr(status)));
433 goto done;
435 if (!W_ERROR_IS_OK(result)) {
436 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
437 win_errstr(result)));
438 goto done;
441 status = dcerpc_winreg_set_sz(mem_ctx,
443 &key_hnd,
444 "ImagePath",
445 ipath,
446 &result);
447 if (!NT_STATUS_IS_OK(status)) {
448 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
449 nt_errstr(status)));
450 goto done;
452 if (!W_ERROR_IS_OK(result)) {
453 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
454 win_errstr(result)));
455 goto done;
458 status = dcerpc_winreg_set_sz(mem_ctx,
460 &key_hnd,
461 "Description",
462 description,
463 &result);
464 if (!NT_STATUS_IS_OK(status)) {
465 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
466 nt_errstr(status)));
467 goto done;
469 if (!W_ERROR_IS_OK(result)) {
470 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
471 win_errstr(result)));
472 goto done;
475 sd = svcctl_gen_service_sd(mem_ctx);
476 if (sd == NULL) {
477 DEBUG(0, ("add_new_svc_name: Failed to create default "
478 "sec_desc!\n"));
479 goto done;
482 if (is_valid_policy_hnd(&key_hnd)) {
483 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
485 ZERO_STRUCT(key_hnd);
487 ZERO_STRUCT(wkey);
488 wkey.name = talloc_asprintf(mem_ctx, "%s\\%s\\Security", key, name);
489 if (wkey.name == NULL) {
490 result = WERR_NOMEM;
491 goto done;
494 ZERO_STRUCT(wkeyclass);
495 wkeyclass.name = "";
497 status = dcerpc_winreg_CreateKey(h,
498 mem_ctx,
499 hive_hnd,
500 wkey,
501 wkeyclass,
503 access_mask,
504 NULL,
505 &key_hnd,
506 &action,
507 &result);
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)));
511 goto done;
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)));
516 goto done;
519 status = dcerpc_winreg_set_sd(mem_ctx,
521 &key_hnd,
522 "Security",
524 &result);
525 if (!NT_STATUS_IS_OK(status)) {
526 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
527 nt_errstr(status)));
528 goto done;
530 if (!W_ERROR_IS_OK(result)) {
531 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
532 win_errstr(result)));
533 goto done;
536 ok = true;
537 done:
538 if (is_valid_policy_hnd(&key_hnd)) {
539 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
542 return ok;
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;
553 char *key = NULL;
554 uint32_t i;
555 NTSTATUS status;
556 WERROR result = WERR_OK;
557 bool ok = false;
558 TALLOC_CTX *tmp_ctx;
560 tmp_ctx = talloc_stackframe();
561 if (tmp_ctx == NULL) {
562 return false;
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);
571 if (key == NULL) {
572 goto done;
575 result = regdb_open();
576 if (!W_ERROR_IS_OK(result)) {
577 DEBUG(10, ("regdb_open failed: %s\n",
578 win_errstr(result)));
579 goto done;
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)));
585 goto done;
588 status = dcerpc_winreg_int_hklm_openkey(tmp_ctx,
589 get_session_info_system(),
590 msg_ctx,
592 key,
593 false,
594 access_mask,
595 &hive_hnd,
596 &key_hnd,
597 &result);
598 if (!NT_STATUS_IS_OK(status)) {
599 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
600 key, nt_errstr(status)));
601 goto done;
603 if (!W_ERROR_IS_OK(result)) {
604 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
605 key, win_errstr(result)));
606 goto done;
609 /* get all subkeys */
610 status = dcerpc_winreg_enum_keys(tmp_ctx,
612 &key_hnd,
613 &num_subkeys,
614 &subkeys,
615 &result);
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)));
619 goto done;
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)));
624 goto done;
627 for (i = 0; builtin_svcs[i].servicename != NULL; i++) {
628 uint32_t j;
629 bool skip = false;
631 for (j = 0; j < num_subkeys; j++) {
632 if (strequal(subkeys[i], builtin_svcs[i].servicename)) {
633 skip = true;
637 if (skip) {
638 continue;
641 ok = svcctl_add_service(tmp_ctx,
643 &hive_hnd,
644 key,
645 access_mask,
646 builtin_svcs[i].servicename);
647 if (!ok) {
648 goto done;
652 for (i = 0; service_list && service_list[i]; i++) {
653 uint32_t j;
654 bool skip = false;
656 for (j = 0; j < num_subkeys; j++) {
657 if (strequal(subkeys[i], service_list[i])) {
658 skip = true;
662 if (skip) {
663 continue;
666 ok = svcctl_add_service(tmp_ctx,
668 &hive_hnd,
669 key,
670 access_mask,
671 service_list[i]);
672 if (is_valid_policy_hnd(&key_hnd)) {
673 dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
675 ZERO_STRUCT(key_hnd);
677 if (!ok) {
678 goto done;
682 done:
683 if (is_valid_policy_hnd(&key_hnd)) {
684 dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
687 if (ok) {
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)));
693 } else {
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)));
700 regdb_close();
701 talloc_free(tmp_ctx);
702 return ok;
705 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */