More static fstring elimination.
[samba.git] / source / 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         int i;
129
130         for ( i=0; common_unix_svcs[i].servicename; i++ ) {
131                 if (strequal(servicename, common_unix_svcs[i].servicename)) {
132                         char *dispname;
133                         if (asprintf(&dispname,
134                                 "%s (%s)",
135                                 common_unix_svcs[i].dispname,
136                                 common_unix_svcs[i].servicename) < 0) {
137                                 return NULL;
138                         }
139                         return dispname;
140                 }
141         }
142
143         return SMB_STRDUP(servicename );
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                 char *dispname = NULL;
296                 struct rcinit_file_information *init_info = NULL;
297
298                 if (asprintf(&pstr, "%s/%s/%s",get_dyn_LIBDIR(),
299                                         SVCCTL_SCRIPT_DIR, name) > 0) {
300                         init_unistr2( &ipath, pstr, UNI_STR_TERMINATE );
301                         SAFE_FREE(pstr);
302                 } else {
303                         init_unistr2( &ipath, "", UNI_STR_TERMINATE );
304                 }
305
306                 /* lookup common unix display names */
307                 dispname = get_common_service_dispname(name);
308                 init_unistr2( &dname, dispname ? dispname : "", UNI_STR_TERMINATE );
309                 SAFE_FREE(dispname);
310
311                 /* get info from init file itself */
312                 if ( read_init_file( name, &init_info ) ) {
313                         init_unistr2( &description, init_info->description, UNI_STR_TERMINATE );
314                         TALLOC_FREE( init_info );
315                 }
316                 else {
317                         init_unistr2( &description, "External Unix Service", UNI_STR_TERMINATE );
318                 }
319         }
320
321         /* add the new values */
322
323         regval_ctr_addvalue( values, "DisplayName", REG_SZ, (char*)dname.buffer, dname.uni_str_len*2);
324         regval_ctr_addvalue( values, "ImagePath", REG_SZ, (char*)ipath.buffer, ipath.uni_str_len*2);
325         regval_ctr_addvalue( values, "Description", REG_SZ, (char*)description.buffer, description.uni_str_len*2);
326
327         return;
328 }
329
330 /********************************************************************
331 ********************************************************************/
332
333 static void add_new_svc_name( REGISTRY_KEY *key_parent, REGSUBKEY_CTR *subkeys,
334                               const char *name )
335 {
336         REGISTRY_KEY *key_service, *key_secdesc;
337         WERROR wresult;
338         char *path = NULL;
339         REGVAL_CTR *values;
340         REGSUBKEY_CTR *svc_subkeys;
341         SEC_DESC *sd;
342         DATA_BLOB sd_blob;
343         NTSTATUS status;
344
345         /* add to the list and create the subkey path */
346
347         regsubkey_ctr_addkey( subkeys, name );
348         store_reg_keys( key_parent, subkeys );
349
350         /* open the new service key */
351
352         if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
353                 return;
354         }
355         wresult = regkey_open_internal( NULL, &key_service, path,
356                                         get_root_nt_token(), REG_KEY_ALL );
357         if ( !W_ERROR_IS_OK(wresult) ) {
358                 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
359                         path, dos_errstr(wresult)));
360                 SAFE_FREE(path);
361                 return;
362         }
363         SAFE_FREE(path);
364
365         /* add the 'Security' key */
366
367         if ( !(svc_subkeys = TALLOC_ZERO_P( key_service, REGSUBKEY_CTR )) ) {
368                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
369                 TALLOC_FREE( key_service );
370                 return;
371         }
372
373         fetch_reg_keys( key_service, svc_subkeys );
374         regsubkey_ctr_addkey( svc_subkeys, "Security" );
375         store_reg_keys( key_service, svc_subkeys );
376
377         /* now for the service values */
378
379         if ( !(values = TALLOC_ZERO_P( key_service, REGVAL_CTR )) ) {
380                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
381                 TALLOC_FREE( key_service );
382                 return;
383         }
384
385         fill_service_values( name, values );
386         store_reg_values( key_service, values );
387
388         /* cleanup the service key*/
389
390         TALLOC_FREE( key_service );
391
392         /* now add the security descriptor */
393
394         if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
395                 return;
396         }
397         wresult = regkey_open_internal( NULL, &key_secdesc, path,
398                                         get_root_nt_token(), REG_KEY_ALL );
399         if ( !W_ERROR_IS_OK(wresult) ) {
400                 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n",
401                         path, dos_errstr(wresult)));
402                 TALLOC_FREE( key_secdesc );
403                 SAFE_FREE(path);
404                 return;
405         }
406         SAFE_FREE(path);
407
408         if ( !(values = TALLOC_ZERO_P( key_secdesc, REGVAL_CTR )) ) {
409                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
410                 TALLOC_FREE( key_secdesc );
411                 return;
412         }
413
414         if ( !(sd = construct_service_sd(key_secdesc)) ) {
415                 DEBUG(0,("add_new_svc_name: Failed to create default sec_desc!\n"));
416                 TALLOC_FREE( key_secdesc );
417                 return;
418         }
419
420         status = marshall_sec_desc(key_secdesc, sd, &sd_blob.data,
421                                    &sd_blob.length);
422         if (!NT_STATUS_IS_OK(status)) {
423                 DEBUG(0, ("marshall_sec_desc failed: %s\n",
424                           nt_errstr(status)));
425                 TALLOC_FREE(key_secdesc);
426                 return;
427         }
428
429         regval_ctr_addvalue(values, "Security", REG_BINARY,
430                             (const char *)sd_blob.data, sd_blob.length);
431         store_reg_values( key_secdesc, values );
432
433         TALLOC_FREE( key_secdesc );
434
435         return;
436 }
437
438 /********************************************************************
439 ********************************************************************/
440
441 void svcctl_init_keys( void )
442 {
443         const char **service_list = lp_svcctl_list();
444         int i;
445         REGSUBKEY_CTR *subkeys;
446         REGISTRY_KEY *key = NULL;
447         WERROR wresult;
448
449         /* bad mojo here if the lookup failed.  Should not happen */
450
451         wresult = regkey_open_internal( NULL, &key, KEY_SERVICES,
452                                         get_root_nt_token(), REG_KEY_ALL );
453
454         if ( !W_ERROR_IS_OK(wresult) ) {
455                 DEBUG(0,("svcctl_init_keys: key lookup failed! (%s)\n",
456                         dos_errstr(wresult)));
457                 return;
458         }
459
460         /* lookup the available subkeys */
461
462         if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) {
463                 DEBUG(0,("svcctl_init_keys: talloc() failed!\n"));
464                 TALLOC_FREE( key );
465                 return;
466         }
467
468         fetch_reg_keys( key, subkeys );
469
470         /* the builting services exist */
471
472         for ( i=0; builtin_svcs[i].servicename; i++ )
473                 add_new_svc_name( key, subkeys, builtin_svcs[i].servicename );
474
475         for ( i=0; service_list && service_list[i]; i++ ) {
476
477                 /* only add new services */
478                 if ( regsubkey_ctr_key_exists( subkeys, service_list[i] ) )
479                         continue;
480
481                 /* Add the new service key and initialize the appropriate values */
482
483                 add_new_svc_name( key, subkeys, service_list[i] );
484         }
485
486         TALLOC_FREE( key );
487
488         /* initialize the control hooks */
489
490         init_service_op_table();
491
492         return;
493 }
494
495 /********************************************************************
496  This is where we do the dirty work of filling in things like the
497  Display name, Description, etc...Always return a default secdesc
498  in case of any failure.
499 ********************************************************************/
500
501 SEC_DESC *svcctl_get_secdesc( TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
502 {
503         REGISTRY_KEY *key;
504         REGVAL_CTR *values;
505         REGISTRY_VALUE *val;
506         SEC_DESC *ret_sd = NULL;
507         char *path= NULL;
508         WERROR wresult;
509         NTSTATUS status;
510
511         /* now add the security descriptor */
512
513         if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
514                 return NULL;
515         }
516         wresult = regkey_open_internal( NULL, &key, path, token,
517                                         REG_KEY_ALL );
518         if ( !W_ERROR_IS_OK(wresult) ) {
519                 DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n",
520                         path, dos_errstr(wresult)));
521                 SAFE_FREE(path);
522                 return NULL;
523         }
524         SAFE_FREE(path);
525
526         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
527                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
528                 TALLOC_FREE( key );
529                 return NULL;
530         }
531
532         fetch_reg_values( key, values );
533
534         TALLOC_FREE(key);
535
536         if ( !(val = regval_ctr_getvalue( values, "Security" )) ) {
537                 DEBUG(6,("svcctl_get_secdesc: constructing default secdesc for service [%s]\n", 
538                         name));
539                 return construct_service_sd( ctx );
540         }
541
542         /* stream the service security descriptor */
543
544         status = unmarshall_sec_desc(ctx, regval_data_p(val),
545                                      regval_size(val), &ret_sd);
546
547         if (!NT_STATUS_IS_OK(status)) {
548                 return construct_service_sd( ctx );
549         }
550
551         return ret_sd;
552 }
553
554 /********************************************************************
555  Wrapper to make storing a Service sd easier
556 ********************************************************************/
557
558 bool svcctl_set_secdesc( TALLOC_CTX *ctx, const char *name, SEC_DESC *sec_desc, NT_USER_TOKEN *token )
559 {
560         REGISTRY_KEY *key;
561         WERROR wresult;
562         char *path = NULL;
563         REGVAL_CTR *values;
564         prs_struct ps;
565         bool ret = False;
566
567         /* now add the security descriptor */
568
569         if (asprintf(&path, "%s\\%s\\%s", KEY_SERVICES, name, "Security") < 0) {
570                 return false;
571         }
572         wresult = regkey_open_internal( NULL, &key, path, token,
573                                         REG_KEY_ALL );
574         if ( !W_ERROR_IS_OK(wresult) ) {
575                 DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n",
576                         path, dos_errstr(wresult)));
577                 SAFE_FREE(path);
578                 return False;
579         }
580         SAFE_FREE(path);
581
582         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
583                 DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
584                 TALLOC_FREE( key );
585                 return False;
586         }
587
588         /* stream the printer security descriptor */
589         prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, key, MARSHALL);
590
591         if ( sec_io_desc("sec_desc", &sec_desc, &ps, 0 ) ) {
592                 uint32 offset = prs_offset( &ps );
593                 regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&ps), offset );
594                 ret = store_reg_values( key, values );
595         }
596
597         /* cleanup */
598
599         prs_mem_free( &ps );
600         TALLOC_FREE( key);
601
602         return ret;
603 }
604
605 /********************************************************************
606 ********************************************************************/
607
608 const char *svcctl_lookup_dispname(TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
609 {
610         char *display_name = NULL;
611         REGISTRY_KEY *key = NULL;
612         REGVAL_CTR *values;
613         REGISTRY_VALUE *val;
614         char *path = NULL;
615         WERROR wresult;
616
617         /* now add the security descriptor */
618
619         if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
620                 return NULL;
621         }
622         wresult = regkey_open_internal( NULL, &key, path, token,
623                                         REG_KEY_READ );
624         if ( !W_ERROR_IS_OK(wresult) ) {
625                 DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", 
626                         path, dos_errstr(wresult)));
627                 SAFE_FREE(path);
628                 goto fail;
629         }
630         SAFE_FREE(path);
631
632         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
633                 DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n"));
634                 TALLOC_FREE( key );
635                 goto fail;
636         }
637
638         fetch_reg_values( key, values );
639
640         if ( !(val = regval_ctr_getvalue( values, "DisplayName" )) )
641                 goto fail;
642
643         rpcstr_pull_talloc(ctx, &display_name, regval_data_p(val), regval_size(val), 0 );
644
645         TALLOC_FREE( key );
646
647         return display_name;
648
649 fail:
650         /* default to returning the service name */
651         TALLOC_FREE( key );
652         return talloc_strdup(ctx, name);
653 }
654
655 /********************************************************************
656 ********************************************************************/
657
658 const char *svcctl_lookup_description(TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token )
659 {
660         char *description = NULL;
661         REGISTRY_KEY *key = NULL;
662         REGVAL_CTR *values;
663         REGISTRY_VALUE *val;
664         char *path = NULL;
665         WERROR wresult;
666
667         /* now add the security descriptor */
668
669         if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
670                 return NULL;
671         }
672         wresult = regkey_open_internal( NULL, &key, path, token,
673                                         REG_KEY_READ );
674         if ( !W_ERROR_IS_OK(wresult) ) {
675                 DEBUG(0,("svcctl_lookup_description: key lookup failed! [%s] (%s)\n", 
676                         path, dos_errstr(wresult)));
677                 SAFE_FREE(path);
678                 return NULL;
679         }
680         SAFE_FREE(path);
681
682         if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
683                 DEBUG(0,("svcctl_lookup_description: talloc() failed!\n"));
684                 TALLOC_FREE( key );
685                 return NULL;
686         }
687
688         fetch_reg_values( key, values );
689
690         if ( !(val = regval_ctr_getvalue( values, "Description" )) ) {
691                 TALLOC_FREE( key );
692                 return "Unix Service";
693         }
694         rpcstr_pull_talloc(ctx, &description, regval_data_p(val), regval_size(val), 0 );
695         TALLOC_FREE(key);
696
697         return description;
698 }
699
700
701 /********************************************************************
702 ********************************************************************/
703
704 REGVAL_CTR *svcctl_fetch_regvalues( const char *name, NT_USER_TOKEN *token )
705 {
706         REGISTRY_KEY *key = NULL;
707         REGVAL_CTR *values;
708         char *path = NULL;
709         WERROR wresult;
710
711         /* now add the security descriptor */
712
713         if (asprintf(&path, "%s\\%s", KEY_SERVICES, name) < 0) {
714                 return NULL;
715         }
716         wresult = regkey_open_internal( NULL, &key, path, token,
717                                         REG_KEY_READ );
718         if ( !W_ERROR_IS_OK(wresult) ) {
719                 DEBUG(0,("svcctl_fetch_regvalues: key lookup failed! [%s] (%s)\n",
720                         path, dos_errstr(wresult)));
721                 SAFE_FREE(path);
722                 return NULL;
723         }
724         SAFE_FREE(path);
725
726         if ( !(values = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
727                 DEBUG(0,("svcctl_fetch_regvalues: talloc() failed!\n"));
728                 TALLOC_FREE( key );
729                 return NULL;
730         }
731         fetch_reg_values( key, values );
732
733         TALLOC_FREE( key );
734         return values;
735 }