s3-rpc_server: move services into individual directories.
[sharpe/samba-autobuild/.git] / source3 / rpc_server / svcctl / srv_svcctl_reg.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *
4  *  SVCCTL RPC server keys initialization
5  *
6  *  Copyright (c) 2005      Marcin Krzysztof Porwit
7  *  Copyright (c) 2005      Gerald (Jerry) Carter
8  *  Copyright (c) 2011      Andreas Schneider <asn@samba.org>
9  *
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.
14  *
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.
19  *
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/>.
22  */
23
24 #include "includes.h"
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"
31
32 #undef DBGC_CLASS
33 #define DBGC_CLASS DBGC_REGISTRY
34
35 #define TOP_LEVEL_SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services"
36
37 struct rcinit_file_information {
38         char *description;
39 };
40
41 struct service_display_info {
42         const char *servicename;
43         const char *daemon;
44         const char *dispname;
45         const char *description;
46 };
47
48 static struct service_display_info builtin_svcs[] = {
49         {
50                 "Spooler",
51                 "smbd",
52                 "Print Spooler",
53                 "Internal service for spooling files to print devices"
54         },
55         {
56                 "NETLOGON",
57                 "smbd",
58                 "Net Logon",
59                 "File service providing access to policy and profile data (not"
60                         "remotely manageable)"
61         },
62         {
63                 "RemoteRegistry",
64                 "smbd",
65                 "Remote Registry Service",
66                 "Internal service providing remote access to the Samba registry"
67         },
68         {
69                 "WINS",
70                 "nmbd",
71                 "Windows Internet Name Service (WINS)",
72                 "Internal service providing a NetBIOS point-to-point name server"
73                         "(not remotely manageable)"
74         },
75         { NULL, NULL, NULL, NULL }
76 };
77
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 }
115 };
116
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)
123 {
124         uint32_t i;
125
126         for (i = 0; common_unix_svcs[i].servicename; i++) {
127                 if (strequal(servicename, common_unix_svcs[i].servicename)) {
128                         char *dispname;
129                         dispname = talloc_asprintf(mem_ctx, "%s (%s)",
130                                         common_unix_svcs[i].dispname,
131                                         common_unix_svcs[i].servicename);
132                         if (dispname == NULL) {
133                                 return NULL;
134                         }
135                         return dispname;
136                 }
137         }
138
139         return talloc_strdup(mem_ctx, servicename);
140 }
141
142 /********************************************************************
143 ********************************************************************/
144 static char *svcctl_cleanup_string(TALLOC_CTX *mem_ctx,
145                                    const char *string)
146 {
147         char *clean = NULL;
148         char *begin, *end;
149
150         clean = talloc_strdup(mem_ctx, string);
151         if (clean == NULL) {
152                 return NULL;
153         }
154         begin = clean;
155
156         /* trim any beginning whilespace */
157         while (isspace(*begin)) {
158                 begin++;
159         }
160
161         if (*begin == '\0') {
162                 return NULL;
163         }
164
165         /* trim any trailing whitespace or carriage returns.
166            Start at the end and move backwards */
167
168         end = begin + strlen(begin) - 1;
169
170         while (isspace(*end) || *end=='\n' || *end=='\r') {
171                 *end = '\0';
172                 end--;
173         }
174
175         return begin;
176 }
177
178 /********************************************************************
179 ********************************************************************/
180 static bool read_init_file(TALLOC_CTX *mem_ctx,
181                            const char *servicename,
182                            struct rcinit_file_information **service_info)
183 {
184         struct rcinit_file_information *info = NULL;
185         char *filepath = NULL;
186         char str[1024];
187         XFILE *f = NULL;
188         char *p = NULL;
189
190         info = talloc_zero(mem_ctx, struct rcinit_file_information);
191         if (info == NULL) {
192                 return false;
193         }
194
195         /* attempt the file open */
196
197         filepath = talloc_asprintf(mem_ctx,
198                                    "%s/%s/%s",
199                                    get_dyn_MODULESDIR(),
200                                    SVCCTL_SCRIPT_DIR,
201                                    servicename);
202         if (filepath == NULL) {
203                 return false;
204         }
205         f = x_fopen( filepath, O_RDONLY, 0 );
206         if (f == NULL) {
207                 DEBUG(0,("read_init_file: failed to open [%s]\n", filepath));
208                 return false;
209         }
210
211         while ((x_fgets(str, sizeof(str) - 1, f)) != NULL) {
212                 /* ignore everything that is not a full line
213                    comment starting with a '#' */
214
215                 if (str[0] != '#') {
216                         continue;
217                 }
218
219                 /* Look for a line like '^#.*Description:' */
220
221                 p = strstr(str, "Description:");
222                 if (p != NULL) {
223                         char *desc;
224
225                         p += strlen( "Description:" ) + 1;
226                         if (p == NULL) {
227                                 break;
228                         }
229
230                         desc = svcctl_cleanup_string(mem_ctx, p);
231                         if (desc != NULL) {
232                                 info->description = talloc_strdup(info, desc);
233                         }
234                 }
235         }
236
237         x_fclose(f);
238
239         if (info->description == NULL) {
240                 info->description = talloc_strdup(info,
241                                                   "External Unix Service");
242                 if (info->description == NULL) {
243                         return false;
244                 }
245         }
246
247         *service_info = info;
248
249         return true;
250 }
251
252 static bool svcctl_add_service(TALLOC_CTX *mem_ctx,
253                                struct dcerpc_binding_handle *h,
254                                struct policy_handle *hive_hnd,
255                                const char *key,
256                                uint32_t access_mask,
257                                const char *name)
258 {
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;
265         char *dname = NULL;
266         char *ipath = NULL;
267         bool ok = false;
268         uint32_t i;
269         NTSTATUS status;
270         WERROR result = WERR_OK;
271
272         ZERO_STRUCT(key_hnd);
273
274         ZERO_STRUCT(wkey);
275         wkey.name = talloc_asprintf(mem_ctx, "%s\\%s", key, name);
276         if (wkey.name == NULL) {
277                 goto done;
278         }
279
280         ZERO_STRUCT(wkeyclass);
281         wkeyclass.name = "";
282
283         status = dcerpc_winreg_CreateKey(h,
284                                          mem_ctx,
285                                          hive_hnd,
286                                          wkey,
287                                          wkeyclass,
288                                          0,
289                                          access_mask,
290                                          NULL,
291                                          &key_hnd,
292                                          &action,
293                                          &result);
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)));
297                 goto done;
298         }
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)));
302                 goto done;
303         }
304
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,
308                                          h,
309                                          &key_hnd,
310                                          "Start",
311                                          SVCCTL_AUTO_START,
312                                          &result);
313         if (!NT_STATUS_IS_OK(status)) {
314                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
315                           nt_errstr(status)));
316                 goto done;
317         }
318         if (!W_ERROR_IS_OK(result)) {
319                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
320                           win_errstr(result)));
321                 goto done;
322         }
323
324         status = dcerpc_winreg_set_dword(mem_ctx,
325                                          h,
326                                          &key_hnd,
327                                          "Type",
328                                          SERVICE_TYPE_WIN32_OWN_PROCESS,
329                                          &result);
330         if (!NT_STATUS_IS_OK(status)) {
331                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
332                           nt_errstr(status)));
333                 goto done;
334         }
335         if (!W_ERROR_IS_OK(result)) {
336                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
337                           win_errstr(result)));
338                 goto done;
339         }
340
341         status = dcerpc_winreg_set_dword(mem_ctx,
342                                          h,
343                                          &key_hnd,
344                                          "ErrorControl",
345                                          SVCCTL_SVC_ERROR_NORMAL,
346                                          &result);
347         if (!NT_STATUS_IS_OK(status)) {
348                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
349                           nt_errstr(status)));
350                 goto done;
351         }
352         if (!W_ERROR_IS_OK(result)) {
353                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
354                           win_errstr(result)));
355                 goto done;
356         }
357
358         status = dcerpc_winreg_set_sz(mem_ctx,
359                                       h,
360                                       &key_hnd,
361                                       "ObjectName",
362                                       "LocalSystem",
363                                       &result);
364         if (!NT_STATUS_IS_OK(status)) {
365                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
366                           nt_errstr(status)));
367                 goto done;
368         }
369         if (!W_ERROR_IS_OK(result)) {
370                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
371                           win_errstr(result)));
372                 goto done;
373         }
374
375         /*
376          * Special considerations for internal services and the DisplayName
377          * value.
378          */
379         for (i = 0; builtin_svcs[i].servicename; i++) {
380                 if (strequal(name, builtin_svcs[i].servicename)) {
381                         ipath = talloc_asprintf(mem_ctx,
382                                                 "%s/%s/%s",
383                                                 get_dyn_MODULESDIR(),
384                                                 SVCCTL_SCRIPT_DIR,
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);
388                         break;
389                 }
390         }
391
392         if (ipath == NULL || dname == NULL || description == NULL) {
393                 goto done;
394         }
395
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;
400
401                 ipath = talloc_asprintf(mem_ctx,
402                                         "%s/%s/%s",
403                                         get_dyn_MODULESDIR(),
404                                         SVCCTL_SCRIPT_DIR,
405                                         name);
406
407                 /* lookup common unix display names */
408                 dispname = svcctl_get_common_service_dispname(mem_ctx, name);
409                 dname = talloc_strdup(mem_ctx, dispname ? dispname : "");
410
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);
415                 } else {
416                         description = talloc_strdup(mem_ctx,
417                                                     "External Unix Service");
418                 }
419         }
420
421         if (ipath == NULL || dname == NULL || description == NULL) {
422                 goto done;
423         }
424
425         status = dcerpc_winreg_set_sz(mem_ctx,
426                                       h,
427                                       &key_hnd,
428                                       "DisplayName",
429                                       dname,
430                                       &result);
431         if (!NT_STATUS_IS_OK(status)) {
432                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
433                           nt_errstr(status)));
434                 goto done;
435         }
436         if (!W_ERROR_IS_OK(result)) {
437                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
438                           win_errstr(result)));
439                 goto done;
440         }
441
442         status = dcerpc_winreg_set_sz(mem_ctx,
443                                       h,
444                                       &key_hnd,
445                                       "ImagePath",
446                                       ipath,
447                                       &result);
448         if (!NT_STATUS_IS_OK(status)) {
449                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
450                           nt_errstr(status)));
451                 goto done;
452         }
453         if (!W_ERROR_IS_OK(result)) {
454                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
455                           win_errstr(result)));
456                 goto done;
457         }
458
459         status = dcerpc_winreg_set_sz(mem_ctx,
460                                       h,
461                                       &key_hnd,
462                                       "Description",
463                                       description,
464                                       &result);
465         if (!NT_STATUS_IS_OK(status)) {
466                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
467                           nt_errstr(status)));
468                 goto done;
469         }
470         if (!W_ERROR_IS_OK(result)) {
471                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
472                           win_errstr(result)));
473                 goto done;
474         }
475
476         sd = svcctl_gen_service_sd(mem_ctx);
477         if (sd == NULL) {
478                 DEBUG(0, ("add_new_svc_name: Failed to create default "
479                           "sec_desc!\n"));
480                 goto done;
481         }
482
483         if (is_valid_policy_hnd(&key_hnd)) {
484                 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
485         }
486         ZERO_STRUCT(key_hnd);
487
488         ZERO_STRUCT(wkey);
489         wkey.name = talloc_asprintf(mem_ctx, "%s\\%s\\Security", key, name);
490         if (wkey.name == NULL) {
491                 result = WERR_NOMEM;
492                 goto done;
493         }
494
495         ZERO_STRUCT(wkeyclass);
496         wkeyclass.name = "";
497
498         status = dcerpc_winreg_CreateKey(h,
499                                          mem_ctx,
500                                          hive_hnd,
501                                          wkey,
502                                          wkeyclass,
503                                          0,
504                                          access_mask,
505                                          NULL,
506                                          &key_hnd,
507                                          &action,
508                                          &result);
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)));
512                 goto done;
513         }
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)));
517                 goto done;
518         }
519
520         status = dcerpc_winreg_set_sd(mem_ctx,
521                                       h,
522                                       &key_hnd,
523                                       "Security",
524                                       sd,
525                                       &result);
526         if (!NT_STATUS_IS_OK(status)) {
527                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
528                           nt_errstr(status)));
529                 goto done;
530         }
531         if (!W_ERROR_IS_OK(result)) {
532                 DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n",
533                           win_errstr(result)));
534                 goto done;
535         }
536
537         ok = true;
538 done:
539         if (is_valid_policy_hnd(&key_hnd)) {
540                 dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result);
541         }
542
543         return ok;
544 }
545
546 bool svcctl_init_winreg(struct messaging_context *msg_ctx)
547 {
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;
554         char *key = NULL;
555         uint32_t i;
556         NTSTATUS status;
557         WERROR result = WERR_OK;
558         bool ok = false;
559         TALLOC_CTX *tmp_ctx;
560
561         tmp_ctx = talloc_stackframe();
562         if (tmp_ctx == NULL) {
563                 return false;
564         }
565
566         DEBUG(3, ("Initialise the svcctl registry keys if needed.\n"));
567
568         ZERO_STRUCT(hive_hnd);
569         ZERO_STRUCT(key_hnd);
570
571         key = talloc_strdup(tmp_ctx, TOP_LEVEL_SERVICES_KEY);
572         if (key == NULL) {
573                 goto done;
574         }
575
576         status = dcerpc_winreg_int_hklm_openkey(tmp_ctx,
577                                                 get_server_info_system(),
578                                                 msg_ctx,
579                                                 &h,
580                                                 key,
581                                                 false,
582                                                 access_mask,
583                                                 &hive_hnd,
584                                                 &key_hnd,
585                                                 &result);
586         if (!NT_STATUS_IS_OK(status)) {
587                 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
588                           key, nt_errstr(status)));
589                 goto done;
590         }
591         if (!W_ERROR_IS_OK(result)) {
592                 DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n",
593                           key, win_errstr(result)));
594                 goto done;
595         }
596
597         /* get all subkeys */
598         status = dcerpc_winreg_enum_keys(tmp_ctx,
599                                          h,
600                                          &key_hnd,
601                                          &num_subkeys,
602                                          &subkeys,
603                                          &result);
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)));
607                 goto done;
608         }
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)));
612                 goto done;
613         }
614
615         for (i = 0; builtin_svcs[i].servicename != NULL; i++) {
616                 uint32_t j;
617                 bool skip = false;
618
619                 for (j = 0; j < num_subkeys; j++) {
620                         if (strequal(subkeys[i], builtin_svcs[i].servicename)) {
621                                 skip = true;
622                         }
623                 }
624
625                 if (skip) {
626                         continue;
627                 }
628
629                 ok = svcctl_add_service(tmp_ctx,
630                                         h,
631                                         &hive_hnd,
632                                         key,
633                                         access_mask,
634                                         builtin_svcs[i].servicename);
635                 if (!ok) {
636                         goto done;
637                 }
638         }
639
640         for (i = 0; service_list && service_list[i]; i++) {
641                 uint32_t j;
642                 bool skip = false;
643
644                 for (j = 0; j < num_subkeys; j++) {
645                         if (strequal(subkeys[i], service_list[i])) {
646                                 skip = true;
647                         }
648                 }
649
650                 if (skip) {
651                         continue;
652                 }
653
654                 ok = svcctl_add_service(tmp_ctx,
655                                         h,
656                                         &hive_hnd,
657                                         key,
658                                         access_mask,
659                                         service_list[i]);
660                 if (is_valid_policy_hnd(&key_hnd)) {
661                         dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
662                 }
663                 ZERO_STRUCT(key_hnd);
664
665                 if (!ok) {
666                         goto done;
667                 }
668         }
669
670 done:
671         if (is_valid_policy_hnd(&key_hnd)) {
672                 dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result);
673         }
674
675         return ok;
676 }
677
678 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */