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