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