Remove the char[1024] strings from dynconfig. Replace
[samba.git] / source3 / services / services_db.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Service Control API Implementation
4  * 
5  *  Copyright (C) Marcin Krzysztof Porwit         2005.
6  *  Largely Rewritten by:
7  *  Copyright (C) Gerald (Jerry) Carter           2005.
8  *  
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *  
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *  
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "includes.h"
24
25 struct rcinit_file_information {
26         char *description;
27 };
28
29 struct service_display_info {
30         const char *servicename;
31         const char *daemon;
32         const char *dispname;
33         const char *description;
34 };
35
36 struct service_display_info builtin_svcs[] = {
37   { "Spooler",        "smbd",   "Print Spooler", "Internal service for spooling files to print devices" },
38   { "NETLOGON",       "smbd",   "Net Logon", "File service providing access to policy and profile data (not remotely manageable)" },
39   { "RemoteRegistry", "smbd",   "Remote Registry Service", "Internal service providing remote access to "
40                                 "the Samba registry" },
41   { "WINS",           "nmbd",   "Windows Internet Name Service (WINS)", "Internal service providing a "
42                                 "NetBIOS point-to-point name server (not remotely manageable)" },
43   { NULL, NULL, NULL, NULL }
44 };
45
46 struct service_display_info common_unix_svcs[] = {
47   { "cups",          NULL, "Common Unix Printing System","Provides unified printing support for all operating systems" },
48   { "postfix",       NULL, "Internet Mail Service",     "Provides support for sending and receiving electonic mail" },
49   { "sendmail",      NULL, "Internet Mail Service",     "Provides support for sending and receiving electonic mail" },
50   { "portmap",       NULL, "TCP Port to RPC PortMapper",NULL },
51   { "xinetd",        NULL, "Internet Meta-Daemon",      NULL },
52   { "inet",          NULL, "Internet Meta-Daemon",      NULL },
53   { "xntpd",         NULL, "Network Time Service",      NULL },
54   { "ntpd",          NULL, "Network Time Service",      NULL },
55   { "lpd",           NULL, "BSD Print Spooler",         NULL },
56   { "nfsserver",     NULL, "Network File Service",      NULL },
57   { "cron",          NULL, "Scheduling Service",        NULL },
58   { "at",            NULL, "Scheduling Service",        NULL },
59   { "nscd",          NULL, "Name Service Cache Daemon", NULL },
60   { "slapd",         NULL, "LDAP Directory Service",    NULL },
61   { "ldap",          NULL, "LDAP DIrectory Service",    NULL },
62   { "ypbind",        NULL, "NIS Directory Service",     NULL },
63   { "courier-imap",  NULL, "IMAP4 Mail Service",        NULL },
64   { "courier-pop3",  NULL, "POP3 Mail Service",         NULL },
65   { "named",         NULL, "Domain Name Service",       NULL },
66   { "bind",          NULL, "Domain Name Service",       NULL },
67   { "httpd",         NULL, "HTTP Server",               NULL },
68   { "apache",        NULL, "HTTP Server",               "Provides s highly scalable and flexible web server "
69                                                         "capable of implementing various protocols incluing "
70                                                         "but not limited to HTTP" },
71   { "autofs",        NULL, "Automounter",               NULL },
72   { "squid",         NULL, "Web Cache Proxy ",          NULL },
73   { "perfcountd",    NULL, "Performance Monitoring Daemon", NULL },
74   { "pgsql",         NULL, "PgSQL Database Server",     "Provides service for SQL database from Postgresql.org" },
75   { "arpwatch",      NULL, "ARP Tables watcher",        "Provides service for monitoring ARP tables for changes" },
76   { "dhcpd",         NULL, "DHCP Server",               "Provides service for dynamic host configuration and IP assignment" },
77   { "nwserv",        NULL, "NetWare Server Emulator",   "Provides service for emulating Novell NetWare 3.12 server" },
78   { "proftpd",       NULL, "Professional FTP Server",   "Provides high configurable service for FTP connection and "
79                                                         "file transferring" },
80   { "ssh2",          NULL, "SSH Secure Shell",          "Provides service for secure connection for remote administration" },
81   { "sshd",          NULL, "SSH Secure Shell",          "Provides service for secure connection for remote administration" },
82   { NULL, NULL, NULL, NULL }
83 };
84
85
86 /********************************************************************
87 ********************************************************************/
88
89 static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx )
90 {
91         SEC_ACE ace[4];
92         SEC_ACCESS mask;
93         size_t i = 0;
94         SEC_DESC *sd;
95         SEC_ACL *acl;
96         size_t sd_size;
97
98         /* basic access for Everyone */
99
100         init_sec_access(&mask, SERVICE_READ_ACCESS );
101         init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
102
103         init_sec_access(&mask,SERVICE_EXECUTE_ACCESS );
104         init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
105
106         init_sec_access(&mask,SERVICE_ALL_ACCESS );
107         init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
108         init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
109
110         /* create the security descriptor */
111
112         if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
113                 return NULL;
114
115         if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
116                 return NULL;
117
118         return sd;
119 }
120
121 /********************************************************************
122  This is where we do the dirty work of filling in things like the
123  Display name, Description, etc...
124 ********************************************************************/
125
126 static char *get_common_service_dispname( const char *servicename )
127 {
128         static fstring dispname;
129         int i;
130
131         for ( i=0; common_unix_svcs[i].servicename; i++ ) {
132                 if (strequal(servicename, common_unix_svcs[i].servicename)) {
133                         fstr_sprintf( dispname, "%s (%s)",
134                                 common_unix_svcs[i].dispname,
135                                 common_unix_svcs[i].servicename );
136
137                         return dispname;
138                 }
139         }
140
141         fstrcpy( dispname, servicename );
142
143         return dispname;
144 }
145
146 /********************************************************************
147 ********************************************************************/
148
149 static char *cleanup_string( const char *string )
150 {
151         char *clean = NULL;
152         char *begin, *end;
153         TALLOC_CTX *ctx = talloc_tos();
154
155         clean = talloc_strdup(ctx, string);
156         if (!clean) {
157                 return NULL;
158         }
159         begin = clean;
160
161         /* trim any beginning whilespace */
162
163         while (isspace(*begin)) {
164                 begin++;
165         }
166
167         if (*begin == '\0') {
168                 return NULL;
169         }
170
171         /* trim any trailing whitespace or carriage returns.
172            Start at the end and move backwards */
173
174         end = begin + strlen(begin) - 1;
175
176         while ( isspace(*end) || *end=='\n' || *end=='\r' ) {
177                 *end = '\0';
178                 end--;
179         }
180
181         return begin;
182 }
183
184 /********************************************************************
185 ********************************************************************/
186
187 static bool read_init_file( const char *servicename, struct rcinit_file_information **service_info )
188 {
189         struct rcinit_file_information *info;
190         char *filepath = NULL;
191         char str[1024];
192         XFILE *f;
193         char *p;
194
195         if ( !(info = TALLOC_ZERO_P( NULL, struct rcinit_file_information ) ) )
196                 return False;
197
198         /* attempt the file open */
199
200         filepath = talloc_asprintf(info, "%s/%s/%s", get_dyn_LIBDIR(),
201                                 SVCCTL_SCRIPT_DIR, servicename);
202         if (!filepath) {
203                 TALLOC_FREE(info);
204                 return false;
205         }
206         if (!(f = x_fopen( filepath, O_RDONLY, 0 ))) {
207                 DEBUG(0,("read_init_file: failed to open [%s]\n", filepath));
208                 TALLOC_FREE(info);
209                 return false;
210         }
211
212         while ( (x_fgets( str, sizeof(str)-1, f )) != NULL ) {
213                 /* ignore everything that is not a full line
214                    comment starting with a '#' */
215
216                 if ( str[0] != '#' )
217                         continue;
218
219                 /* Look for a line like '^#.*Description:' */
220
221                 if ( (p = strstr( str, "Description:" )) != NULL ) {
222                         char *desc;
223
224                         p += strlen( "Description:" ) + 1;
225                         if ( !p )
226                                 break;
227
228                         if ( (desc = cleanup_string(p)) != NULL )
229                                 info->description = talloc_strdup( info, desc );
230                 }
231         }
232
233         x_fclose( f );
234
235         if ( !info->description )
236                 info->description = talloc_strdup( info, "External Unix Service" );
237
238         *service_info = info;
239         TALLOC_FREE(filepath);
240
241         return True;
242 }
243
244 /********************************************************************
245  This is where we do the dirty work of filling in things like the
246  Display name, Description, etc...
247 ********************************************************************/
248
249 static void fill_service_values( const char *name, REGVAL_CTR *values )
250 {
251         UNISTR2 data, dname, ipath, description;
252         uint32 dword;
253         int i;
254
255         /* These values are hardcoded in all QueryServiceConfig() replies.
256            I'm just storing them here for cosmetic purposes */
257
258         dword = SVCCTL_AUTO_START;
259         regval_ctr_addvalue( values, "Start", REG_DWORD, (char*)&dword, sizeof(uint32));
260
261         dword = SVCCTL_WIN32_OWN_PROC;
262         regval_ctr_addvalue( values, "Type", REG_DWORD, (char*)&dword, sizeof(uint32));
263
264         dword = SVCCTL_SVC_ERROR_NORMAL;
265         regval_ctr_addvalue( values, "ErrorControl", REG_DWORD, (char*)&dword, sizeof(uint32));
266
267         /* everything runs as LocalSystem */
268
269         init_unistr2( &data, "LocalSystem", UNI_STR_TERMINATE );
270         regval_ctr_addvalue( values, "ObjectName", REG_SZ, (char*)data.buffer, data.uni_str_len*2);
271
272         /* special considerations for internal services and the DisplayName value */
273
274         for ( i=0; builtin_svcs[i].servicename; i++ ) {
275                 if ( strequal( name, builtin_svcs[i].servicename ) ) {
276                         char *pstr = NULL;
277                         if (asprintf(&pstr, "%s/%s/%s",
278                                         get_dyn_LIBDIR(), SVCCTL_SCRIPT_DIR,
279                                         builtin_svcs[i].daemon) > 0) {
280                                 init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
281                                 SAFE_FREE(pstr);
282                         } else {
283                                 init_unistr2( &ipath, "", UNI_STR_TERMINATE );
284                         }
285                         init_unistr2( &description, builtin_svcs[i].description, UNI_STR_TERMINATE );
286                         init_unistr2( &dname, builtin_svcs[i].dispname, UNI_STR_TERMINATE );
287                         break;
288                 }
289         }
290
291         /* default to an external service if we haven't found a match */
292
293         if ( builtin_svcs[i].servicename == NULL ) {
294                 char *pstr = NULL;
295                 struct rcinit_file_information *init_info = NULL;
296
297                 if (asprintf(&pstr, "%s/%s/%s",get_dyn_LIBDIR(),
298                                         SVCCTL_SCRIPT_DIR, name) > 0) {
299                         init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
300                         SAFE_FREE(pstr);
301                 } else {
302                         init_unistr2( &ipath, "", UNI_STR_TERMINATE );
303                 }
304
305                 /* lookup common unix display names */
306                 init_unistr2( &dname, get_common_service_dispname( name ), UNI_STR_TERMINATE );
307
308                 /* get info from init file itself */
309                 if ( read_init_file( name, &init_info ) ) {
310                         init_unistr2( &description, init_info->description, UNI_STR_TERMINATE );
311                         TALLOC_FREE( init_info );
312                 }
313                 else {
314                         init_unistr2( &description, "External Unix Service", UNI_STR_TERMINATE );
315                 }
316         }
317
318         /* add the new values */
319
320         regval_ctr_addvalue( values, "DisplayName", REG_SZ, (char*)dname.buffer, dname.uni_str_len*2);
321         regval_ctr_addvalue( values, "ImagePath", REG_SZ, (char*)ipath.buffer, ipath.uni_str_len*2);
322         regval_ctr_addvalue( values, "Description", REG_SZ, (char*)description.buffer, description.uni_str_len*2);
323
324         return;
325 }
326
327 /********************************************************************
328 ********************************************************************/
329
330 static void add_new_svc_name( REGISTRY_KEY *key_parent, REGSUBKEY_CTR *subkeys,
331                               const char *name )
332 {
333         REGISTRY_KEY *key_service, *key_secdesc;
334         WERROR wresult;
335         char *path = NULL;
336         REGVAL_CTR *values;
337         REGSUBKEY_CTR *svc_subkeys;
338         SEC_DESC *sd;
339         DATA_BLOB sd_blob;
340         NTSTATUS status;
341
342         /* add to the list and create the subkey path */
343
344         regsubkey_ctr_addkey( subkeys, name );
345         store_reg_keys( key_parent, subkeys );
346
347         /* open the new service key */
348
349         if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
350                 return;
351         }
352         wresult = regkey_open_internal( NULL, &key_service, path,
353                                         get_root_nt_token(), REG_KEY_ALL );
354         if ( !W_ERROR_IS_OK(wresult) ) {
355                 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
356                         path, dos_errstr(wresult)));
357                 SAFE_FREE(path);
358                 return;
359         }
360         SAFE_FREE(path);
361
362         /* add the 'Security' key */
363
364         if ( !(svc_subkeys = TALLOC_ZERO_P( key_service, REGSUBKEY_CTR )) ) {
365                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
366                 TALLOC_FREE( key_service );
367                 return;
368         }
369
370         fetch_reg_keys( key_service, svc_subkeys );
371         regsubkey_ctr_addkey( svc_subkeys, "Security" );
372         store_reg_keys( key_service, svc_subkeys );
373
374         /* now for the service values */
375
376         if ( !(values = TALLOC_ZERO_P( key_service, REGVAL_CTR )) ) {
377                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
378                 TALLOC_FREE( key_service );
379                 return;
380         }
381
382         fill_service_values( name, values );
383         store_reg_values( key_service, values );
384
385         /* cleanup the service key*/
386
387         TALLOC_FREE( key_service );
388
389         /* now add the security descriptor */
390
391         if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
392                 return;
393         }
394         wresult = regkey_open_internal( NULL, &key_secdesc, path,
395                                         get_root_nt_token(), REG_KEY_ALL );
396         if ( !W_ERROR_IS_OK(wresult) ) {
397                 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
398                         path, dos_errstr(wresult)));
399                 TALLOC_FREE( key_secdesc );
400                 SAFE_FREE(path);
401                 return;
402         }
403         SAFE_FREE(path);
404
405         if ( !(values = TALLOC_ZERO_P( key_secdesc, REGVAL_CTR )) ) {
406                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
407                 TALLOC_FREE( key_secdesc );
408                 return;
409         }
410
411         if ( !(sd = construct_service_sd(key_secdesc)) ) {
412                 DEBUG(0,("add_new_svc_name: Failed to create default sec_desc!\n"));
413                 TALLOC_FREE( key_secdesc );
414                 return;
415         }
416
417         status = marshall_sec_desc(key_secdesc, sd, &sd_blob.data,
418                                    &sd_blob.length);
419         if (!NT_STATUS_IS_OK(status)) {
420                 DEBUG(0, ("marshall_sec_desc failed: %s\n",
421                           nt_errstr(status)));
422                 TALLOC_FREE(key_secdesc);
423                 return;
424         }
425
426         regval_ctr_addvalue(values, "Security", REG_BINARY,
427                             (const char *)sd_blob.data, sd_blob.length);
428         store_reg_values( key_secdesc, values );
429
430         TALLOC_FREE( key_secdesc );
431
432         return;
433 }
434
435 /********************************************************************
436 ********************************************************************/
437
438 void svcctl_init_keys( void )
439 {
440         const char **service_list = lp_svcctl_list();
441         int i;
442         REGSUBKEY_CTR *subkeys;
443         REGISTRY_KEY *key = NULL;
444         WERROR wresult;
445
446         /* bad mojo here if the lookup failed.  Should not happen */
447
448         wresult = regkey_open_internal( NULL, &key, KEY_SERVICES,
449                                         get_root_nt_token(), REG_KEY_ALL );
450
451         if ( !W_ERROR_IS_OK(wresult) ) {
452                 DEBUG(0,("svcctl_init_keys: key lookup failed! (%s)\n",
453                         dos_errstr(wresult)));
454                 return;
455         }
456
457         /* lookup the available subkeys */
458
459         if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) {
460                 DEBUG(0,("svcctl_init_keys: talloc() failed!\n"));
461                 TALLOC_FREE( key );
462                 return;
463         }
464
465         fetch_reg_keys( key, subkeys );
466
467         /* the builting services exist */
468
469         for ( i=0; builtin_svcs[i].servicename; i++ )
470                 add_new_svc_name( key, subkeys, builtin_svcs[i].servicename );
471
472         for ( i=0; service_list && service_list[i]; i++ ) {
473
474                 /* only add new services */
475                 if ( regsubkey_ctr_key_exists( subkeys, service_list[i] ) )
476                         continue;
477
478                 /* Add the new service key and initialize the appropriate values */
479
480                 add_new_svc_name( key, subkeys, service_list[i] );
481         }
482
483         TALLOC_FREE( key );
484
485         /* initialize the control hooks */
486
487         init_service_op_table();
488
489         return;
490 }
491
492 /********************************************************************
493  This is where we do the dirty work of filling in things like the
494  Display name, Description, etc...Always return a default secdesc
495  in case of any failure.
496 ********************************************************************/
497
498 SEC_DESC *svcctl_get_secdesc( TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
499 {
500         REGISTRY_KEY *key;
501         REGVAL_CTR *values;
502         REGISTRY_VALUE *val;
503         SEC_DESC *ret_sd = NULL;
504         char *path= NULL;
505         WERROR wresult;
506         NTSTATUS status;
507
508         /* now add the security descriptor */
509
510         if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
511                 return NULL;
512         }
513         wresult = regkey_open_internal( NULL, &key, path, token,
514                                         REG_KEY_ALL );
515         if ( !W_ERROR_IS_OK(wresult) ) {
516                 DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n",
517                         path, dos_errstr(wresult)));
518                 SAFE_FREE(path);
519                 return NULL;
520         }
521         SAFE_FREE(path);
522
523         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
524                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
525                 TALLOC_FREE( key );
526                 return NULL;
527         }
528
529         fetch_reg_values( key, values );
530
531         TALLOC_FREE(key);
532
533         if ( !(val = regval_ctr_getvalue( values, "Security" )) ) {
534                 DEBUG(6,("svcctl_get_secdesc: constructing default secdesc for service [%s]\n", 
535                         name));
536                 return construct_service_sd( ctx );
537         }
538
539         /* stream the service security descriptor */
540
541         status = unmarshall_sec_desc(ctx, regval_data_p(val),
542                                      regval_size(val), &ret_sd);
543
544         if (!NT_STATUS_IS_OK(status)) {
545                 return construct_service_sd( ctx );
546         }
547
548         return ret_sd;
549 }
550
551 /********************************************************************
552  Wrapper to make storing a Service sd easier
553 ********************************************************************/
554
555 bool svcctl_set_secdesc( TALLOC_CTX *ctx, const char *name, SEC_DESC *sec_desc, NT_USER_TOKEN *token )
556 {
557         REGISTRY_KEY *key;
558         WERROR wresult;
559         char *path = NULL;
560         REGVAL_CTR *values;
561         prs_struct ps;
562         bool ret = False;
563
564         /* now add the security descriptor */
565
566         if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
567                 return false;
568         }
569         wresult = regkey_open_internal( NULL, &key, path, token,
570                                         REG_KEY_ALL );
571         if ( !W_ERROR_IS_OK(wresult) ) {
572                 DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n",
573                         path, dos_errstr(wresult)));
574                 SAFE_FREE(path);
575                 return False;
576         }
577         SAFE_FREE(path);
578
579         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
580                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
581                 TALLOC_FREE( key );
582                 return False;
583         }
584
585         /* stream the printer security descriptor */
586         prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, key, MARSHALL);
587
588         if ( sec_io_desc("sec_desc", &sec_desc, &ps, 0 ) ) {
589                 uint32 offset = prs_offset( &ps );
590                 regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&ps), offset );
591                 ret = store_reg_values( key, values );
592         }
593
594         /* cleanup */
595
596         prs_mem_free( &ps );
597         TALLOC_FREE( key);
598
599         return ret;
600 }
601
602 /********************************************************************
603 ********************************************************************/
604
605 char *svcctl_lookup_dispname( const char *name, NT_USER_TOKEN *token )
606 {
607         static fstring display_name;
608         REGISTRY_KEY *key = NULL;
609         REGVAL_CTR *values;
610         REGISTRY_VALUE *val;
611         char *path = NULL;
612         WERROR wresult;
613
614         /* now add the security descriptor */
615
616         if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
617                 return NULL;
618         }
619         wresult = regkey_open_internal( NULL, &key, path, token,
620                                         REG_KEY_READ );
621         if ( !W_ERROR_IS_OK(wresult) ) {
622                 DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", 
623                         path, dos_errstr(wresult)));
624                 SAFE_FREE(path);
625                 goto fail;
626         }
627         SAFE_FREE(path);
628
629         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
630                 DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n"));
631                 TALLOC_FREE( key );
632                 goto fail;
633         }
634
635         fetch_reg_values( key, values );
636
637         if ( !(val = regval_ctr_getvalue( values, "DisplayName" )) )
638                 goto fail;
639
640         rpcstr_pull( display_name, regval_data_p(val), sizeof(display_name), regval_size(val), 0 );
641
642         TALLOC_FREE( key );
643
644         return display_name;
645
646 fail:
647         /* default to returning the service name */
648         TALLOC_FREE( key );
649         fstrcpy( display_name, name );
650         return display_name;
651 }
652
653 /********************************************************************
654 ********************************************************************/
655
656 char *svcctl_lookup_description( const char *name, NT_USER_TOKEN *token )
657 {
658         static fstring description;
659         REGISTRY_KEY *key = NULL;
660         REGVAL_CTR *values;
661         REGISTRY_VALUE *val;
662         char *path = NULL;
663         WERROR wresult;
664
665         /* now add the security descriptor */
666
667         if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
668                 return NULL;
669         }
670         wresult = regkey_open_internal( NULL, &key, path, token,
671                                         REG_KEY_READ );
672         if ( !W_ERROR_IS_OK(wresult) ) {
673                 DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", 
674                         path, dos_errstr(wresult)));
675                 SAFE_FREE(path);
676                 return NULL;
677         }
678         SAFE_FREE(path);
679
680         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
681                 DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n"));
682                 TALLOC_FREE( key );
683                 return NULL;
684         }
685
686         fetch_reg_values( key, values );
687
688         if ( !(val = regval_ctr_getvalue( values, "Description" )) )
689                 fstrcpy( description, "Unix Service");
690         else
691                 rpcstr_pull( description, regval_data_p(val), sizeof(description), regval_size(val), 0 );
692
693         TALLOC_FREE( key );
694
695         return description;
696 }
697
698
699 /********************************************************************
700 ********************************************************************/
701
702 REGVAL_CTR *svcctl_fetch_regvalues( const char *name, NT_USER_TOKEN *token )
703 {
704         REGISTRY_KEY *key = NULL;
705         REGVAL_CTR *values;
706         char *path = NULL;
707         WERROR wresult;
708
709         /* now add the security descriptor */
710
711         if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
712                 return NULL;
713         }
714         wresult = regkey_open_internal( NULL, &key, path, token,
715                                         REG_KEY_READ );
716         if ( !W_ERROR_IS_OK(wresult) ) {
717                 DEBUG(0,("svcctl_fetch_regvalues: key lookup failed! [%s] (%s)\n",
718                         path, dos_errstr(wresult)));
719                 SAFE_FREE(path);
720                 return NULL;
721         }
722         SAFE_FREE(path);
723
724         if ( !(values = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
725                 DEBUG(0,("svcctl_fetch_regvalues: talloc() failed!\n"));
726                 TALLOC_FREE( key );
727                 return NULL;
728         }
729         fetch_reg_values( key, values );
730
731         TALLOC_FREE( key );
732         return values;
733 }