2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Gerald (Jerry) Carter 2005,
5 * Copyright (C) Marcin Krzysztof Porwit 2005.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* TODO - Do the OpenService service name matching case-independently, or at least make it an option. */
28 #define DBGC_CLASS DBGC_RPC_SRV
30 #define SERVICEDB_VERSION_V1 1 /* Will there be more? */
31 #define INTERNAL_SERVICES_LIST "NETLOGON Spooler"
34 /* scripts will execute from the following libdir, if they are in the enable svcctl=<list of scripts> */
35 /* these should likely be symbolic links. Note that information about them will be extracted from the files themselves */
36 /* using the LSB standard keynames for various information */
38 #define SVCCTL_SCRIPT_DIR "/svcctl/"
41 * sertup the \PIPE\svcctl db API
44 #define SCVCTL_DATABASE_VERSION_V1 1
45 TALLOC_CTX *svcdb=NULL;
46 static TDB_CONTEXT *service_tdb; /* used for services tdb file */
48 /* there are two types of services -- internal, and external.
49 Internal services are "built-in" to samba -- there may be
50 functions that exist to provide the control and enumeration
51 functions. There certainly is information returned to be
52 displayed in the typical management console.
54 External services are those that can be specified in the smb.conf
55 file -- and they conform to the LSB specification as to having
56 particular keywords in the scripts. Note that these "scripts" are
57 located in the lib directory, and are likely links to LSB-compliant
58 init.d scripts, such as those that might come with Suse. Note
59 that the spec is located http://www.linuxbase.org/spec/ */
63 /* Expand this to include what can and can't be done
64 with a particular internal service. Expand as necessary
65 to add other infromation like what can be controlled,
68 typedef struct Internal_service_struct
70 const char *filename; /* internal name "index" */
71 const char *displayname;
72 const char *description;
73 const uint32 statustype;
76 } Internal_service_description;
79 static const Internal_service_description ISD[] = {
80 { "NETLOGON", "Net Logon", "Provides logon and authentication service to the network", 0x110, NULL, NULL},
81 { "Spooler", "Spooler", "Printing Services", 0x0020, NULL, NULL},
82 { NULL, NULL, NULL, 0, NULL, NULL}
86 /********************************************************************
88 (a) get and set security descriptors on services
89 (b) read and write QUERY_SERVICE_CONFIG structures (both kinds, country and western)
90 (c) create default secdesc objects for services and SCM
91 (d) check access control masks with se_access_check()
92 ********************************************************************/
94 /*********************************************************************
95 given a service nice name, find the underlying service name
96 *********************************************************************/
98 BOOL _svcctl_service_nicename_to_servicename(TDB_CONTEXT *stdb,pstring service_nicename, pstring servicename,int szsvcname)
103 if ((stdb == NULL) || (service_nicename==NULL) || (servicename == NULL))
106 pstr_sprintf(keystring,"SERVICE_NICENAME/%s", servicename);
108 DEBUG(5, ("_svcctl_service_nicename_to_servicename: Looking for service name [%s], key [%s]\n",
109 service_nicename, keystring));
111 key_data = tdb_fetch_bystring(stdb,keystring);
113 if (key_data.dsize == 0) {
114 DEBUG(5, ("_svcctl_service_nicename_to_servicename: [%s] Not found, tried key [%s]\n",service_nicename,keystring));
118 strncpy(servicename,key_data.dptr,szsvcname);
119 servicename[(key_data.dsize > szsvcname ? szsvcname : key_data.dsize)] = 0;
120 DEBUG(5, ("_svcctl_service_nicename_to_servicename: Found service name [%s], name is [%s]\n",
121 service_nicename,servicename));
126 /*********************************************************************
127 *********************************************************************/
129 static BOOL write_si_to_service_tdb(TDB_CONTEXT *stdb,char *service_name, Service_info *si)
133 /* Note -- when we write to the tdb, we "index" on the filename
134 field, not the nice name. when a service is "opened", it is
135 opened by the nice (SERVICENAME) name, not the file name.
136 So there needs to be a mapping from nice name back to the file name. */
138 if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0))
142 /* Store the nicename */
144 pstr_sprintf(keystring,"SERVICE_NICENAME/%s", si->servicename);
145 tdb_store_bystring(stdb,keystring,string_tdb_data(service_name),TDB_REPLACE);
147 pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name);
148 tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicetype),TDB_REPLACE);
150 pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name);
151 tdb_store_bystring(stdb,keystring,string_tdb_data(si->filename),TDB_REPLACE);
153 pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name);
154 tdb_store_bystring(stdb,keystring,string_tdb_data(si->provides),TDB_REPLACE);
156 pstr_sprintf(keystring,"SERVICE/%s/SERVICENAME", service_name);
157 tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicename),TDB_REPLACE);
159 pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name);
160 tdb_store_bystring(stdb,keystring,string_tdb_data(si->dependencies),TDB_REPLACE);
162 pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name);
163 tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstart),TDB_REPLACE);
165 pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTOP", service_name);
166 tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstop),TDB_REPLACE);
168 pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name);
169 tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstart),TDB_REPLACE);
171 pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name);
172 tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstop),TDB_REPLACE);
174 pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name);
175 tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE);
177 pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name);
178 tdb_lock_bystring(stdb, keystring, 0);
179 if (si->shortdescription && *si->shortdescription)
180 tdb_store_bystring(stdb,keystring,string_tdb_data(si->shortdescription),TDB_REPLACE);
182 tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE);
188 /*******************************************************************************
189 Get the INTERNAL services information for the given service name.
190 *******************************************************************************/
192 static BOOL _svcctl_get_internal_service_data(const Internal_service_description *isd, Service_info *si)
197 pstrcpy( si->servicename, isd->displayname);
198 pstrcpy( si->servicetype, "INTERNAL");
199 pstrcpy( si->filename, isd->filename);
200 pstrcpy( si->provides, isd->displayname);
201 pstrcpy( si->description, isd->description);
202 pstrcpy( si->shortdescription, isd->description);
209 /*******************************************************************************
210 Get the services information by reading and parsing the shell scripts. These
211 are symbolically linked into the SVCCTL_SCRIPT_DIR directory.
213 Get the names of the services/scripts to read from the smb.conf file.
214 *******************************************************************************/
216 static BOOL _svcctl_get_LSB_data(char *fname,Service_info *si )
220 const char *tokenptr;
223 int nlines, *numlines,i,in_section,in_description;
225 pstrcpy(si->servicename,"");
226 pstrcpy(si->servicetype,"EXTERNAL");
227 pstrcpy(si->filename,fname);
228 pstrcpy(si->provides,"");
229 pstrcpy(si->dependencies,"");
230 pstrcpy(si->shouldstart,"");
231 pstrcpy(si->shouldstop,"");
232 pstrcpy(si->requiredstart,"");
233 pstrcpy(si->requiredstop,"");
234 pstrcpy(si->description,"");
235 pstrcpy(si->shortdescription,"");
242 if( !fname || !*fname ) {
243 DEBUG(0, ("Must define an \"LSB-style init file\" to read.\n"));
246 pstrcpy(initdfile,dyn_LIBDIR);
247 pstrcat(initdfile,SVCCTL_SCRIPT_DIR);
248 pstrcat(initdfile,fname);
250 /* TODO - should check to see if the file that we're trying to open is
251 actually a script. If it's NOT, we should do something like warn,
252 and not continue to try to find info we're looking for */
254 DEBUG(10, ("Opening [%s]\n", initdfile));
256 fd = open(initdfile,O_RDONLY);
260 DEBUG(10, ("Couldn't open [%s]\n", initdfile));
264 qlines = fd_lines_load(fd, numlines);
265 DEBUGADD(10, ("Lines returned = [%d]\n", *numlines));
271 for(i = 0; i < *numlines; i++) {
273 DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i]));
274 if (!in_section && (0==strwicmp("### BEGIN INIT INFO", qlines[i]))) {
275 /* we now can look for params */
276 DEBUGADD(10, ("Configuration information starts on line = [%d]\n", i));
279 } else if (in_section && (0==strwicmp("### END INIT INFO", qlines[i]))) {
280 DEBUGADD(10, ("Configuration information ends on line = [%d]\n", i));
281 DEBUGADD(10, ("Description is [%s]\n", si->description));
285 } else if (in_section) {
286 tokenptr = qlines[i];
287 if (in_description) {
288 DEBUGADD(10, ("Processing DESCRIPTION [%d]\n", *tokenptr));
289 if (tokenptr && (*tokenptr=='#') && (*(tokenptr+1)=='\t')) {
290 DEBUGADD(10, ("Adding to DESCRIPTION [%d]\n", *tokenptr));
291 pstrcat(si->description," ");
292 pstrcat(si->description,tokenptr+2);
296 DEBUGADD(10, ("Not a description!\n"));
298 if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) {
299 DEBUGADD(10, ("Invalid line [%d]\n", i));
300 break; /* bad line? */
302 if (0 != strncmp(mybuffer,"#",1)) {
303 DEBUGADD(10, ("Invalid line [%d], is %s\n", i,mybuffer));
306 if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) {
307 DEBUGADD(10, ("Invalid token on line [%d]\n", i));
308 break; /* bad line? */
310 DEBUGADD(10, ("Keyword is [%s]\n", mybuffer));
311 if (0==strwicmp(mybuffer,"Description:")) {
312 while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) {
315 pstrcpy(si->description,tokenptr);
316 DEBUGADD(10, ("FOUND DESCRIPTION! Data is [%s]\n", tokenptr));
319 while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) {
322 DEBUGADD(10, ("Data is [%s]\n", tokenptr));
325 /* save certain keywords, don't save others */
326 if (0==strwicmp(mybuffer, "Provides:")) {
327 pstrcpy(si->provides,tokenptr);
328 pstrcpy(si->servicename,tokenptr);
331 if (0==strwicmp(mybuffer, "Short-Description:")) {
332 pstrcpy(si->shortdescription,tokenptr);
335 if (0==strwicmp(mybuffer, "Required-start:")) {
336 pstrcpy(si->requiredstart,tokenptr);
337 pstrcpy(si->dependencies,tokenptr);
340 if (0==strwicmp(mybuffer, "Should-start:")) {
341 pstrcpy(si->shouldstart,tokenptr);
347 file_lines_free(qlines);
354 /****************************************************************************
355 Create/Open the service control manager tdb. This code a clone of init_group_mapping.
356 ****************************************************************************/
358 BOOL init_svcctl_db(void)
360 const char *vstring = "INFO/version";
365 pstring external_service_list;
366 pstring internal_service_list;
368 const Internal_service_description *isd_ptr;
369 /* svc_list = str_list_make( "etc/init.d/skeleton etc/init.d/syslog", NULL ); */
370 svc_list=(char **)lp_enable_svcctl();
375 pstrcpy(external_service_list,"");
377 service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
379 DEBUG(0,("Failed to open service db\n"));
380 service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
381 if (!service_tdb) return False;
382 DEBUG(0,("Created new services db\n"));
385 if ((-1 == tdb_fetch_uint32(service_tdb, vstring,&vers_id)) || (vers_id != SERVICEDB_VERSION_V1)) {
386 /* wrong version of DB, or db was just created */
387 tdb_traverse(service_tdb, tdb_traverse_delete_fn, NULL);
388 tdb_store_uint32(service_tdb, vstring, SERVICEDB_VERSION_V1);
390 tdb_unlock_bystring(service_tdb, vstring);
392 DEBUG(0,("Initializing services db\n"));
396 /* Get the EXTERNAL services as mentioned by line in smb.conf */
399 DEBUG(10,("Reading information on service %s\n",*svcname));
400 if (_svcctl_get_LSB_data(*svcname,&si));{
401 /* write the information to the TDB */
402 write_si_to_service_tdb(service_tdb,*svcname,&si);
403 /* definitely not efficient to do it this way. */
404 pstrcat(external_service_list,"\"");
405 pstrcat(external_service_list,*svcname);
406 pstrcat(external_service_list,"\" ");
410 pstrcpy(keystring,"EXTERNAL_SERVICES");
411 tdb_lock_bystring(service_tdb, keystring, 0);
412 DEBUG(8,("Storing external service list [%s]\n",external_service_list));
413 tdb_store_bystring(service_tdb,keystring,string_tdb_data(external_service_list),TDB_REPLACE);
414 tdb_unlock_bystring(service_tdb,keystring);
416 /* Get the INTERNAL services */
418 pstrcpy(internal_service_list,"");
421 while (isd_ptr && (isd_ptr->filename)) {
422 DEBUG(10,("Reading information on service %s\n",isd_ptr->filename));
423 if (_svcctl_get_internal_service_data(isd_ptr,&si)){
424 /* write the information to the TDB */
425 write_si_to_service_tdb(service_tdb,(char *)isd_ptr->filename,&si);
426 /* definitely not efficient to do it this way. */
427 pstrcat(internal_service_list,"\"");
428 pstrcat(internal_service_list,isd_ptr->filename);
429 pstrcat(internal_service_list,"\" ");
434 pstrcpy(keystring,"INTERNAL_SERVICES");
435 tdb_lock_bystring(service_tdb, keystring, 0);
436 DEBUG(8,("Storing internal service list [%s]\n",internal_service_list));
437 tdb_store_bystring(service_tdb,keystring,string_tdb_data(internal_service_list),TDB_REPLACE);
438 tdb_unlock_bystring(service_tdb,keystring);
443 /********************************************************************
444 ********************************************************************/
446 static NTSTATUS svcctl_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token,
447 uint32 access_desired, uint32 *access_granted )
451 /* maybe add privilege checks in here later */
453 se_access_check( sec_desc, token, access_desired, access_granted, &result );
458 /********************************************************************
459 ********************************************************************/
461 static SEC_DESC* construct_scm_sd( TALLOC_CTX *ctx )
470 /* basic access for Everyone */
472 init_sec_access(&mask, SC_MANAGER_READ_ACCESS );
473 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
475 /* Full Access 'BUILTIN\Administrators' */
477 init_sec_access(&mask,SC_MANAGER_ALL_ACCESS );
478 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
481 /* create the security descriptor */
483 if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
486 if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
492 /********************************************************************
493 ********************************************************************/
495 static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx )
504 /* basic access for Everyone */
506 init_sec_access(&mask, SERVICE_READ_ACCESS );
507 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
509 init_sec_access(&mask,SERVICE_EXECUTE_ACCESS );
510 init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
512 init_sec_access(&mask,SERVICE_ALL_ACCESS );
513 init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
514 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
516 /* create the security descriptor */
518 if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
521 if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
528 /********************************************************************
529 ********************************************************************/
531 static BOOL read_service_tdb_to_si(TDB_CONTEXT *stdb,char *service_name, Service_info *si)
537 if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0))
540 /* TODO - error handling -- what if the service isn't in the DB? */
542 pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name);
543 key_data = tdb_fetch_bystring(stdb,keystring);
544 strncpy(si->servicetype,key_data.dptr,key_data.dsize);
545 si->servicetype[key_data.dsize] = 0;
547 /* crude check to see if the service exists... */
548 DEBUG(3,("Size of the TYPE field is %d\n",key_data.dsize));
549 if (key_data.dsize == 0)
552 pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name);
553 key_data = tdb_fetch_bystring(stdb,keystring);
554 strncpy(si->filename,key_data.dptr,key_data.dsize);
555 si->filename[key_data.dsize] = 0;
557 pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name);
558 key_data = tdb_fetch_bystring(stdb,keystring);
559 strncpy(si->provides,key_data.dptr,key_data.dsize);
560 si->provides[key_data.dsize] = 0;
561 strncpy(si->servicename,key_data.dptr,key_data.dsize);
562 si->servicename[key_data.dsize] = 0;
565 pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name);
566 key_data = tdb_fetch_bystring(stdb,keystring);
567 strncpy(si->dependencies,key_data.dptr,key_data.dsize);
568 si->dependencies[key_data.dsize] = 0;
570 pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name);
571 key_data = tdb_fetch_bystring(stdb,keystring);
572 strncpy(si->shouldstart,key_data.dptr,key_data.dsize);
573 si->shouldstart[key_data.dsize] = 0;
575 pstr_sprintf(keystring,"SERVICE/%s/SHOULD_STOP", service_name);
576 key_data = tdb_fetch_bystring(stdb,keystring);
577 strncpy(si->shouldstop,key_data.dptr,key_data.dsize);
578 si->shouldstop[key_data.dsize] = 0;
580 pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name);
581 key_data = tdb_fetch_bystring(stdb,keystring);
582 strncpy(si->requiredstart,key_data.dptr,key_data.dsize);
583 si->requiredstart[key_data.dsize] = 0;
585 pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name);
586 key_data = tdb_fetch_bystring(stdb,keystring);
587 strncpy(si->requiredstop,key_data.dptr,key_data.dsize);
588 si->requiredstop[key_data.dsize] = 0;
590 pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name);
591 key_data = tdb_fetch_bystring(stdb,keystring);
592 strncpy(si->description,key_data.dptr,key_data.dsize);
593 si->description[key_data.dsize] = 0;
595 pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name);
596 key_data = tdb_fetch_bystring(stdb,keystring);
597 strncpy(si->shortdescription,key_data.dptr,key_data.dsize);
598 si->shortdescription[key_data.dsize] = 0;
603 /******************************************************************
604 free() function for REGISTRY_KEY
605 *****************************************************************/
607 static void free_service_handle_info(void *ptr)
609 SERVICE_INFO *info = (SERVICE_INFO*)ptr;
611 SAFE_FREE(info->name);
615 /******************************************************************
616 Find a registry key handle and return a SERVICE_INFO
617 *****************************************************************/
619 static SERVICE_INFO *find_service_info_by_hnd(pipes_struct *p, POLICY_HND *hnd)
621 SERVICE_INFO *service_info = NULL;
623 if( !find_policy_by_hnd( p, hnd, (void **)&service_info) ) {
624 DEBUG(2,("find_service_info_by_hnd: handle not found"));
631 /******************************************************************
632 *****************************************************************/
634 static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle,
635 const char *service, uint32 access_granted )
637 SERVICE_INFO *info = NULL;
639 if ( !(info = SMB_MALLOC_P( SERVICE_INFO )) )
642 ZERO_STRUCTP( info );
644 /* the Service Manager has a NULL name */
647 info->type = SVC_HANDLE_IS_SCM;
649 info->type = SVC_HANDLE_IS_SERVICE;
651 if ( !(info->name = SMB_STRDUP( service )) ) {
652 free_service_handle_info( info );
657 /* lookup the SERVICE_CONTROL_OPS */
659 for ( i=0; svcctl_ops[i].name; i++ ) {
665 info->access_granted = access_granted;
667 /* store the SERVICE_INFO and create an open handle */
669 if ( !create_policy_hnd( p, handle, free_service_handle_info, info ) ) {
670 free_service_handle_info( info );
671 return WERR_ACCESS_DENIED;
677 /********************************************************************
678 ********************************************************************/
680 WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVCCTL_R_OPEN_SCMANAGER *r_u)
683 uint32 access_granted = 0;
686 /* perform access checks */
688 if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) )
691 status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
692 if ( !NT_STATUS_IS_OK(status) )
693 return ntstatus_to_werror( status );
695 return create_open_service_handle( p, &r_u->handle, NULL, access_granted );
698 /********************************************************************
699 ********************************************************************/
701 WERROR _svcctl_open_service(pipes_struct *p, SVCCTL_Q_OPEN_SERVICE *q_u, SVCCTL_R_OPEN_SERVICE *r_u)
704 uint32 access_granted = 0;
708 rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
710 DEBUG(5, ("_svcctl_open_service: Attempting to open Service [%s], \n", service));
712 if ( !service_tdb ) {
713 DEBUG(1, ("_svcctl_open_service: service database is not open\n!"));
714 return WERR_ACCESS_DENIED;
717 /* perform access checks */
719 if ( !(sec_desc = construct_service_sd( p->mem_ctx )) )
722 status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
723 if ( !NT_STATUS_IS_OK(status) )
724 return ntstatus_to_werror( status );
727 if ( ! read_service_tdb_to_si(service_tdb,service, info) ) {
728 return WERR_NO_SUCH_SERVICE;
731 return create_open_service_handle( p, &r_u->handle, service, access_granted );
734 /********************************************************************
735 ********************************************************************/
737 WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCTL_R_CLOSE_SERVICE *r_u)
739 return close_policy_hnd( p, &q_u->handle ) ? WERR_OK : WERR_BADFID;
742 /********************************************************************
743 ********************************************************************/
745 WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, SVCCTL_R_GET_DISPLAY_NAME *r_u)
750 SERVICE_INFO *service_info;
753 rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
755 handle = &(q_u->handle);
757 service_info = find_service_info_by_hnd(p, handle);
760 DEBUG(10, ("_svcctl_get_display_name : Can't find the service for the handle\n"));
761 return WERR_ACCESS_DENIED;
764 DEBUG(10,("_svcctl_get_display_name: Found service [%s]\n", service_info->name ));
766 fstrcpy( displayname, "FIX ME!" );
768 init_svcctl_r_get_display_name( r_u, displayname );
773 /********************************************************************
774 ********************************************************************/
776 WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_R_QUERY_STATUS *r_u)
778 r_u->svc_status.type = 0x0020;
779 r_u->svc_status.state = 0x0004;
780 r_u->svc_status.controls_accepted = 0x0005;
785 /* allocate an array of external services and return them. Null return is okay, make sure &added is also zero! */
787 int _svcctl_num_external_services(void)
791 pstring keystring, external_services_string;
796 DEBUG(8,("enum_external_services: service database is not open!!!\n"));
799 pstrcpy(keystring,"EXTERNAL_SERVICES");
800 tdb_lock_bystring(service_tdb, keystring, 0);
801 key_data = tdb_fetch_bystring(service_tdb, keystring);
803 if ((key_data.dptr != NULL) && (key_data.dsize != 0)) {
804 strncpy(external_services_string,key_data.dptr,key_data.dsize);
805 external_services_string[key_data.dsize] = 0;
806 DEBUG(8,("enum_external_services: services list is %s, size is %d\n",external_services_string,key_data.dsize));
808 tdb_unlock_bystring(service_tdb, keystring);
810 svc_list = str_list_make(external_services_string,NULL);
812 num_services = str_list_count( (const char **)svc_list);
819 /********************************************************************
820 Gather information on the "external services". These are services
821 listed in the smb.conf file, and found to exist through checks in
822 this code. Note that added will be incremented on the basis of the
823 number of services added. svc_ptr should have enough memory allocated
824 to accommodate all of the services that exist.
826 Typically _svcctl_num_external_services is used to "size" the amount of
827 memory allocated, but does little/no work.
829 enum_external_services() actually examines each of the specified
830 external services, populates the memory structures, and returns.
832 ** note that 'added' may end up with less than the number of services
833 found in _num_external_services, such as the case when a service is
834 called out, but the actual service doesn't exist or the file can't be
835 read for the service information.
836 ********************************************************************/
838 WERROR enum_external_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services,int *added)
840 /* *svc_ptr must have pre-allocated memory */
841 int num_services = 0;
843 ENUM_SERVICES_STATUS *services=NULL;
844 char **svc_list,**svcname;
845 pstring command, keystring, external_services_string;
851 *added = num_services;
854 DEBUG(8,("enum_external_services: service database is not open!!!\n"));
856 pstrcpy(keystring,"EXTERNAL_SERVICES");
857 tdb_lock_bystring(service_tdb, keystring, 0);
858 key_data = tdb_fetch_bystring(service_tdb, keystring);
859 if ((key_data.dptr != NULL) && (key_data.dsize != 0)) {
860 strncpy(external_services_string,key_data.dptr,key_data.dsize);
861 external_services_string[key_data.dsize] = 0;
862 DEBUG(8,("enum_external_services: services list is %s, size is %d\n",external_services_string,key_data.dsize));
864 tdb_unlock_bystring(service_tdb, keystring);
866 svc_list = str_list_make(external_services_string,NULL);
868 num_services = str_list_count( (const char **)svc_list);
870 if (0 == num_services) {
871 DEBUG(8,("enum_external_services: there are no external services\n"));
872 *added = num_services;
875 DEBUG(8,("enum_external_services: there are [%d] external services\n",num_services));
876 si=TALLOC_ARRAY( tcx, Service_info, 1 );
878 DEBUG(8,("enum_external_services: Failed to alloc si\n"));
883 /* *svc_ptr has the pointer to the array if there is one already. NULL if not. */
884 if ((existing_services>0) && svc_ptr && *svc_ptr) { /* reallocate vs. allocate */
885 DEBUG(8,("enum_external_services: REALLOCing %x to %d services\n", *svc_ptr, existing_services+num_services));
887 services=TALLOC_REALLOC_ARRAY(tcx,*svc_ptr,ENUM_SERVICES_STATUS,existing_services+num_services);
888 DEBUG(8,("enum_external_services: REALLOCed to %x services\n", services));
890 if (!services) return WERR_NOMEM;
893 if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
898 if (!svc_ptr || !(*svc_ptr))
901 if (existing_services > 0) {
902 i+=existing_services;
906 DEBUG(8,("enum_external_services: enumerating %d external services starting at index %d\n", num_services,existing_services));
909 DEBUG(10,("enum_external_services: Reading information on service %s, index %d\n",*svcname,i));
910 /* _svcctl_get_LSB_data(*svcname,si); */
911 if (!read_service_tdb_to_si(service_tdb,*svcname, si)) {
912 DEBUG(1,("enum_external_services: CAN'T FIND INFO FOR SERVICE %s in the services DB\n",*svcname));
915 if ((si->filename == NULL) || (*si->filename == 0)) {
916 init_unistr(&services[i].servicename, *svcname );
918 init_unistr( &services[i].servicename, si->filename );
919 /* init_unistr( &services[i].servicename, si->servicename ); */
922 if ((si->provides == NULL) || (*si->provides == 0)) {
923 init_unistr(&services[i].displayname, *svcname );
925 init_unistr( &services[i].displayname, si->provides );
928 /* TODO - we could keep the following info in the DB, too... */
930 DEBUG(8,("enum_external_services: Service name [%s] displayname [%s]\n",
931 si->filename, si->provides));
932 services[i].status.type = SVCCTL_WIN32_OWN_PROC;
933 services[i].status.win32_exit_code = 0x0;
934 services[i].status.service_exit_code = 0x0;
935 services[i].status.check_point = 0x0;
936 services[i].status.wait_hint = 0x0;
938 /* TODO - do callout here to get the status */
940 memset(command, 0, sizeof(command));
941 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, *svcname, "status");
943 DEBUG(10, ("enum_external_services: status command is [%s]\n", command));
945 /* TODO - wrap in privilege check */
947 ret = smbrun(command, &fd);
948 DEBUGADD(10, ("returned [%d]\n", ret));
951 DEBUG(10, ("enum_external_services: Command returned [%d]\n", ret));
952 services[i].status.state = SVCCTL_STOPPED;
954 services[i].status.state = SVCCTL_RUNNING;
955 services[i].status.controls_accepted = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
957 services[i].status.state = SVCCTL_STOPPED;
958 services[i].status.controls_accepted = 0;
964 DEBUG(10,("enum_external_services: Read services %d\n",num_services));
965 *added = num_services;
970 int _svcctl_num_internal_services(void)
974 pstring keystring, internal_services_string;
978 DEBUG(8,("_svcctl_enum_internal_services: service database is not open!!!\n"));
981 pstrcpy(keystring,"INTERNAL_SERVICES");
982 tdb_lock_bystring(service_tdb, keystring, 0);
983 key_data = tdb_fetch_bystring(service_tdb, keystring);
985 if ((key_data.dptr != NULL) && (key_data.dsize != 0)) {
986 strncpy(internal_services_string,key_data.dptr,key_data.dsize);
987 internal_services_string[key_data.dsize] = 0;
988 DEBUG(8,("_svcctl_enum_internal_services: services list is %s, size is %d\n",internal_services_string,key_data.dsize));
990 tdb_unlock_bystring(service_tdb, keystring);
992 svc_list = str_list_make(internal_services_string,NULL);
994 num_services = str_list_count( (const char **)svc_list);
1001 int _svcctl_num_internal_services(void)
1007 /* TODO - for internal services, do similar to external services, except we have to call the right status routine... */
1009 WERROR _svcctl_enum_internal_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services, int *added)
1011 int num_services = 2;
1013 ENUM_SERVICES_STATUS *services=NULL;
1015 if (!svc_ptr || !(*svc_ptr))
1018 services = *svc_ptr;
1021 /* *svc_ptr has the pointer to the array if there is one already. NULL if not. */
1022 if ((existing_services>0) && svc_ptr && *svc_ptr) { /* reallocate vs. allocate */
1023 DEBUG(8,("_svcctl_enum_internal_services: REALLOCing %d services\n", num_services));
1024 services = TALLOC_REALLOC_ARRAY(tcx,*svc_ptr,ENUM_SERVICES_STATUS,existing_services+num_services);
1027 *svc_ptr = services;
1029 if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
1034 if (existing_services > 0) {
1035 i += existing_services;
1037 DEBUG(8,("_svcctl_enum_internal_services: Creating %d services, starting index %d\n", num_services,existing_services));
1039 init_unistr( &services[i].servicename, "Spooler" );
1040 init_unistr( &services[i].displayname, "Print Spooler" );
1042 services[i].status.type = 0x110;
1043 services[i].status.controls_accepted = 0x0;
1044 services[i].status.win32_exit_code = 0x0;
1045 services[i].status.service_exit_code = 0x0;
1046 services[i].status.check_point = 0x0;
1047 services[i].status.wait_hint = 0x0;
1048 if ( !lp_disable_spoolss() )
1049 services[i].status.state = SVCCTL_RUNNING;
1051 services[i].status.state = SVCCTL_STOPPED;
1055 init_unistr( &services[i].servicename, "NETLOGON" );
1056 init_unistr( &services[i].displayname, "Net Logon" );
1058 services[i].status.type = 0x20;
1059 services[i].status.controls_accepted = 0x0;
1060 services[i].status.win32_exit_code = 0x0;
1061 services[i].status.service_exit_code = 0x0;
1062 services[i].status.check_point = 0x0;
1063 services[i].status.wait_hint = 0x0;
1064 if ( lp_servicenumber("NETLOGON") != -1 )
1065 services[i].status.state = SVCCTL_RUNNING;
1067 services[i].status.state = SVCCTL_STOPPED;
1069 *added = num_services;
1074 WERROR _init_svcdb(void)
1077 talloc_destroy(svcdb);
1079 svcdb = talloc_init("services DB");
1084 /********************************************************************
1085 ********************************************************************/
1087 WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
1089 ENUM_SERVICES_STATUS *services = NULL;
1091 uint32 num_int_services = 0;
1092 uint32 num_ext_services = 0;
1095 WERROR result = WERR_OK;
1096 WERROR ext_result = WERR_OK;
1098 /* num_services = str_list_count( lp_enable_svcctl() ); */
1100 /* here's where we'll read the db of external services */
1101 /* _svcctl_read_LSB_data(NULL,NULL); */
1102 /* init_svcctl_db(); */
1104 num_int_services = 0;
1106 num_int_services = _svcctl_num_internal_services();
1108 num_ext_services = _svcctl_num_external_services();
1110 if ( !(services = TALLOC_ARRAY(p->mem_ctx, ENUM_SERVICES_STATUS, num_int_services+num_ext_services )) )
1113 result = _svcctl_enum_internal_services(p->mem_ctx, &services, 0, &num_int_services);
1115 if (W_ERROR_IS_OK(result)) {
1116 DEBUG(8,("_svcctl_enum_services_status: Got %d internal services\n", num_int_services));
1119 ext_result=enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services);
1121 if (W_ERROR_IS_OK(ext_result)) {
1122 DEBUG(8,("_svcctl_enum_services_status: Got %d external services\n", num_ext_services));
1125 DEBUG(8,("_svcctl_enum_services_status: total of %d services\n", num_int_services+num_ext_services));
1128 for (i=0;i<num_int_services+num_ext_services;i++) {
1129 buffer_size += svcctl_sizeof_enum_services_status(&services[i]);
1133 buffer_size += buffer_size % 4;
1134 DEBUG(8,("_svcctl_enum_services_status: buffer size passed %d, we need %d\n",
1135 q_u->buffer_size, buffer_size));
1137 if (buffer_size > q_u->buffer_size ) {
1138 num_int_services = 0;
1139 num_ext_services = 0;
1140 result = WERR_MORE_DATA;
1143 rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
1145 if ( W_ERROR_IS_OK(result) ) {
1146 for ( i=0; i<num_int_services+num_ext_services; i++ )
1147 svcctl_io_enum_services_status( "", &services[i], &r_u->buffer, 0 );
1150 r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
1151 r_u->returned = num_int_services+num_ext_services;
1153 if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) )
1161 /********************************************************************
1162 ********************************************************************/
1164 WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCTL_R_START_SERVICE *r_u)
1166 return WERR_ACCESS_DENIED;
1169 /********************************************************************
1170 ********************************************************************/
1172 WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, SVCCTL_R_CONTROL_SERVICE *r_u)
1175 SERVICE_INFO *service_info;
1178 SERVICE_STATUS *service_status;
1181 /* need to find the service name by the handle that is open */
1182 handle = &(q_u->handle);
1184 service_info = find_service_info_by_hnd(p, handle);
1186 if (!service_info) {
1187 DEBUG(10, ("_svcctl_control_service : Can't find the service for the handle\n"));
1191 /* we return a SERVICE_STATUS structure if there's an error. */
1192 if ( !(service_status = TALLOC_ARRAY(p->mem_ctx, SERVICE_STATUS, 1 )) )
1195 DEBUG(10, ("_svcctl_control_service: Found service [%s], [%s]\n",
1196 service_info->servicename, service_info->filename));
1198 /* TODO - call the service config function here... */
1199 memset(command, 0, sizeof(command));
1200 if (q_u->control == SVCCTL_CONTROL_STOP) {
1201 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR,
1202 service_info->filename, "stop");
1205 if (q_u->control == SVCCTL_CONTROL_PAUSE) {
1206 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR,
1207 service_info->filename, "stop");
1210 if (q_u->control == SVCCTL_CONTROL_CONTINUE) {
1211 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR,
1212 service_info->filename, "restart");
1215 DEBUG(10, ("_svcctl_control_service: status command is [%s]\n", command));
1217 /* TODO - wrap in privilege check */
1219 ret = smbrun(command, &fd);
1220 DEBUGADD(10, ("returned [%d]\n", ret));
1224 DEBUG(10, ("enum_external_services: Command returned [%d]\n", ret));
1226 /* SET all service_stats bits here...*/
1228 service_status->state = SVCCTL_RUNNING;
1229 service_status->controls_accepted = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
1231 service_status->state = SVCCTL_STOPPED;
1232 service_status->controls_accepted = 0;
1235 DEBUG(10, ("_svcctl_query_service_config: Should call the commFound service [%s], [%s]\n",service_info->servicename,service_info->filename));
1242 /********************************************************************
1243 ********************************************************************/
1245 WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT_SERVICES *q_u, SVCCTL_R_ENUM_DEPENDENT_SERVICES *r_u )
1248 /* we have to set the outgoing buffer size to the same as the
1249 incoming buffer size (even in the case of failure */
1251 rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
1253 r_u->needed = q_u->buffer_size;
1255 /* no dependent services...basically a stub function */
1261 /********************************************************************
1262 ********************************************************************/
1264 WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u )
1266 SERVICE_STATUS_PROCESS ssp;
1268 SERVICE_INFO *service_info;
1271 /* we have to set the outgoing buffer size to the same as the
1272 incoming buffer size (even in the case of failure */
1274 r_u->needed = q_u->buffer_size;
1276 /* need to find the service name by the handle that is open */
1277 handle = &(q_u->handle);
1280 /* get rid of the easy errors */
1282 if (q_u->info_level != SVC_STATUS_PROCESS_INFO) {
1283 DEBUG(10, ("_svcctl_query_service_status_ex : Invalid information level specified\n"));
1284 return WERR_UNKNOWN_LEVEL;
1287 service_info = find_service_info_by_hnd(p, handle);
1289 if (!service_info) {
1290 DEBUG(10, ("_svcctl_query_service_status_ex : Can't find the service for the handle\n"));
1294 if (r_u->needed < (sizeof(SERVICE_STATUS_PROCESS)+sizeof(uint32)+sizeof(uint32))) {
1295 DEBUG(10, ("_svcctl_query_service_status_ex : buffer size of [%d] is too small.\n",r_u->needed));
1296 return WERR_INSUFFICIENT_BUFFER;
1302 if (!strwicmp(service_info->servicetype,"EXTERNAL"))
1303 ssp.type = SVCCTL_WIN32_OWN_PROC;
1305 ssp.type = SVCCTL_WIN32_SHARED_PROC;
1308 /* Get the status of the service.. */
1310 memset(command, 0, sizeof(command));
1313 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, service_info->filename, "status");
1315 DEBUG(10, ("_svcctl_query_service_status_ex: status command is [%s]\n", command));
1317 /* TODO - wrap in privilege check */
1319 ret = smbrun(command, &fd);
1320 DEBUGADD(10, ("returned [%d]\n", ret));
1323 DEBUG(10, ("_svcctl_query_service_status_ex: Command returned [%d]\n", ret));
1325 /* SET all service_stats bits here... */
1327 ssp.state = SVCCTL_RUNNING;
1328 ssp.controls_accepted = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
1330 ssp.state = SVCCTL_STOPPED;
1331 ssp.controls_accepted = 0;
1338 /********************************************************************
1339 ********************************************************************/
1341 WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
1344 SERVICE_INFO *service_info;
1347 /* we have to set the outgoing buffer size to the same as the
1348 incoming buffer size (even in the case of failure */
1350 r_u->needed = q_u->buffer_size;
1352 /* need to find the service name by the handle that is open */
1353 handle = &(q_u->handle);
1355 service_info = find_service_info_by_hnd(p, handle);
1358 if (q_u->buffer_size < sizeof(Service_info)) {
1359 /* have to report need more... */
1360 /* TODO worst case -- should actualy calc what we need here. */
1361 r_u->needed = sizeof(Service_info)+sizeof(pstring)*5;
1362 DEBUG(10, ("_svcctl_query_service_config: NOT ENOUGH BUFFER ALLOCATED FOR RETURN DATA -- provided %d wanted %d\n",
1363 q_u->buffer_size,r_u->needed));
1365 return WERR_INSUFFICIENT_BUFFER;
1368 if (!service_info) {
1369 DEBUG(10, ("_svcctl_query_service_config : Can't find the service for the handle\n"));
1374 if ( !(service_config = (SERVICE_CONFIG *)TALLOC_ZERO_P(p->mem_ctx, SERVICE_CONFIG)) )
1378 r_u->config.service_type = SVCCTL_WIN32_OWN_PROC;
1379 r_u->config.start_type = SVCCTL_DEMAND_START;
1380 r_u->config.error_control = SVCCTL_SVC_ERROR_IGNORE;
1381 r_u->config.tag_id = 0x00000000;
1383 /* Init the strings */
1385 r_u->config.executablepath = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
1386 r_u->config.loadordergroup = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
1387 r_u->config.dependencies = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
1388 r_u->config.startname = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
1389 r_u->config.displayname = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
1392 pstrcpy(fullpathinfo,dyn_LIBDIR);
1393 pstrcat(fullpathinfo,SVCCTL_SCRIPT_DIR);
1394 pstrcat(fullpathinfo,service_info->filename);
1395 /* Get and calculate the size of the fields. Note that we're still building the fields in the "too-small buffer case"
1396 even though we throw it away. */
1398 DEBUG(10, ("_svcctl_query_service_config: fullpath info [%s]\n",fullpathinfo));
1399 init_unistr2(r_u->config.executablepath,fullpathinfo,UNI_STR_TERMINATE);
1400 init_unistr2(r_u->config.loadordergroup,"",UNI_STR_TERMINATE);
1401 init_unistr2(r_u->config.dependencies,service_info->dependencies,UNI_STR_TERMINATE);
1403 /* TODO - if someone really cares, perhaps "LocalSystem" should be changed to something else here... */
1405 init_unistr2(r_u->config.startname,"LocalSystem",UNI_STR_TERMINATE);
1406 init_unistr2(r_u->config.displayname,service_info->servicename,UNI_STR_TERMINATE);
1409 needed_size = 0x04 + sizeof(SERVICE_CONFIG)+ 2*(
1410 r_u->config.executablepath->uni_str_len +
1411 r_u->config.loadordergroup->uni_str_len +
1412 r_u->config.dependencies->uni_str_len +
1413 r_u->config.startname->uni_str_len +
1414 r_u->config.displayname->uni_str_len);
1416 DEBUG(10, ("_svcctl_query_service_config: ****** need to have a buffer of [%d], [%d] for struct \n",needed_size,
1417 sizeof(SERVICE_CONFIG)));
1418 DEBUG(10, ("\tsize of executable path : %d\n",r_u->config.executablepath->uni_str_len));
1419 DEBUG(10, ("\tsize of loadordergroup : %d\n", r_u->config.loadordergroup->uni_str_len));
1420 DEBUG(10, ("\tsize of dependencies : %d\n", r_u->config.dependencies->uni_str_len));
1421 DEBUG(10, ("\tsize of startname : %d\n", r_u->config.startname->uni_str_len));
1422 DEBUG(10, ("\tsize of displayname : %d\n", r_u->config.displayname->uni_str_len));
1424 if (q_u->buffer_size < needed_size) {
1425 /* have to report need more...*/
1426 r_u->needed = needed_size;
1427 DEBUG(10, ("_svcctl_query_service_config: ****** zeroing strings for return\n"));
1428 memset(&r_u->config,0,sizeof(SERVICE_CONFIG));
1429 DEBUG(10, ("_svcctl_query_service_config: Not enouh buffer provided for return -- provided %d wanted %d\n",
1430 q_u->buffer_size,needed_size));
1431 return WERR_INSUFFICIENT_BUFFER;
1437 /********************************************************************
1438 ********************************************************************/
1440 WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u )
1443 SERVICE_INFO *service_info;
1446 /* we have to set the outgoing buffer size to the same as the
1447 incoming buffer size (even in the case of failure */
1449 r_u->needed = q_u->buffer_size;
1450 r_u->description = NULL;
1451 r_u->returned = q_u->buffer_size;
1454 handle = &(q_u->handle);
1456 service_info = find_service_info_by_hnd(p, handle);
1458 if (!service_info) {
1459 DEBUG(10, ("_svcctl_query_service_config2 : Can't find the service for the handle\n"));
1464 TODO - perhaps move the RPC_DATA_BLOB into the R_QUERY_SERVICE_CONFIG structure, and to the processing in here, vs
1465 in the *r_query_config2 marshalling routine...
1468 level = q_u->info_level;
1471 if (SERVICE_CONFIG_DESCRIPTION == level) {
1472 if (service_info && service_info->shortdescription) {
1473 /* length of the string, plus the terminator... */
1474 string_buffer_size = strlen(service_info->shortdescription)+1;
1475 DEBUG(10, ("_svcctl_query_service_config: copying the description [%s] length [%d]\n",
1476 service_info->shortdescription,string_buffer_size));
1478 if (q_u->buffer_size >= ((string_buffer_size)*2+4)) {
1479 r_u->description = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
1480 if (!r_u->description) return WERR_NOMEM;
1481 init_unistr2(r_u->description,service_info->shortdescription,UNI_STR_TERMINATE);
1485 string_buffer_size = 0;
1487 DEBUG(10, ("_svcctl_query_service_config2: buffer needed is [%x], return buffer size is [%x]\n",
1488 string_buffer_size,q_u->buffer_size));
1489 if (((string_buffer_size)*2+4) > q_u->buffer_size) {
1490 r_u->needed = (string_buffer_size+1)*2+4;
1491 DEBUG(10, ("_svcctl_query_service_config2: INSUFFICIENT BUFFER\n"));
1492 return WERR_INSUFFICIENT_BUFFER;
1494 DEBUG(10, ("_svcctl_query_service_config2: returning ok, needed is [%x], buffer size is [%x]\n",
1495 r_u->needed,q_u->buffer_size));
1501 return WERR_ACCESS_DENIED;