r7583: * more rearranging and renaming of functions
[samba.git] / source / rpc_server / srv_svcctl_nt.c
1 /* 
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.
6  *  
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.
11  *  
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.
16  *  
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.
20  */
21
22 /* TODO - Do the OpenService service name matching case-independently, or at least make it an option. */
23
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_RPC_SRV
29
30 #define SERVICEDB_VERSION_V1 1 /* Will there be more? */
31 #define INTERNAL_SERVICES_LIST "NETLOGON Spooler"
32
33 /*                                                                                                                     */
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                                                             */
37
38 #define SVCCTL_SCRIPT_DIR  "/svcctl/"
39
40 /*
41  * sertup the \PIPE\svcctl db API
42  */
43  
44 #define SCVCTL_DATABASE_VERSION_V1 1
45 static TDB_CONTEXT *service_tdb; /* used for services tdb file */
46
47 /* there are two types of services -- internal, and external.
48    Internal services are "built-in" to samba -- there may be 
49    functions that exist to provide the control and enumeration 
50    functions.  There certainly is information returned to be 
51    displayed in the typical management console.
52
53    External services are those that can be specified in the smb.conf 
54    file -- and they conform to the LSB specification as to having 
55    particular keywords in the scripts. Note that these "scripts" are 
56    located in the lib directory, and are likely links to LSB-compliant 
57    init.d scripts, such as those that might come with Suse. Note 
58    that the spec is located  http://www.linuxbase.org/spec/ */
59
60
61
62 /* Expand this to include what can and can't be done 
63    with a particular internal service. Expand as necessary 
64    to add other infromation like what can be controlled, 
65    etc. */
66
67 typedef struct Internal_service_struct
68 {
69         const char *filename;           /* internal name "index" */
70         const char *displayname;
71         const char *description;
72         const uint32 statustype;
73         void *status_fn; 
74         void *control_fn;
75 } Internal_service_description;
76
77
78 static const Internal_service_description ISD[] = {
79         { "NETLOGON",   "Net Logon",    "Provides logon and authentication service to the network",     0x110,  NULL, NULL},
80         { "Spooler",    "Spooler",      "Printing Services",                                            0x0020, NULL, NULL},
81         { NULL, NULL, NULL, 0, NULL, NULL}
82 };
83
84
85 /********************************************************************
86  TODOs
87  (a) get and set security descriptors on services
88  (b) read and write QUERY_SERVICE_CONFIG structures (both kinds, country and western)
89  (c) create default secdesc objects for services and SCM
90  (d) check access control masks with se_access_check()
91 ********************************************************************/
92
93 #if 0 
94 /*********************************************************************
95  given a service nice name, find the underlying service name
96 *********************************************************************/
97
98 static BOOL convert_service_displayname(TDB_CONTEXT *stdb,pstring service_nicename, pstring servicename,int szsvcname) 
99 {
100         pstring keystring;
101         TDB_DATA key_data;
102
103         if ((stdb == NULL) || (service_nicename==NULL) || (servicename == NULL)) 
104                 return False;
105
106         pstr_sprintf(keystring,"SERVICE_NICENAME/%s", servicename);
107
108         DEBUG(5, ("convert_service_displayname: Looking for service name [%s], key [%s]\n", 
109                 service_nicename, keystring));
110
111         key_data = tdb_fetch_bystring(stdb,keystring);
112
113         if (key_data.dsize == 0) {
114                 DEBUG(5, ("convert_service_displayname: [%s] Not found, tried key [%s]\n",service_nicename,keystring));
115                 return False; 
116         }
117
118         strncpy(servicename,key_data.dptr,szsvcname);
119         servicename[(key_data.dsize > szsvcname ? szsvcname : key_data.dsize)] = 0;
120         DEBUG(5, ("convert_service_displayname: Found service name [%s], name is  [%s]\n",
121                 service_nicename,servicename));
122
123         return True;
124 }
125 #endif
126
127 /*******************************************************************************
128  Get the INTERNAL services information for the given service name. 
129 *******************************************************************************/
130
131 static BOOL get_internal_service_data(const Internal_service_description *isd, Service_info *si)
132 {
133         ZERO_STRUCTP( si );
134 #if 0
135         
136         pstrcpy( si->servicename, isd->displayname);
137         pstrcpy( si->servicetype, "INTERNAL");
138         pstrcpy( si->filename, isd->filename);
139         pstrcpy( si->provides, isd->displayname);
140         pstrcpy( si->description, isd->description);
141         pstrcpy( si->shortdescription, isd->description);
142 #endif
143         
144         return True;
145 }
146
147
148 /*******************************************************************************
149  Get the services information  by reading and parsing the shell scripts. These 
150  are symbolically linked into the  SVCCTL_SCRIPT_DIR  directory.
151
152  Get the names of the services/scripts to read from the smb.conf file.
153 *******************************************************************************/
154
155 static BOOL get_LSB_data(char *fname,Service_info *si )
156 {
157         pstring initdfile;
158         char mybuffer[256];
159         const char *tokenptr;
160         char **qlines;
161         int fd = -1;
162         int nlines, *numlines,i,in_section,in_description;
163         
164         pstrcpy(si->servicename,"");
165         pstrcpy(si->servicetype,"EXTERNAL");
166         pstrcpy(si->filename,fname);
167         pstrcpy(si->provides,"");
168         pstrcpy(si->dependencies,"");
169         pstrcpy(si->shouldstart,"");
170         pstrcpy(si->shouldstop,"");
171         pstrcpy(si->requiredstart,"");
172         pstrcpy(si->requiredstop,"");
173         pstrcpy(si->description,"");
174         pstrcpy(si->shortdescription,"");
175
176         numlines = &nlines;
177         in_section = 0;
178         in_description = 0;
179
180    
181         if( !fname || !*fname ) {
182                 DEBUG(0, ("Must define an \"LSB-style init file\" to read.\n"));
183                 return False;
184         }
185         pstrcpy(initdfile,dyn_LIBDIR);
186         pstrcat(initdfile,SVCCTL_SCRIPT_DIR);
187         pstrcat(initdfile,fname);
188
189         /* TODO  - should check to see if the file that we're trying to open is 
190            actually a script. If it's NOT, we should do something like warn, 
191            and not continue to try to find info we're looking for */
192
193         DEBUG(10, ("Opening [%s]\n", initdfile));
194         fd = -1;
195         fd = open(initdfile,O_RDONLY);
196         *numlines = 0;
197
198         if (fd == -1) {
199                 DEBUG(10, ("Couldn't open [%s]\n", initdfile));
200                 return False;
201         }
202
203         qlines = fd_lines_load(fd, numlines);
204         DEBUGADD(10, ("Lines returned = [%d]\n", *numlines));
205         close(fd);
206     
207
208         if (*numlines) {
209         
210                 for(i = 0; i < *numlines; i++) {
211
212                         DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i]));
213                         if (!in_section && (0==strwicmp("### BEGIN INIT INFO", qlines[i]))) {
214                                 /* we now can look for params */
215                                 DEBUGADD(10, ("Configuration information starts on line = [%d]\n", i));
216                                 in_section = 1;
217
218                         } else if (in_section && (0==strwicmp("### END INIT INFO", qlines[i]))) {
219                                 DEBUGADD(10, ("Configuration information ends on line = [%d]\n", i));
220                                 DEBUGADD(10, ("Description is [%s]\n", si->description));
221                                 in_description = 0;
222                                 in_section = 0;
223                                 break;
224                         } else if (in_section) {
225                                 tokenptr = qlines[i];
226                                 if (in_description) {
227                                         DEBUGADD(10, ("Processing DESCRIPTION [%d]\n", *tokenptr));
228                                         if (tokenptr && (*tokenptr=='#') && (*(tokenptr+1)=='\t')) {
229                                                 DEBUGADD(10, ("Adding to DESCRIPTION [%d]\n", *tokenptr));
230                                                 pstrcat(si->description," ");
231                                                 pstrcat(si->description,tokenptr+2);
232                                                 continue;
233                                         }
234                                         in_description = 0;
235                                         DEBUGADD(10, ("Not a description!\n"));
236                                 }
237                                 if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) {
238                                         DEBUGADD(10, ("Invalid line [%d]\n", i));
239                                         break; /* bad line? */
240                                 }
241                                 if (0 != strncmp(mybuffer,"#",1)) {
242                                         DEBUGADD(10, ("Invalid line [%d], is %s\n", i,mybuffer));
243                                         break;
244                                 }
245                                 if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) {
246                                         DEBUGADD(10, ("Invalid token on line [%d]\n", i));
247                                         break; /* bad line? */
248                                 }             
249                                 DEBUGADD(10, ("Keyword is  [%s]\n", mybuffer));
250                                 if (0==strwicmp(mybuffer,"Description:")) {
251                                         while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { 
252                                                 tokenptr++; 
253                                         }
254                                         pstrcpy(si->description,tokenptr);
255                                         DEBUGADD(10, ("FOUND DESCRIPTION! Data is [%s]\n", tokenptr));
256                                         in_description = 1;
257                                 } else {
258                                         while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { 
259                                                 tokenptr++; 
260                                         }
261                                         DEBUGADD(10, ("Data is [%s]\n", tokenptr));
262                                         in_description = 0;
263
264                                         /* save certain keywords, don't save others */
265                                         if (0==strwicmp(mybuffer, "Provides:")) {
266                                                 pstrcpy(si->provides,tokenptr);
267                                                 pstrcpy(si->servicename,tokenptr);
268                                         }
269
270                                         if (0==strwicmp(mybuffer, "Short-Description:")) {
271                                                 pstrcpy(si->shortdescription,tokenptr);
272                                         }
273
274                                         if (0==strwicmp(mybuffer, "Required-start:")) {
275                                                 pstrcpy(si->requiredstart,tokenptr);
276                                                 pstrcpy(si->dependencies,tokenptr);
277                                         }
278
279                                         if (0==strwicmp(mybuffer, "Should-start:")) {
280                                                 pstrcpy(si->shouldstart,tokenptr);
281                                         }
282                                 }
283                         }
284                 }
285
286                 file_lines_free(qlines);
287                         return True;
288         }
289
290         return False;
291 }
292
293 /********************************************************************
294 ********************************************************************/
295
296 static BOOL get_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si) 
297 {
298
299         pstring keystring;
300         TDB_DATA  key_data;
301
302         if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0)) 
303                 return False;
304
305         /* TODO  - error handling -- what if the service isn't in the DB? */
306     
307         pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name);
308         key_data = tdb_fetch_bystring(stdb,keystring);
309         strncpy(si->servicetype,key_data.dptr,key_data.dsize);
310         si->servicetype[key_data.dsize] = 0;
311
312         /* crude check to see if the service exists... */
313         DEBUG(3,("Size of the TYPE field is %d\n",key_data.dsize));
314         if (key_data.dsize == 0) 
315                 return False;
316
317         pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name);
318         key_data = tdb_fetch_bystring(stdb,keystring);
319         strncpy(si->filename,key_data.dptr,key_data.dsize);
320         si->filename[key_data.dsize] = 0;
321
322         pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name);
323         key_data = tdb_fetch_bystring(stdb,keystring);
324         strncpy(si->provides,key_data.dptr,key_data.dsize);
325         si->provides[key_data.dsize] = 0;
326         strncpy(si->servicename,key_data.dptr,key_data.dsize);
327         si->servicename[key_data.dsize] = 0;
328
329             
330         pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name);
331         key_data = tdb_fetch_bystring(stdb,keystring);
332         strncpy(si->dependencies,key_data.dptr,key_data.dsize);
333         si->dependencies[key_data.dsize] = 0;
334
335         pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name);
336         key_data = tdb_fetch_bystring(stdb,keystring);
337         strncpy(si->shouldstart,key_data.dptr,key_data.dsize);
338         si->shouldstart[key_data.dsize] = 0;
339
340         pstr_sprintf(keystring,"SERVICE/%s/SHOULD_STOP", service_name);
341         key_data = tdb_fetch_bystring(stdb,keystring);
342         strncpy(si->shouldstop,key_data.dptr,key_data.dsize);
343         si->shouldstop[key_data.dsize] = 0;
344
345         pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name);
346         key_data = tdb_fetch_bystring(stdb,keystring);
347         strncpy(si->requiredstart,key_data.dptr,key_data.dsize);
348         si->requiredstart[key_data.dsize] = 0;
349
350         pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name);
351         key_data = tdb_fetch_bystring(stdb,keystring);
352         strncpy(si->requiredstop,key_data.dptr,key_data.dsize);
353         si->requiredstop[key_data.dsize] = 0;
354
355         pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name);
356         key_data = tdb_fetch_bystring(stdb,keystring);
357         strncpy(si->description,key_data.dptr,key_data.dsize);
358         si->description[key_data.dsize] = 0;
359
360         pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name);
361         key_data = tdb_fetch_bystring(stdb,keystring);
362         strncpy(si->shortdescription,key_data.dptr,key_data.dsize);
363         si->shortdescription[key_data.dsize] = 0;
364
365         return True;
366 }
367
368 /*********************************************************************
369 *********************************************************************/
370
371 static BOOL store_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si) 
372 {
373         pstring keystring;
374
375         /* Note -- when we write to the tdb, we "index" on the filename 
376            field, not the nice name. when a service is "opened", it is 
377            opened by the nice (SERVICENAME) name, not the file name. 
378            So there needs to be a mapping from nice name back to the file name. */
379
380         if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0)) 
381                 return False;
382
383
384         /* Store the nicename */
385
386         pstr_sprintf(keystring,"SERVICE_NICENAME/%s", si->servicename);
387         tdb_store_bystring(stdb,keystring,string_tdb_data(service_name),TDB_REPLACE);
388
389         pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name);
390         tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicetype),TDB_REPLACE);
391
392         pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name);
393         tdb_store_bystring(stdb,keystring,string_tdb_data(si->filename),TDB_REPLACE);
394
395         pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name);
396         tdb_store_bystring(stdb,keystring,string_tdb_data(si->provides),TDB_REPLACE);
397
398         pstr_sprintf(keystring,"SERVICE/%s/SERVICENAME", service_name);
399         tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicename),TDB_REPLACE);
400
401         pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name);
402         tdb_store_bystring(stdb,keystring,string_tdb_data(si->dependencies),TDB_REPLACE);
403
404         pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name);
405         tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstart),TDB_REPLACE);
406
407         pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTOP", service_name);
408         tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstop),TDB_REPLACE);
409
410         pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name);
411         tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstart),TDB_REPLACE);
412
413         pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name);
414         tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstop),TDB_REPLACE);
415
416         pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name);
417         tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE);
418
419         pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name);
420         tdb_lock_bystring(stdb, keystring, 0);
421         if (si->shortdescription && *si->shortdescription) 
422                 tdb_store_bystring(stdb,keystring,string_tdb_data(si->shortdescription),TDB_REPLACE);
423         else
424                 tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE);
425
426         return True;
427 }
428
429 /********************************************************************
430  allocate an array of external services and return them. Null return 
431  is okay, make sure &added is also zero! 
432 ********************************************************************/
433
434 static int num_external_services(void)
435 {
436         int num_services;
437         char **svc_list;
438         pstring keystring, external_services_string;
439         TDB_DATA key_data;
440
441
442         if (!service_tdb) {
443                 DEBUG(8,("enum_external_services: service database is not open!!!\n"));
444                 num_services = 0;
445         } else {
446                 pstrcpy(keystring,"EXTERNAL_SERVICES");
447                 tdb_lock_bystring(service_tdb, keystring, 0);
448                 key_data = tdb_fetch_bystring(service_tdb, keystring);
449
450                 if ((key_data.dptr != NULL) && (key_data.dsize != 0)) {
451                         strncpy(external_services_string,key_data.dptr,key_data.dsize);
452                         external_services_string[key_data.dsize] = 0;
453                         DEBUG(8,("enum_external_services: services list is %s, size is %d\n",external_services_string,key_data.dsize));
454                 }
455                 tdb_unlock_bystring(service_tdb, keystring);
456         } 
457         svc_list = str_list_make(external_services_string,NULL);
458  
459         num_services = str_list_count( (const char **)svc_list);
460
461         return num_services;
462 }
463
464
465
466 /********************************************************************
467   Gather information on the "external services". These are services 
468   listed in the smb.conf file, and found to exist through checks in 
469   this code. Note that added will be incremented on the basis of the 
470   number of services added.  svc_ptr should have enough memory allocated 
471   to accommodate all of the services that exist. 
472
473   Typically num_external_services is used to "size" the amount of
474   memory allocated, but does little/no work. 
475
476   enum_external_services() actually examines each of the specified 
477   external services, populates the memory structures, and returns.
478
479   ** note that 'added' may end up with less than the number of services 
480   found in _num_external_services, such as the case when a service is
481   called out, but the actual service doesn't exist or the file can't be 
482   read for the service information.
483 ********************************************************************/
484
485 static WERROR enum_external_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services,int *added) 
486 {
487         /* *svc_ptr must have pre-allocated memory */
488         int num_services = 0;
489         int i = 0;
490         ENUM_SERVICES_STATUS *services=NULL;
491         char **svc_list,**svcname;
492         pstring command, keystring, external_services_string;
493         int ret;
494         int fd = -1;
495         Service_info *si;
496         TDB_DATA key_data;
497
498         *added = num_services;
499
500         if (!service_tdb) {
501                 DEBUG(8,("enum_external_services: service database is not open!!!\n"));
502         } else {
503                 pstrcpy(keystring,"EXTERNAL_SERVICES");
504                 tdb_lock_bystring(service_tdb, keystring, 0);
505                 key_data = tdb_fetch_bystring(service_tdb, keystring);
506                 if ((key_data.dptr != NULL) && (key_data.dsize != 0)) {
507                         strncpy(external_services_string,key_data.dptr,key_data.dsize);
508                         external_services_string[key_data.dsize] = 0;
509                         DEBUG(8,("enum_external_services: services list is %s, size is %d\n",external_services_string,key_data.dsize));
510                 }
511                 tdb_unlock_bystring(service_tdb, keystring);
512         } 
513         svc_list = str_list_make(external_services_string,NULL);
514  
515         num_services = str_list_count( (const char **)svc_list);
516
517         if (0 == num_services) {
518                 DEBUG(8,("enum_external_services: there are no external services\n"));
519                 *added = num_services;
520                 return WERR_OK;
521         }
522         DEBUG(8,("enum_external_services: there are [%d] external services\n",num_services));
523         si=TALLOC_ARRAY( tcx, Service_info, 1 );
524         if (si == NULL) { 
525                 DEBUG(8,("enum_external_services: Failed to alloc si\n"));
526                 return WERR_NOMEM;
527         }
528
529 #if 0
530 /* *svc_ptr has the pointer to the array if there is one already. NULL if not. */
531         if ((existing_services>0) && svc_ptr && *svc_ptr) { /* reallocate vs. allocate */
532                 DEBUG(8,("enum_external_services: REALLOCing %x to %d services\n", *svc_ptr, existing_services+num_services));
533
534                 services=TALLOC_REALLOC_ARRAY(tcx,*svc_ptr,ENUM_SERVICES_STATUS,existing_services+num_services);
535                 DEBUG(8,("enum_external_services: REALLOCed to %x services\n", services));
536
537                 if (!services) return WERR_NOMEM;
538                         *svc_ptr = services;
539         } else {
540                 if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
541                         return WERR_NOMEM;
542         }
543 #endif
544
545         if (!svc_ptr || !(*svc_ptr)) 
546                 return WERR_NOMEM;
547         services = *svc_ptr;
548         if (existing_services > 0) {
549                 i+=existing_services;
550         }
551
552         svcname = svc_list;
553         DEBUG(8,("enum_external_services: enumerating %d external services starting at index %d\n", num_services,existing_services));
554
555         while (*svcname) {
556                 DEBUG(10,("enum_external_services: Reading information on service %s, index %d\n",*svcname,i));
557                 /* get_LSB_data(*svcname,si);  */
558                 if (!get_service_info(service_tdb,*svcname, si)) {
559                         DEBUG(1,("enum_external_services: CAN'T FIND INFO FOR SERVICE %s in the services DB\n",*svcname));
560                 }
561
562                 if ((si->filename == NULL) || (*si->filename == 0)) {
563                         init_unistr(&services[i].servicename, *svcname );
564                 } else {
565                         init_unistr( &services[i].servicename, si->filename );    
566                         /* init_unistr( &services[i].servicename, si->servicename ); */
567                 }
568
569                 if ((si->provides == NULL) || (*si->provides == 0)) {
570                         init_unistr(&services[i].displayname, *svcname );
571                 } else {
572                         init_unistr( &services[i].displayname, si->provides );
573                 }
574
575                 /* TODO - we could keep the following info in the DB, too... */
576
577                 DEBUG(8,("enum_external_services: Service name [%s] displayname [%s]\n",
578                 si->filename, si->provides)); 
579                 services[i].status.type               = SVCCTL_WIN32_OWN_PROC; 
580                 services[i].status.win32_exit_code    = 0x0;
581                 services[i].status.service_exit_code  = 0x0;
582                 services[i].status.check_point        = 0x0;
583                 services[i].status.wait_hint          = 0x0;
584
585                 /* TODO - do callout here to get the status */
586
587                 memset(command, 0, sizeof(command));
588                 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, *svcname, "status");
589
590                 DEBUG(10, ("enum_external_services: status command is [%s]\n", command));
591
592                 /* TODO  - wrap in privilege check */
593
594                 ret = smbrun(command, &fd);
595                 DEBUGADD(10, ("returned [%d]\n", ret));
596                 close(fd);
597                 if(ret != 0)
598                         DEBUG(10, ("enum_external_services: Command returned  [%d]\n", ret));
599                 services[i].status.state              = SVCCTL_STOPPED;
600                 if (ret == 0) {
601                         services[i].status.state              = SVCCTL_RUNNING;
602                         services[i].status.controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
603                 } else {
604                         services[i].status.state              = SVCCTL_STOPPED;
605                         services[i].status.controls_accepted  = 0;
606                 }
607                 svcname++; 
608                 i++;
609         } 
610
611         DEBUG(10,("enum_external_services: Read services %d\n",num_services));
612         *added = num_services;
613
614         return WERR_OK;
615 }
616
617 int num_internal_services(void)
618 {
619         int num_services;
620         char **svc_list;
621         pstring keystring, internal_services_string;
622         TDB_DATA key_data;
623
624         if (!service_tdb) {
625                 DEBUG(8,("enum_internal_services: service database is not open!!!\n"));
626                 num_services = 0;
627         } else {
628                 pstrcpy(keystring,"INTERNAL_SERVICES");
629                 tdb_lock_bystring(service_tdb, keystring, 0);
630                 key_data = tdb_fetch_bystring(service_tdb, keystring);
631
632                 if ((key_data.dptr != NULL) && (key_data.dsize != 0)) {
633                         strncpy(internal_services_string,key_data.dptr,key_data.dsize);
634                         internal_services_string[key_data.dsize] = 0;
635                         DEBUG(8,("enum_internal_services: services list is %s, size is %d\n",internal_services_string,key_data.dsize));
636                 }
637                 tdb_unlock_bystring(service_tdb, keystring);
638         } 
639         svc_list = str_list_make(internal_services_string,NULL);
640  
641         num_services = str_list_count( (const char **)svc_list);
642
643         return num_services;
644 }
645
646 /****************************************************************************
647  Create/Open the service control manager tdb. This code a clone of init_group_mapping.
648 ****************************************************************************/
649
650 BOOL init_svcctl_db(void)
651 {
652         const char *vstring = "INFO/version";
653         uint32 vers_id;
654         char **svc_list;
655         char **svcname;
656         pstring keystring;
657         pstring external_service_list;
658         pstring internal_service_list;
659         Service_info si;
660         const Internal_service_description *isd_ptr;
661         /* svc_list = str_list_make( "etc/init.d/skeleton  etc/init.d/syslog", NULL ); */
662         svc_list=(char **)lp_enable_svcctl(); 
663
664         if (service_tdb)
665                 return True;
666
667         pstrcpy(external_service_list,"");
668
669         service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
670         if (!service_tdb) {
671                 DEBUG(0,("Failed to open service db\n"));
672                 service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
673                 if (!service_tdb) return False;
674                 DEBUG(0,("Created new services db\n"));
675         }
676
677         if ((-1 == tdb_fetch_uint32(service_tdb, vstring,&vers_id)) || (vers_id != SERVICEDB_VERSION_V1)) {
678           /* wrong version of DB, or db was just created */
679           tdb_traverse(service_tdb, tdb_traverse_delete_fn, NULL);
680           tdb_store_uint32(service_tdb, vstring, SERVICEDB_VERSION_V1);
681         }
682         tdb_unlock_bystring(service_tdb, vstring);
683
684         DEBUG(0,("Initializing services db\n"));
685         
686         svcname = svc_list;
687
688         /* Get the EXTERNAL services as mentioned by line in smb.conf */
689
690         while (*svcname) {
691                 DEBUG(10,("Reading information on service %s\n",*svcname));
692                 if (get_LSB_data(*svcname,&si));{
693                         /* write the information to the TDB */
694                         store_service_info(service_tdb,*svcname,&si);
695                         /* definitely not efficient to do it this way. */
696                         pstrcat(external_service_list,"\"");
697                         pstrcat(external_service_list,*svcname);
698                         pstrcat(external_service_list,"\" ");
699                 }
700                 svcname++;
701         }
702         pstrcpy(keystring,"EXTERNAL_SERVICES");
703         tdb_lock_bystring(service_tdb, keystring, 0);
704         DEBUG(8,("Storing external service list [%s]\n",external_service_list));
705         tdb_store_bystring(service_tdb,keystring,string_tdb_data(external_service_list),TDB_REPLACE);
706         tdb_unlock_bystring(service_tdb,keystring);
707
708         /* Get the INTERNAL services */
709         
710         pstrcpy(internal_service_list,"");
711         isd_ptr = ISD; 
712
713         while (isd_ptr && (isd_ptr->filename)) {
714                 DEBUG(10,("Reading information on service %s\n",isd_ptr->filename));
715                 if (get_internal_service_data(isd_ptr,&si)){
716                         /* write the information to the TDB */
717                         store_service_info(service_tdb,(char *)isd_ptr->filename,&si);
718                         /* definitely not efficient to do it this way. */
719                         pstrcat(internal_service_list,"\"");
720                         pstrcat(internal_service_list,isd_ptr->filename);
721                         pstrcat(internal_service_list,"\" ");
722
723                 }
724                 isd_ptr++;
725         }
726         pstrcpy(keystring,"INTERNAL_SERVICES");
727         tdb_lock_bystring(service_tdb, keystring, 0);
728         DEBUG(8,("Storing internal service list [%s]\n",internal_service_list));
729         tdb_store_bystring(service_tdb,keystring,string_tdb_data(internal_service_list),TDB_REPLACE);
730         tdb_unlock_bystring(service_tdb,keystring);
731
732         return True;
733 }
734
735 /********************************************************************
736 ********************************************************************/
737
738 static NTSTATUS svcctl_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token, 
739                                      uint32 access_desired, uint32 *access_granted )
740 {
741         NTSTATUS result;
742         
743         /* maybe add privilege checks in here later */
744         
745         se_access_check( sec_desc, token, access_desired, access_granted, &result );
746         
747         return result;
748 }
749
750 /********************************************************************
751 ********************************************************************/
752
753 static SEC_DESC* construct_scm_sd( TALLOC_CTX *ctx )
754 {
755         SEC_ACE ace[2]; 
756         SEC_ACCESS mask;
757         size_t i = 0;
758         SEC_DESC *sd;
759         SEC_ACL *acl;
760         uint32 sd_size;
761
762         /* basic access for Everyone */
763         
764         init_sec_access(&mask, SC_MANAGER_READ_ACCESS );
765         init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
766         
767         /* Full Access 'BUILTIN\Administrators' */
768         
769         init_sec_access(&mask,SC_MANAGER_ALL_ACCESS );
770         init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
771         
772         
773         /* create the security descriptor */
774         
775         if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
776                 return NULL;
777
778         if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
779                 return NULL;
780
781         return sd;
782 }
783
784 /********************************************************************
785 ********************************************************************/
786
787 static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx )
788 {
789         SEC_ACE ace[4]; 
790         SEC_ACCESS mask;
791         size_t i = 0;
792         SEC_DESC *sd;
793         SEC_ACL *acl;
794         uint32 sd_size;
795
796         /* basic access for Everyone */
797         
798         init_sec_access(&mask, SERVICE_READ_ACCESS );
799         init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
800                 
801         init_sec_access(&mask,SERVICE_EXECUTE_ACCESS );
802         init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
803         
804         init_sec_access(&mask,SERVICE_ALL_ACCESS );
805         init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
806         init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
807         
808         /* create the security descriptor */
809         
810         if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
811                 return NULL;
812
813         if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
814                 return NULL;
815
816         return sd;
817 }
818
819 /******************************************************************
820  free() function for REGISTRY_KEY
821  *****************************************************************/
822  
823 static void free_service_handle_info(void *ptr)
824 {
825         SERVICE_INFO *info = (SERVICE_INFO*)ptr;
826         
827         SAFE_FREE(info->name);
828         SAFE_FREE(info);
829 }
830
831 /******************************************************************
832  Find a registry key handle and return a SERVICE_INFO
833  *****************************************************************/
834
835 static SERVICE_INFO *find_service_info_by_hnd(pipes_struct *p, POLICY_HND *hnd)
836 {
837         SERVICE_INFO *service_info = NULL;
838
839         if( !find_policy_by_hnd( p, hnd, (void **)&service_info) ) {
840                 DEBUG(2,("find_service_info_by_hnd: handle not found"));
841                 return NULL;
842         }
843
844         return service_info;
845 }
846
847 /******************************************************************
848  *****************************************************************/
849  
850 static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle, 
851                                           const char *service, uint32 access_granted )
852 {
853         SERVICE_INFO *info = NULL;
854         
855         if ( !(info = SMB_MALLOC_P( SERVICE_INFO )) )
856                 return WERR_NOMEM;
857
858         ZERO_STRUCTP( info );
859                 
860         /* the Service Manager has a NULL name */
861         
862         if ( !service ) {
863                 info->type = SVC_HANDLE_IS_SCM;
864         } else {
865                 info->type = SVC_HANDLE_IS_SERVICE;
866                 
867                 if ( !(info->name  = SMB_STRDUP( service )) ) {
868                         free_service_handle_info( info );
869                         WERR_NOMEM;
870                 }
871                 
872 #if 0
873                 /* lookup the SERVICE_CONTROL_OPS */
874
875                 for ( i=0; svcctl_ops[i].name; i++ ) {
876                         ;;
877                 }
878 #endif
879         }
880
881         info->access_granted = access_granted;  
882         
883         /* store the SERVICE_INFO and create an open handle */
884         
885         if ( !create_policy_hnd( p, handle, free_service_handle_info, info ) ) {
886                 free_service_handle_info( info );
887                 return WERR_ACCESS_DENIED;
888         }
889                 
890         return WERR_OK;
891 }
892
893 /********************************************************************
894 ********************************************************************/
895
896 WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVCCTL_R_OPEN_SCMANAGER *r_u)
897 {
898         SEC_DESC *sec_desc;
899         uint32 access_granted = 0;
900         NTSTATUS status;
901         
902         /* perform access checks */
903         
904         if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) )
905                 return WERR_NOMEM;
906                 
907         status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
908         if ( !NT_STATUS_IS_OK(status) )
909                 return ntstatus_to_werror( status );
910                 
911         return create_open_service_handle( p, &r_u->handle, NULL, access_granted );
912 }
913
914 /********************************************************************
915 ********************************************************************/
916
917 WERROR _svcctl_open_service(pipes_struct *p, SVCCTL_Q_OPEN_SERVICE *q_u, SVCCTL_R_OPEN_SERVICE *r_u)
918 {
919         SEC_DESC *sec_desc;
920         uint32 access_granted = 0;
921         NTSTATUS status;
922         pstring service;
923         SERVICE_INFO *scm_info;
924
925         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
926         
927         DEBUG(5, ("_svcctl_open_service: Attempting to open Service [%s], \n", service));
928
929         
930         /* based on my tests you can open a service if you have a valid scm handle */
931         
932         if ( !(scm_info = find_service_info_by_hnd( p, &q_u->handle )) )
933                 return WERR_BADFID;
934                         
935         /* perform access checks */
936         
937         if ( !(sec_desc = construct_service_sd( p->mem_ctx )) )
938                 return WERR_NOMEM;
939                 
940         status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
941         if ( !NT_STATUS_IS_OK(status) )
942                 return ntstatus_to_werror( status );
943                 
944 #if 0   /* FIXME!!! */
945         if ( ! get_service_info(service_tdb, service, info) ) {
946                 return WERR_NO_SUCH_SERVICE;
947 #endif
948         
949         return create_open_service_handle( p, &r_u->handle, service, access_granted );
950 }
951
952 /********************************************************************
953 ********************************************************************/
954
955 WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCTL_R_CLOSE_SERVICE *r_u)
956 {
957         return close_policy_hnd( p, &q_u->handle ) ? WERR_OK : WERR_BADFID;
958 }
959
960 /********************************************************************
961 ********************************************************************/
962
963 WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, SVCCTL_R_GET_DISPLAY_NAME *r_u)
964 {
965         fstring service;
966         fstring displayname;
967         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
968         
969         /* can only use an SCM handle here */
970         
971         if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
972                 return WERR_BADFID;
973                 
974         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
975
976         /* need a tdb lookup here or something */
977         
978         fstrcpy( displayname, "FIX ME!" );
979
980         init_svcctl_r_get_display_name( r_u, displayname );
981
982         return WERR_OK;
983 }
984
985 /********************************************************************
986 ********************************************************************/
987
988 WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_R_QUERY_STATUS *r_u)
989 {
990         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
991         
992         /* perform access checks */
993
994         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
995                 return WERR_BADFID;
996                 
997         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
998                 return WERR_ACCESS_DENIED;
999                 
1000         r_u->svc_status.type = 0x0020;
1001         r_u->svc_status.state = 0x0004;
1002         r_u->svc_status.controls_accepted = 0x0005;
1003
1004         return WERR_OK;
1005 }
1006
1007
1008 /*********************************************************************
1009  TODO - for internal services, do similar to external services, except 
1010  we have to call the right status routine...
1011 **********************************************************************/
1012
1013 static WERROR enum_internal_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services, int *added) 
1014 {
1015         int num_services = 2;
1016         int i = 0;
1017         ENUM_SERVICES_STATUS *services=NULL;
1018
1019         if (!svc_ptr || !(*svc_ptr)) 
1020                 return WERR_NOMEM;
1021
1022         services = *svc_ptr;
1023
1024 #if 0
1025         /* *svc_ptr has the pointer to the array if there is one already. NULL if not. */
1026         if ((existing_services>0) && svc_ptr && *svc_ptr) { /* reallocate vs. allocate */
1027                 DEBUG(8,("enum_internal_services: REALLOCing %d services\n", num_services));
1028                 services = TALLOC_REALLOC_ARRAY(tcx,*svc_ptr,ENUM_SERVICES_STATUS,existing_services+num_services);
1029                 if (!rsvcs) 
1030                         return WERR_NOMEM;
1031                 *svc_ptr = services;
1032         } else {
1033                 if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
1034                         return WERR_NOMEM;
1035         }
1036 #endif
1037
1038         if (existing_services > 0) {
1039                 i += existing_services;
1040         }
1041         DEBUG(8,("enum_internal_services: Creating %d services, starting index %d\n", num_services,existing_services));
1042                                 
1043         init_unistr( &services[i].servicename, "Spooler" );
1044         init_unistr( &services[i].displayname, "Print Spooler" );
1045         
1046         services[i].status.type               = 0x110;
1047         services[i].status.controls_accepted  = 0x0;
1048         services[i].status.win32_exit_code    = 0x0;
1049         services[i].status.service_exit_code  = 0x0;
1050         services[i].status.check_point        = 0x0;
1051         services[i].status.wait_hint          = 0x0;
1052         if ( !lp_disable_spoolss() ) 
1053                 services[i].status.state              = SVCCTL_RUNNING;
1054         else
1055                 services[i].status.state              = SVCCTL_STOPPED;
1056
1057         i++;            
1058         
1059         init_unistr( &services[i].servicename, "NETLOGON" );
1060         init_unistr( &services[i].displayname, "Net Logon" );
1061         
1062         services[i].status.type               = 0x20;   
1063         services[i].status.controls_accepted  = 0x0;
1064         services[i].status.win32_exit_code    = 0x0;
1065         services[i].status.service_exit_code  = 0x0;
1066         services[i].status.check_point        = 0x0;
1067         services[i].status.wait_hint          = 0x0;
1068         if ( lp_servicenumber("NETLOGON") != -1 ) 
1069                 services[i].status.state              = SVCCTL_RUNNING;
1070         else
1071                 services[i].status.state              = SVCCTL_STOPPED;
1072
1073         *added = num_services;
1074
1075         return WERR_OK;
1076 }
1077
1078 /********************************************************************
1079 ********************************************************************/
1080
1081 WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
1082 {
1083         ENUM_SERVICES_STATUS *services = NULL;
1084         uint32 num_int_services = 0;
1085         uint32 num_ext_services = 0;
1086         int i = 0;
1087         size_t buffer_size;
1088         WERROR result = WERR_OK;
1089         WERROR ext_result = WERR_OK;
1090         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
1091         
1092         /* perform access checks */
1093
1094         if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
1095                 return WERR_BADFID;
1096                 
1097         if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) )
1098                 return WERR_ACCESS_DENIED;
1099
1100         /* num_services = str_list_count( lp_enable_svcctl() ); */
1101
1102         /* here's where we'll read the db of external services */
1103         /* _svcctl_read_LSB_data(NULL,NULL); */
1104         /* init_svcctl_db(); */
1105         
1106         num_int_services = 0;
1107
1108         num_int_services = num_internal_services();
1109
1110         num_ext_services =  num_external_services();
1111
1112         if ( !(services = TALLOC_ARRAY(p->mem_ctx, ENUM_SERVICES_STATUS, num_int_services+num_ext_services )) )
1113           return WERR_NOMEM;
1114
1115         result = enum_internal_services(p->mem_ctx, &services, 0, &num_int_services);
1116
1117         if (W_ERROR_IS_OK(result)) {
1118                 DEBUG(8,("_svcctl_enum_services_status: Got %d internal services\n", num_int_services));
1119         } 
1120
1121         ext_result=enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services);
1122
1123         if (W_ERROR_IS_OK(ext_result)) {
1124                 DEBUG(8,("_svcctl_enum_services_status: Got %d external services\n", num_ext_services));
1125         } 
1126
1127         DEBUG(8,("_svcctl_enum_services_status: total of %d services\n", num_int_services+num_ext_services));
1128
1129         buffer_size = 0;
1130         for (i=0;i<num_int_services+num_ext_services;i++) {
1131           buffer_size += svcctl_sizeof_enum_services_status(&services[i]);
1132         }
1133
1134         /* */
1135         buffer_size += buffer_size % 4;
1136         DEBUG(8,("_svcctl_enum_services_status: buffer size passed %d, we need %d\n",
1137                  q_u->buffer_size, buffer_size));
1138
1139         if (buffer_size > q_u->buffer_size ) {
1140                 num_int_services = 0;
1141                 num_ext_services = 0;
1142                 result = WERR_MORE_DATA;
1143         }
1144
1145         rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
1146
1147         if ( W_ERROR_IS_OK(result) ) {
1148                 for ( i=0; i<num_int_services+num_ext_services; i++ )
1149                         svcctl_io_enum_services_status( "", &services[i], &r_u->buffer, 0 );
1150         }
1151
1152         r_u->needed      = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
1153         r_u->returned    = num_int_services+num_ext_services;
1154
1155         if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) )
1156                 return WERR_NOMEM;
1157
1158         *r_u->resume = 0x0;
1159
1160         return result;
1161 }
1162
1163 /********************************************************************
1164 ********************************************************************/
1165
1166 WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCTL_R_START_SERVICE *r_u)
1167 {
1168         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
1169         
1170         /* perform access checks */
1171
1172         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
1173                 return WERR_BADFID;
1174         
1175         if ( !(info->access_granted & SC_RIGHT_SVC_START) )
1176                 return WERR_ACCESS_DENIED;
1177                 
1178         return WERR_OK;
1179 }
1180
1181 /********************************************************************
1182 ********************************************************************/
1183
1184 WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, SVCCTL_R_CONTROL_SERVICE *r_u)
1185 {
1186         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
1187         
1188         /* perform access checks */
1189         /* we only support stop so don't get complicated */
1190
1191         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
1192                 return WERR_BADFID;     
1193         
1194         if ( q_u->control != SVCCTL_CONTROL_STOP )
1195                 return WERR_ACCESS_DENIED;
1196                 
1197         if ( !(info->access_granted & SC_RIGHT_SVC_STOP) )
1198                 return WERR_ACCESS_DENIED;
1199                 
1200 #if 0
1201         SERVICE_INFO *service_info;
1202         POLICY_HND   *handle;
1203         pstring      command;
1204         SERVICE_STATUS *service_status;
1205         int          ret,fd;
1206
1207         /* need to find the service name by the handle that is open */
1208         handle = &(q_u->handle);
1209
1210         service_info = find_service_info_by_hnd(p, handle);
1211
1212         if (!service_info) {
1213                 DEBUG(10, ("_svcctl_control_service : Can't find the service for the handle\n"));
1214                 return WERR_BADFID; 
1215         }
1216
1217         /* we return a SERVICE_STATUS structure if there's an error. */
1218         if ( !(service_status = TALLOC_ARRAY(p->mem_ctx, SERVICE_STATUS, 1 ))  )
1219                 return WERR_NOMEM;
1220
1221         DEBUG(10, ("_svcctl_control_service: Found service [%s], [%s]\n",
1222                 service_info->servicename, service_info->filename));
1223
1224         /* TODO  - call the service config function here... */
1225         memset(command, 0, sizeof(command));
1226         if (q_u->control == SVCCTL_CONTROL_STOP) {
1227                 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR,
1228                         service_info->filename, "stop");
1229         }
1230
1231         if (q_u->control == SVCCTL_CONTROL_PAUSE) {
1232                 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR,
1233                         service_info->filename, "stop");
1234         }
1235
1236         if (q_u->control == SVCCTL_CONTROL_CONTINUE) {
1237                 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR,
1238                         service_info->filename, "restart");
1239         }
1240
1241         DEBUG(10, ("_svcctl_control_service: status command is [%s]\n", command));
1242
1243         /* TODO  - wrap in privilege check */
1244
1245         ret = smbrun(command, &fd);
1246         DEBUGADD(10, ("returned [%d]\n", ret));
1247         close(fd);
1248
1249         if(ret != 0)
1250                 DEBUG(10, ("enum_external_services: Command returned  [%d]\n", ret));
1251
1252         /* SET all service_stats bits here...*/
1253         if (ret == 0) {
1254                 service_status->state              = SVCCTL_RUNNING;
1255                 service_status->controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
1256         } else {
1257                 service_status->state              = SVCCTL_STOPPED;
1258                 service_status->controls_accepted  = 0;
1259         }
1260
1261         DEBUG(10, ("_svcctl_query_service_config: Should call the commFound service [%s], [%s]\n",service_info->servicename,service_info->filename));
1262
1263 #endif
1264
1265         return WERR_OK;
1266 }
1267
1268 /********************************************************************
1269 ********************************************************************/
1270
1271 WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT_SERVICES *q_u, SVCCTL_R_ENUM_DEPENDENT_SERVICES *r_u )
1272 {
1273         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
1274         
1275         /* perform access checks */
1276
1277         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
1278                 return WERR_BADFID;     
1279         
1280         if ( !(info->access_granted & SC_RIGHT_SVC_ENUMERATE_DEPENDENTS) )
1281                 return WERR_ACCESS_DENIED;
1282                         
1283         /* we have to set the outgoing buffer size to the same as the 
1284            incoming buffer size (even in the case of failure */
1285
1286         rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
1287                                 
1288         r_u->needed      = q_u->buffer_size;
1289         
1290         /* no dependent services...basically a stub function */
1291         r_u->returned    = 0;
1292
1293         return WERR_OK;
1294 }
1295
1296 /********************************************************************
1297 ********************************************************************/
1298
1299 WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u )
1300 {
1301         SERVICE_STATUS_PROCESS ssp;
1302         POLICY_HND *handle;
1303         SERVICE_INFO *service_info;
1304         pstring     command;
1305         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
1306         
1307         /* perform access checks */
1308
1309         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
1310                 return WERR_BADFID;     
1311         
1312         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
1313                 return WERR_ACCESS_DENIED;
1314
1315         /* we have to set the outgoing buffer size to the same as the 
1316            incoming buffer size (even in the case of failure */
1317
1318         r_u->needed      = q_u->buffer_size;
1319
1320         /* need to find the service name by the handle that is open */
1321         handle = &(q_u->handle);
1322
1323
1324         /* get rid of the easy errors */
1325
1326         if (q_u->info_level != SVC_STATUS_PROCESS_INFO) {
1327                 DEBUG(10, ("_svcctl_query_service_status_ex :  Invalid information level specified\n"));
1328                 return WERR_UNKNOWN_LEVEL; 
1329         }
1330
1331         service_info = find_service_info_by_hnd(p, handle);
1332
1333         if (!service_info) {
1334                 DEBUG(10, ("_svcctl_query_service_status_ex : Can't find the service for the handle\n"));
1335                 return WERR_BADFID; 
1336         }
1337         
1338         if (r_u->needed < (sizeof(SERVICE_STATUS_PROCESS)+sizeof(uint32)+sizeof(uint32))) {
1339                 DEBUG(10, ("_svcctl_query_service_status_ex : buffer size of [%d] is too small.\n",r_u->needed));
1340                 return WERR_INSUFFICIENT_BUFFER;
1341         }
1342
1343         ZERO_STRUCT(ssp); 
1344             
1345 #if 0
1346         if (!strwicmp(service_info->servicetype,"EXTERNAL")) 
1347                 ssp.type = SVCCTL_WIN32_OWN_PROC;
1348         else 
1349                 ssp.type = SVCCTL_WIN32_SHARED_PROC;
1350 #endif
1351
1352         /* Get the status of the service.. */
1353
1354         memset(command, 0, sizeof(command));
1355
1356 #if 0
1357         slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, service_info->filename, "status");
1358
1359         DEBUG(10, ("_svcctl_query_service_status_ex: status command is [%s]\n", command));
1360
1361         /* TODO  - wrap in privilege check */
1362
1363         ret = smbrun(command, &fd);
1364         DEBUGADD(10, ("returned [%d]\n", ret));
1365         close(fd);
1366         if(ret != 0)
1367                 DEBUG(10, ("_svcctl_query_service_status_ex: Command returned  [%d]\n", ret));
1368
1369         /* SET all service_stats bits here... */
1370         if (ret == 0) {
1371                 ssp.state              = SVCCTL_RUNNING;
1372                 ssp.controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
1373         } else {
1374                 ssp.state              = SVCCTL_STOPPED;
1375                 ssp.controls_accepted  = 0;
1376         }
1377 #endif
1378
1379         return WERR_OK;
1380 }
1381
1382 /********************************************************************
1383 ********************************************************************/
1384
1385 WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
1386 {
1387         POLICY_HND *handle;
1388         SERVICE_INFO *service_info;
1389         uint32      needed_size;
1390         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
1391         
1392         /* perform access checks */
1393
1394         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
1395                 return WERR_BADFID;     
1396         
1397         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
1398                 return WERR_ACCESS_DENIED;
1399
1400         /* we have to set the outgoing buffer size to the same as the 
1401            incoming buffer size (even in the case of failure */
1402
1403         r_u->needed      = q_u->buffer_size;
1404
1405         /* need to find the service name by the handle that is open */
1406         handle = &(q_u->handle);
1407
1408         service_info = find_service_info_by_hnd(p, handle);
1409
1410 #if 0
1411         if (q_u->buffer_size < sizeof(Service_info)) {
1412                 /* have to report need more... */
1413                 /* TODO worst case -- should actualy calc what we need here. */
1414                 r_u->needed = sizeof(Service_info)+sizeof(pstring)*5; 
1415                 DEBUG(10, ("_svcctl_query_service_config: NOT ENOUGH BUFFER ALLOCATED FOR RETURN DATA -- provided %d wanted %d\n",
1416                 q_u->buffer_size,r_u->needed));
1417
1418                 return WERR_INSUFFICIENT_BUFFER;
1419         }
1420 #endif
1421         if (!service_info) {
1422                 DEBUG(10, ("_svcctl_query_service_config : Can't find the service for the handle\n"));
1423                 return WERR_BADFID; 
1424         }
1425
1426 #if 0
1427         if ( !(service_config = (SERVICE_CONFIG *)TALLOC_ZERO_P(p->mem_ctx, SERVICE_CONFIG)) )
1428                 return WERR_NOMEM;
1429 #endif
1430
1431         r_u->config.service_type       = SVCCTL_WIN32_OWN_PROC;
1432         r_u->config.start_type         = SVCCTL_DEMAND_START;
1433         r_u->config.error_control      = SVCCTL_SVC_ERROR_IGNORE;
1434         r_u->config.tag_id = 0x00000000;
1435
1436         /* Init the strings */
1437
1438         r_u->config.executablepath = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
1439         r_u->config.loadordergroup = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
1440         r_u->config.dependencies = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
1441         r_u->config.startname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
1442         r_u->config.displayname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
1443
1444 #if 0
1445         pstrcpy(fullpathinfo,dyn_LIBDIR);
1446         pstrcat(fullpathinfo,SVCCTL_SCRIPT_DIR);
1447         pstrcat(fullpathinfo,service_info->filename);
1448         /* Get and calculate the size of the fields. Note that we're still building the fields in the "too-small buffer case"
1449            even though we throw it away. */
1450         
1451         DEBUG(10, ("_svcctl_query_service_config: fullpath info [%s]\n",fullpathinfo));
1452         init_unistr2(r_u->config.executablepath,fullpathinfo,UNI_STR_TERMINATE);
1453         init_unistr2(r_u->config.loadordergroup,"",UNI_STR_TERMINATE);
1454         init_unistr2(r_u->config.dependencies,service_info->dependencies,UNI_STR_TERMINATE);
1455
1456         /* TODO - if someone really cares, perhaps "LocalSystem" should be changed to something else here... */
1457
1458         init_unistr2(r_u->config.startname,"LocalSystem",UNI_STR_TERMINATE);
1459         init_unistr2(r_u->config.displayname,service_info->servicename,UNI_STR_TERMINATE);
1460 #endif
1461
1462         needed_size = 0x04 + sizeof(SERVICE_CONFIG)+ 2*(
1463                       r_u->config.executablepath->uni_str_len +
1464                       r_u->config.loadordergroup->uni_str_len + 
1465                       r_u->config.dependencies->uni_str_len + 
1466                       r_u->config.startname->uni_str_len + 
1467                       r_u->config.displayname->uni_str_len);
1468         
1469         DEBUG(10, ("_svcctl_query_service_config: ****** need to have a buffer of [%d], [%d] for struct \n",needed_size,
1470                    sizeof(SERVICE_CONFIG)));
1471         DEBUG(10, ("\tsize of executable path : %d\n",r_u->config.executablepath->uni_str_len));
1472         DEBUG(10, ("\tsize of loadordergroup  : %d\n", r_u->config.loadordergroup->uni_str_len)); 
1473         DEBUG(10, ("\tsize of dependencies    : %d\n", r_u->config.dependencies->uni_str_len)); 
1474         DEBUG(10, ("\tsize of startname       : %d\n", r_u->config.startname->uni_str_len));
1475         DEBUG(10, ("\tsize of displayname     : %d\n", r_u->config.displayname->uni_str_len));
1476
1477         if (q_u->buffer_size < needed_size) {
1478                 /* have to report need more...*/
1479                 r_u->needed = needed_size;
1480                 DEBUG(10, ("_svcctl_query_service_config: ****** zeroing strings for return\n"));
1481                 memset(&r_u->config,0,sizeof(SERVICE_CONFIG));
1482                 DEBUG(10, ("_svcctl_query_service_config: Not enouh buffer provided for return -- provided %d wanted %d\n",
1483                         q_u->buffer_size,needed_size));
1484                 return WERR_INSUFFICIENT_BUFFER;
1485         }
1486
1487         return WERR_OK;
1488 }
1489
1490 /********************************************************************
1491 ********************************************************************/
1492
1493 WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u )
1494 {
1495         POLICY_HND *handle;
1496         SERVICE_INFO *service_info;
1497         uint32   level;
1498         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
1499         
1500         /* perform access checks */
1501
1502         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
1503                 return WERR_BADFID;     
1504         
1505         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
1506                 return WERR_ACCESS_DENIED;
1507  
1508         /* we have to set the outgoing buffer size to the same as the 
1509            incoming buffer size (even in the case of failure */
1510
1511         r_u->needed      = q_u->buffer_size;
1512         r_u->description = NULL;               
1513         r_u->returned = q_u->buffer_size;
1514         r_u->offset = 4;                       
1515
1516         handle = &(q_u->handle);
1517
1518         service_info = find_service_info_by_hnd(p, handle);
1519
1520         if (!service_info) {
1521                 DEBUG(10, ("_svcctl_query_service_config2 : Can't find the service for the handle\n"));
1522                 return WERR_BADFID; 
1523         }
1524         
1525         /* 
1526            TODO - perhaps move the RPC_DATA_BLOB into the R_QUERY_SERVICE_CONFIG structure, and to the processing in here, vs
1527            in the *r_query_config2 marshalling routine...
1528         */
1529
1530         level = q_u->info_level;
1531
1532 #if 0
1533         if (SERVICE_CONFIG_DESCRIPTION == level) {
1534                 if (service_info && service_info->shortdescription) {
1535                         /* length of the string, plus the terminator... */
1536                         string_buffer_size = strlen(service_info->shortdescription)+1; 
1537                         DEBUG(10, ("_svcctl_query_service_config: copying the description [%s] length [%d]\n",
1538                         service_info->shortdescription,string_buffer_size));
1539             
1540                         if (q_u->buffer_size >= ((string_buffer_size)*2+4)) {
1541                                 r_u->description = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
1542                                 if (!r_u->description) return WERR_NOMEM;
1543                                         init_unistr2(r_u->description,service_info->shortdescription,UNI_STR_TERMINATE);
1544                         }
1545                 }
1546                 else { 
1547                         string_buffer_size = 0;
1548                 }
1549                 DEBUG(10, ("_svcctl_query_service_config2: buffer needed is [%x], return buffer size is [%x]\n",
1550                         string_buffer_size,q_u->buffer_size));
1551                 if (((string_buffer_size)*2+4) > q_u->buffer_size) {
1552                         r_u->needed = (string_buffer_size+1)*2+4;
1553                         DEBUG(10, ("_svcctl_query_service_config2: INSUFFICIENT BUFFER\n"));
1554                         return WERR_INSUFFICIENT_BUFFER;
1555                 }
1556                 DEBUG(10, ("_svcctl_query_service_config2: returning ok, needed is [%x], buffer size is [%x]\n",
1557                 r_u->needed,q_u->buffer_size));
1558
1559                 return WERR_OK;    
1560         } 
1561 #endif
1562
1563         return WERR_ACCESS_DENIED;
1564 }