r7576: implement access checks for open_scm and open_service
[metze/samba/wip.git] / source3 / 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 TALLOC_CTX    *svcdb=NULL;
46 static TDB_CONTEXT *service_tdb; /* used for services tdb file */
47
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.
53
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/ */
60
61
62
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, 
66    etc. */
67
68 typedef struct Internal_service_struct
69 {
70         const char *filename;           /* internal name "index" */
71         const char *displayname;
72         const char *description;
73         const uint32 statustype;
74         void *status_fn; 
75         void *control_fn;
76 } Internal_service_description;
77
78
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}
83 };
84
85
86 /********************************************************************
87  TODOs
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 ********************************************************************/
93
94 /*********************************************************************
95  given a service nice name, find the underlying service name
96 *********************************************************************/
97
98 BOOL  _svcctl_service_nicename_to_servicename(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, ("_svcctl_service_nicename_to_servicename: 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, ("_svcctl_service_nicename_to_servicename: [%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, ("_svcctl_service_nicename_to_servicename: Found service name [%s], name is  [%s]\n",
121                 service_nicename,servicename));
122
123         return True;
124 }
125
126 /*********************************************************************
127 *********************************************************************/
128
129 static BOOL  write_si_to_service_tdb(TDB_CONTEXT *stdb,char *service_name, Service_info *si) 
130 {
131         pstring keystring;
132
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. */
137
138         if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0)) 
139                 return False;
140
141
142         /* Store the nicename */
143
144         pstr_sprintf(keystring,"SERVICE_NICENAME/%s", si->servicename);
145         tdb_store_bystring(stdb,keystring,string_tdb_data(service_name),TDB_REPLACE);
146
147         pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name);
148         tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicetype),TDB_REPLACE);
149
150         pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name);
151         tdb_store_bystring(stdb,keystring,string_tdb_data(si->filename),TDB_REPLACE);
152
153         pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name);
154         tdb_store_bystring(stdb,keystring,string_tdb_data(si->provides),TDB_REPLACE);
155
156         pstr_sprintf(keystring,"SERVICE/%s/SERVICENAME", service_name);
157         tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicename),TDB_REPLACE);
158
159         pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name);
160         tdb_store_bystring(stdb,keystring,string_tdb_data(si->dependencies),TDB_REPLACE);
161
162         pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name);
163         tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstart),TDB_REPLACE);
164
165         pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTOP", service_name);
166         tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstop),TDB_REPLACE);
167
168         pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name);
169         tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstart),TDB_REPLACE);
170
171         pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name);
172         tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstop),TDB_REPLACE);
173
174         pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name);
175         tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE);
176
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);
181         else
182                 tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE);
183
184         return True;
185 }
186
187
188 /*******************************************************************************
189  Get the INTERNAL services information for the given service name. 
190 *******************************************************************************/
191
192 static BOOL _svcctl_get_internal_service_data(const Internal_service_description *isd, Service_info *si)
193 {
194         ZERO_STRUCTP( si );
195 #if 0
196         
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);
203 #endif
204         
205         return True;
206 }
207
208
209 /*******************************************************************************
210  Get the services information  by reading and parsing the shell scripts. These 
211  are symbolically linked into the  SVCCTL_SCRIPT_DIR  directory.
212
213  Get the names of the services/scripts to read from the smb.conf file.
214 *******************************************************************************/
215
216 static BOOL _svcctl_get_LSB_data(char *fname,Service_info *si )
217 {
218         pstring initdfile;
219         char mybuffer[256];
220         const char *tokenptr;
221         char **qlines;
222         int fd = -1;
223         int nlines, *numlines,i,in_section,in_description;
224         
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,"");
236
237         numlines = &nlines;
238         in_section = 0;
239         in_description = 0;
240
241    
242         if( !fname || !*fname ) {
243                 DEBUG(0, ("Must define an \"LSB-style init file\" to read.\n"));
244                 return False;
245         }
246         pstrcpy(initdfile,dyn_LIBDIR);
247         pstrcat(initdfile,SVCCTL_SCRIPT_DIR);
248         pstrcat(initdfile,fname);
249
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 */
253
254         DEBUG(10, ("Opening [%s]\n", initdfile));
255         fd = -1;
256         fd = open(initdfile,O_RDONLY);
257         *numlines = 0;
258
259         if (fd == -1) {
260                 DEBUG(10, ("Couldn't open [%s]\n", initdfile));
261                 return False;
262         }
263
264         qlines = fd_lines_load(fd, numlines);
265         DEBUGADD(10, ("Lines returned = [%d]\n", *numlines));
266         close(fd);
267     
268
269         if (*numlines) {
270         
271                 for(i = 0; i < *numlines; i++) {
272
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));
277                                 in_section = 1;
278
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));
282                                 in_description = 0;
283                                 in_section = 0;
284                                 break;
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);
293                                                 continue;
294                                         }
295                                         in_description = 0;
296                                         DEBUGADD(10, ("Not a description!\n"));
297                                 }
298                                 if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) {
299                                         DEBUGADD(10, ("Invalid line [%d]\n", i));
300                                         break; /* bad line? */
301                                 }
302                                 if (0 != strncmp(mybuffer,"#",1)) {
303                                         DEBUGADD(10, ("Invalid line [%d], is %s\n", i,mybuffer));
304                                         break;
305                                 }
306                                 if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) {
307                                         DEBUGADD(10, ("Invalid token on line [%d]\n", i));
308                                         break; /* bad line? */
309                                 }             
310                                 DEBUGADD(10, ("Keyword is  [%s]\n", mybuffer));
311                                 if (0==strwicmp(mybuffer,"Description:")) {
312                                         while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { 
313                                                 tokenptr++; 
314                                         }
315                                         pstrcpy(si->description,tokenptr);
316                                         DEBUGADD(10, ("FOUND DESCRIPTION! Data is [%s]\n", tokenptr));
317                                         in_description = 1;
318                                 } else {
319                                         while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { 
320                                                 tokenptr++; 
321                                         }
322                                         DEBUGADD(10, ("Data is [%s]\n", tokenptr));
323                                         in_description = 0;
324
325                                         /* save certain keywords, don't save others */
326                                         if (0==strwicmp(mybuffer, "Provides:")) {
327                                                 pstrcpy(si->provides,tokenptr);
328                                                 pstrcpy(si->servicename,tokenptr);
329                                         }
330
331                                         if (0==strwicmp(mybuffer, "Short-Description:")) {
332                                                 pstrcpy(si->shortdescription,tokenptr);
333                                         }
334
335                                         if (0==strwicmp(mybuffer, "Required-start:")) {
336                                                 pstrcpy(si->requiredstart,tokenptr);
337                                                 pstrcpy(si->dependencies,tokenptr);
338                                         }
339
340                                         if (0==strwicmp(mybuffer, "Should-start:")) {
341                                                 pstrcpy(si->shouldstart,tokenptr);
342                                         }
343                                 }
344                         }
345                 }
346
347                 file_lines_free(qlines);
348                         return True;
349         }
350
351         return False;
352 }
353
354 /****************************************************************************
355  Create/Open the service control manager tdb. This code a clone of init_group_mapping.
356 ****************************************************************************/
357
358 BOOL init_svcctl_db(void)
359 {
360         const char *vstring = "INFO/version";
361         uint32 vers_id;
362         char **svc_list;
363         char **svcname;
364         pstring keystring;
365         pstring external_service_list;
366         pstring internal_service_list;
367         Service_info si;
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(); 
371
372         if (service_tdb)
373                 return True;
374
375         pstrcpy(external_service_list,"");
376
377         service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
378         if (!service_tdb) {
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"));
383         }
384
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);
389         }
390         tdb_unlock_bystring(service_tdb, vstring);
391
392         DEBUG(0,("Initializing services db\n"));
393         
394         svcname = svc_list;
395
396         /* Get the EXTERNAL services as mentioned by line in smb.conf */
397
398         while (*svcname) {
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,"\" ");
407                 }
408                 svcname++;
409         }
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);
415
416         /* Get the INTERNAL services */
417         
418         pstrcpy(internal_service_list,"");
419         isd_ptr = ISD; 
420
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,"\" ");
430
431                 }
432                 isd_ptr++;
433         }
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);
439
440         return True;
441 }
442
443 /********************************************************************
444 ********************************************************************/
445
446 static NTSTATUS svcctl_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token, 
447                                      uint32 access_desired, uint32 *access_granted )
448 {
449         NTSTATUS result;
450         
451         /* maybe add privilege checks in here later */
452         
453         se_access_check( sec_desc, token, access_desired, access_granted, &result );
454         
455         return result;
456 }
457
458 /********************************************************************
459 ********************************************************************/
460
461 static SEC_DESC* construct_scm_sd( TALLOC_CTX *ctx )
462 {
463         SEC_ACE ace[2]; 
464         SEC_ACCESS mask;
465         size_t i = 0;
466         SEC_DESC *sd;
467         SEC_ACL *acl;
468         uint32 sd_size;
469
470         /* basic access for Everyone */
471         
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);
474         
475         /* Full Access 'BUILTIN\Administrators' */
476         
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);
479         
480         
481         /* create the security descriptor */
482         
483         if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
484                 return NULL;
485
486         if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
487                 return NULL;
488
489         return sd;
490 }
491
492 /********************************************************************
493 ********************************************************************/
494
495 static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx )
496 {
497         SEC_ACE ace[4]; 
498         SEC_ACCESS mask;
499         size_t i = 0;
500         SEC_DESC *sd;
501         SEC_ACL *acl;
502         uint32 sd_size;
503
504         /* basic access for Everyone */
505         
506         init_sec_access(&mask, SERVICE_READ_ACCESS );
507         init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
508                 
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);
511         
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);
515         
516         /* create the security descriptor */
517         
518         if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
519                 return NULL;
520
521         if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
522                 return NULL;
523
524         return sd;
525 }
526
527
528 /********************************************************************
529 ********************************************************************/
530
531 static BOOL read_service_tdb_to_si(TDB_CONTEXT *stdb,char *service_name, Service_info *si) 
532 {
533
534         pstring keystring;
535         TDB_DATA  key_data;
536
537         if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0)) 
538                 return False;
539
540         /* TODO  - error handling -- what if the service isn't in the DB? */
541     
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;
546
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) 
550                 return False;
551
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;
556
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;
563
564             
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;
569
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;
574
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;
579
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;
584
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;
589
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;
594
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;
599
600         return True;
601 }
602
603 /******************************************************************
604  free() function for REGISTRY_KEY
605  *****************************************************************/
606  
607 static void free_service_handle_info(void *ptr)
608 {
609         SERVICE_INFO *info = (SERVICE_INFO*)ptr;
610         
611         SAFE_FREE(info->name);
612         SAFE_FREE(info);
613 }
614
615 /******************************************************************
616  Find a registry key handle and return a SERVICE_INFO
617  *****************************************************************/
618
619 static SERVICE_INFO *find_service_info_by_hnd(pipes_struct *p, POLICY_HND *hnd)
620 {
621         SERVICE_INFO *service_info = NULL;
622
623         if( !find_policy_by_hnd( p, hnd, (void **)&service_info) ) {
624                 DEBUG(2,("find_service_info_by_hnd: handle not found"));
625                 return NULL;
626         }
627
628         return service_info;
629 }
630
631 /******************************************************************
632  *****************************************************************/
633  
634 static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle, 
635                                           const char *service, uint32 access_granted )
636 {
637         SERVICE_INFO *info = NULL;
638         
639         if ( !(info = SMB_MALLOC_P( SERVICE_INFO )) )
640                 return WERR_NOMEM;
641
642         ZERO_STRUCTP( info );
643                 
644         /* the Service Manager has a NULL name */
645         
646         if ( !service ) {
647                 info->type = SVC_HANDLE_IS_SCM;
648         } else {
649                 info->type = SVC_HANDLE_IS_SERVICE;
650                 
651                 if ( !(info->name  = SMB_STRDUP( service )) ) {
652                         free_service_handle_info( info );
653                         WERR_NOMEM;
654                 }
655                 
656 #if 0
657                 /* lookup the SERVICE_CONTROL_OPS */
658
659                 for ( i=0; svcctl_ops[i].name; i++ ) {
660                         ;;
661                 }
662 #endif
663         }
664
665         info->access_granted = access_granted;  
666         
667         /* store the SERVICE_INFO and create an open handle */
668         
669         if ( !create_policy_hnd( p, handle, free_service_handle_info, info ) ) {
670                 free_service_handle_info( info );
671                 return WERR_ACCESS_DENIED;
672         }
673                 
674         return WERR_OK;
675 }
676
677 /********************************************************************
678 ********************************************************************/
679
680 WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVCCTL_R_OPEN_SCMANAGER *r_u)
681 {
682         SEC_DESC *sec_desc;
683         uint32 access_granted = 0;
684         NTSTATUS status;
685         
686         /* perform access checks */
687         
688         if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) )
689                 return WERR_NOMEM;
690                 
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 );
694                 
695         return create_open_service_handle( p, &r_u->handle, NULL, access_granted );
696 }
697
698 /********************************************************************
699 ********************************************************************/
700
701 WERROR _svcctl_open_service(pipes_struct *p, SVCCTL_Q_OPEN_SERVICE *q_u, SVCCTL_R_OPEN_SERVICE *r_u)
702 {
703         SEC_DESC *sec_desc;
704         uint32 access_granted = 0;
705         NTSTATUS status;
706         pstring service;
707
708         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
709         
710         DEBUG(5, ("_svcctl_open_service: Attempting to open Service [%s], \n", service));
711         
712         if ( !service_tdb ) {
713                 DEBUG(1, ("_svcctl_open_service: service database is not open\n!"));
714                 return WERR_ACCESS_DENIED;
715         }
716         
717         /* perform access checks */
718         
719         if ( !(sec_desc = construct_service_sd( p->mem_ctx )) )
720                 return WERR_NOMEM;
721                 
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 );
725                 
726 #if 0   /* FIXME!!! */
727         if ( ! read_service_tdb_to_si(service_tdb,service, info) ) {
728                 return WERR_NO_SUCH_SERVICE;
729 #endif
730         
731         return create_open_service_handle( p, &r_u->handle, service, access_granted );
732 }
733
734 /********************************************************************
735 ********************************************************************/
736
737 WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCTL_R_CLOSE_SERVICE *r_u)
738 {
739         return close_policy_hnd( p, &q_u->handle ) ? WERR_OK : WERR_BADFID;
740 }
741
742 /********************************************************************
743 ********************************************************************/
744
745 WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, SVCCTL_R_GET_DISPLAY_NAME *r_u)
746 {
747         fstring service;
748         fstring displayname;
749
750         SERVICE_INFO *service_info;
751         POLICY_HND *handle;
752
753         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
754
755         handle = &(q_u->handle);
756
757         service_info = find_service_info_by_hnd(p, handle);
758
759         if (!service_info) {
760                 DEBUG(10, ("_svcctl_get_display_name : Can't find the service for the handle\n"));
761                 return WERR_ACCESS_DENIED;
762         }
763
764         DEBUG(10,("_svcctl_get_display_name: Found service [%s]\n", service_info->name ));
765
766         fstrcpy( displayname, "FIX ME!" );
767
768         init_svcctl_r_get_display_name( r_u, displayname );
769
770         return WERR_OK;
771 }
772
773 /********************************************************************
774 ********************************************************************/
775
776 WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_R_QUERY_STATUS *r_u)
777 {
778         r_u->svc_status.type = 0x0020;
779         r_u->svc_status.state = 0x0004;
780         r_u->svc_status.controls_accepted = 0x0005;
781
782         return WERR_OK;
783 }
784
785 /* allocate an array of external services and return them. Null return is okay, make sure &added is also zero! */
786
787 int _svcctl_num_external_services(void)
788 {
789         int num_services;
790         char **svc_list;
791         pstring keystring, external_services_string;
792         TDB_DATA key_data;
793
794
795         if (!service_tdb) {
796                 DEBUG(8,("enum_external_services: service database is not open!!!\n"));
797                 num_services = 0;
798         } else {
799                 pstrcpy(keystring,"EXTERNAL_SERVICES");
800                 tdb_lock_bystring(service_tdb, keystring, 0);
801                 key_data = tdb_fetch_bystring(service_tdb, keystring);
802
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));
807                 }
808                 tdb_unlock_bystring(service_tdb, keystring);
809         } 
810         svc_list = str_list_make(external_services_string,NULL);
811  
812         num_services = str_list_count( (const char **)svc_list);
813
814         return num_services;
815 }
816
817
818
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. 
825
826   Typically _svcctl_num_external_services is used to "size" the amount of
827   memory allocated, but does little/no work. 
828
829   enum_external_services() actually examines each of the specified 
830   external services, populates the memory structures, and returns.
831
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 ********************************************************************/
837
838 WERROR enum_external_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services,int *added) 
839 {
840         /* *svc_ptr must have pre-allocated memory */
841         int num_services = 0;
842         int i = 0;
843         ENUM_SERVICES_STATUS *services=NULL;
844         char **svc_list,**svcname;
845         pstring command, keystring, external_services_string;
846         int ret;
847         int fd = -1;
848         Service_info *si;
849         TDB_DATA key_data;
850
851         *added = num_services;
852
853         if (!service_tdb) {
854                 DEBUG(8,("enum_external_services: service database is not open!!!\n"));
855         } else {
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));
863                 }
864                 tdb_unlock_bystring(service_tdb, keystring);
865         } 
866         svc_list = str_list_make(external_services_string,NULL);
867  
868         num_services = str_list_count( (const char **)svc_list);
869
870         if (0 == num_services) {
871                 DEBUG(8,("enum_external_services: there are no external services\n"));
872                 *added = num_services;
873                 return WERR_OK;
874         }
875         DEBUG(8,("enum_external_services: there are [%d] external services\n",num_services));
876         si=TALLOC_ARRAY( tcx, Service_info, 1 );
877         if (si == NULL) { 
878                 DEBUG(8,("enum_external_services: Failed to alloc si\n"));
879                 return WERR_NOMEM;
880         }
881
882 #if 0
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));
886
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));
889
890                 if (!services) return WERR_NOMEM;
891                         *svc_ptr = services;
892         } else {
893                 if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
894                         return WERR_NOMEM;
895         }
896 #endif
897
898         if (!svc_ptr || !(*svc_ptr)) 
899                 return WERR_NOMEM;
900         services = *svc_ptr;
901         if (existing_services > 0) {
902                 i+=existing_services;
903         }
904
905         svcname = svc_list;
906         DEBUG(8,("enum_external_services: enumerating %d external services starting at index %d\n", num_services,existing_services));
907
908         while (*svcname) {
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));
913                 }
914
915                 if ((si->filename == NULL) || (*si->filename == 0)) {
916                         init_unistr(&services[i].servicename, *svcname );
917                 } else {
918                         init_unistr( &services[i].servicename, si->filename );    
919                         /* init_unistr( &services[i].servicename, si->servicename ); */
920                 }
921
922                 if ((si->provides == NULL) || (*si->provides == 0)) {
923                         init_unistr(&services[i].displayname, *svcname );
924                 } else {
925                         init_unistr( &services[i].displayname, si->provides );
926                 }
927
928                 /* TODO - we could keep the following info in the DB, too... */
929
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;
937
938                 /* TODO - do callout here to get the status */
939
940                 memset(command, 0, sizeof(command));
941                 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, *svcname, "status");
942
943                 DEBUG(10, ("enum_external_services: status command is [%s]\n", command));
944
945                 /* TODO  - wrap in privilege check */
946
947                 ret = smbrun(command, &fd);
948                 DEBUGADD(10, ("returned [%d]\n", ret));
949                 close(fd);
950                 if(ret != 0)
951                         DEBUG(10, ("enum_external_services: Command returned  [%d]\n", ret));
952                 services[i].status.state              = SVCCTL_STOPPED;
953                 if (ret == 0) {
954                         services[i].status.state              = SVCCTL_RUNNING;
955                         services[i].status.controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
956                 } else {
957                         services[i].status.state              = SVCCTL_STOPPED;
958                         services[i].status.controls_accepted  = 0;
959                 }
960                 svcname++; 
961                 i++;
962         } 
963
964         DEBUG(10,("enum_external_services: Read services %d\n",num_services));
965         *added = num_services;
966
967         return WERR_OK;
968 }
969
970 int _svcctl_num_internal_services(void)
971 {
972         int num_services;
973         char **svc_list;
974         pstring keystring, internal_services_string;
975         TDB_DATA key_data;
976
977         if (!service_tdb) {
978                 DEBUG(8,("_svcctl_enum_internal_services: service database is not open!!!\n"));
979                 num_services = 0;
980         } else {
981                 pstrcpy(keystring,"INTERNAL_SERVICES");
982                 tdb_lock_bystring(service_tdb, keystring, 0);
983                 key_data = tdb_fetch_bystring(service_tdb, keystring);
984
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));
989                 }
990                 tdb_unlock_bystring(service_tdb, keystring);
991         } 
992         svc_list = str_list_make(internal_services_string,NULL);
993  
994         num_services = str_list_count( (const char **)svc_list);
995
996         return num_services;
997 }
998
999 #if 0
1000
1001 int _svcctl_num_internal_services(void)
1002 {
1003         return 2;
1004 }
1005 #endif
1006
1007 /* TODO - for internal services, do similar to external services, except we have to call the right status routine... */
1008
1009 WERROR _svcctl_enum_internal_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services, int *added) 
1010 {
1011         int num_services = 2;
1012         int i = 0;
1013         ENUM_SERVICES_STATUS *services=NULL;
1014
1015         if (!svc_ptr || !(*svc_ptr)) 
1016                 return WERR_NOMEM;
1017
1018         services = *svc_ptr;
1019
1020 #if 0
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);
1025                 if (!rsvcs) 
1026                         return WERR_NOMEM;
1027                 *svc_ptr = services;
1028         } else {
1029                 if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
1030                         return WERR_NOMEM;
1031         }
1032 #endif
1033
1034         if (existing_services > 0) {
1035                 i += existing_services;
1036         }
1037         DEBUG(8,("_svcctl_enum_internal_services: Creating %d services, starting index %d\n", num_services,existing_services));
1038                                 
1039         init_unistr( &services[i].servicename, "Spooler" );
1040         init_unistr( &services[i].displayname, "Print Spooler" );
1041         
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;
1050         else
1051                 services[i].status.state              = SVCCTL_STOPPED;
1052
1053         i++;            
1054         
1055         init_unistr( &services[i].servicename, "NETLOGON" );
1056         init_unistr( &services[i].displayname, "Net Logon" );
1057         
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;
1066         else
1067                 services[i].status.state              = SVCCTL_STOPPED;
1068
1069         *added = num_services;
1070
1071         return WERR_OK;
1072 }
1073
1074 WERROR _init_svcdb(void) 
1075 {
1076         if (svcdb) {
1077                 talloc_destroy(svcdb);
1078         }
1079         svcdb = talloc_init("services DB");
1080
1081         return WERR_OK;
1082 }
1083
1084 /********************************************************************
1085 ********************************************************************/
1086
1087 WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
1088 {
1089         ENUM_SERVICES_STATUS *services = NULL;
1090  
1091         uint32 num_int_services = 0;
1092         uint32 num_ext_services = 0;
1093         int i = 0;
1094         size_t buffer_size;
1095         WERROR result = WERR_OK;
1096         WERROR ext_result = WERR_OK;            
1097
1098         /* num_services = str_list_count( lp_enable_svcctl() ); */
1099
1100         /* here's where we'll read the db of external services */
1101         /* _svcctl_read_LSB_data(NULL,NULL); */
1102         /* init_svcctl_db(); */
1103         
1104         num_int_services = 0;
1105
1106         num_int_services = _svcctl_num_internal_services();
1107
1108         num_ext_services =  _svcctl_num_external_services();
1109
1110         if ( !(services = TALLOC_ARRAY(p->mem_ctx, ENUM_SERVICES_STATUS, num_int_services+num_ext_services )) )
1111           return WERR_NOMEM;
1112
1113         result = _svcctl_enum_internal_services(p->mem_ctx, &services, 0, &num_int_services);
1114
1115         if (W_ERROR_IS_OK(result)) {
1116                 DEBUG(8,("_svcctl_enum_services_status: Got %d internal services\n", num_int_services));
1117         } 
1118
1119         ext_result=enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services);
1120
1121         if (W_ERROR_IS_OK(ext_result)) {
1122                 DEBUG(8,("_svcctl_enum_services_status: Got %d external services\n", num_ext_services));
1123         } 
1124
1125         DEBUG(8,("_svcctl_enum_services_status: total of %d services\n", num_int_services+num_ext_services));
1126
1127         buffer_size = 0;
1128         for (i=0;i<num_int_services+num_ext_services;i++) {
1129           buffer_size += svcctl_sizeof_enum_services_status(&services[i]);
1130         }
1131
1132         /* */
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));
1136
1137         if (buffer_size > q_u->buffer_size ) {
1138                 num_int_services = 0;
1139                 num_ext_services = 0;
1140                 result = WERR_MORE_DATA;
1141         }
1142
1143         rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
1144
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 );
1148         }
1149
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;
1152
1153         if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) )
1154                 return WERR_NOMEM;
1155
1156         *r_u->resume = 0x0;
1157
1158         return result;
1159 }
1160
1161 /********************************************************************
1162 ********************************************************************/
1163
1164 WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCTL_R_START_SERVICE *r_u)
1165 {
1166         return WERR_ACCESS_DENIED;
1167 }
1168
1169 /********************************************************************
1170 ********************************************************************/
1171
1172 WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, SVCCTL_R_CONTROL_SERVICE *r_u)
1173 {
1174 #if 0
1175         SERVICE_INFO *service_info;
1176         POLICY_HND   *handle;
1177         pstring      command;
1178         SERVICE_STATUS *service_status;
1179         int          ret,fd;
1180
1181         /* need to find the service name by the handle that is open */
1182         handle = &(q_u->handle);
1183
1184         service_info = find_service_info_by_hnd(p, handle);
1185
1186         if (!service_info) {
1187                 DEBUG(10, ("_svcctl_control_service : Can't find the service for the handle\n"));
1188                 return WERR_BADFID; 
1189         }
1190
1191         /* we return a SERVICE_STATUS structure if there's an error. */
1192         if ( !(service_status = TALLOC_ARRAY(p->mem_ctx, SERVICE_STATUS, 1 ))  )
1193                 return WERR_NOMEM;
1194
1195         DEBUG(10, ("_svcctl_control_service: Found service [%s], [%s]\n",
1196                 service_info->servicename, service_info->filename));
1197
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");
1203         }
1204
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");
1208         }
1209
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");
1213         }
1214
1215         DEBUG(10, ("_svcctl_control_service: status command is [%s]\n", command));
1216
1217         /* TODO  - wrap in privilege check */
1218
1219         ret = smbrun(command, &fd);
1220         DEBUGADD(10, ("returned [%d]\n", ret));
1221         close(fd);
1222
1223         if(ret != 0)
1224                 DEBUG(10, ("enum_external_services: Command returned  [%d]\n", ret));
1225
1226         /* SET all service_stats bits here...*/
1227         if (ret == 0) {
1228                 service_status->state              = SVCCTL_RUNNING;
1229                 service_status->controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
1230         } else {
1231                 service_status->state              = SVCCTL_STOPPED;
1232                 service_status->controls_accepted  = 0;
1233         }
1234
1235         DEBUG(10, ("_svcctl_query_service_config: Should call the commFound service [%s], [%s]\n",service_info->servicename,service_info->filename));
1236
1237 #endif
1238
1239         return WERR_OK;
1240 }
1241
1242 /********************************************************************
1243 ********************************************************************/
1244
1245 WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT_SERVICES *q_u, SVCCTL_R_ENUM_DEPENDENT_SERVICES *r_u )
1246 {
1247         
1248         /* we have to set the outgoing buffer size to the same as the 
1249            incoming buffer size (even in the case of failure */
1250
1251         rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
1252                                 
1253         r_u->needed      = q_u->buffer_size;
1254         
1255         /* no dependent services...basically a stub function */
1256         r_u->returned    = 0;
1257
1258         return WERR_OK;
1259 }
1260
1261 /********************************************************************
1262 ********************************************************************/
1263
1264 WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u )
1265 {
1266         SERVICE_STATUS_PROCESS ssp;
1267         POLICY_HND *handle;
1268         SERVICE_INFO *service_info;
1269         pstring     command;
1270
1271         /* we have to set the outgoing buffer size to the same as the 
1272            incoming buffer size (even in the case of failure */
1273
1274         r_u->needed      = q_u->buffer_size;
1275
1276         /* need to find the service name by the handle that is open */
1277         handle = &(q_u->handle);
1278
1279
1280         /* get rid of the easy errors */
1281
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; 
1285         }
1286
1287         service_info = find_service_info_by_hnd(p, handle);
1288
1289         if (!service_info) {
1290                 DEBUG(10, ("_svcctl_query_service_status_ex : Can't find the service for the handle\n"));
1291                 return WERR_BADFID; 
1292         }
1293         
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;
1297         }
1298
1299         ZERO_STRUCT(ssp); 
1300             
1301 #if 0
1302         if (!strwicmp(service_info->servicetype,"EXTERNAL")) 
1303                 ssp.type = SVCCTL_WIN32_OWN_PROC;
1304         else 
1305                 ssp.type = SVCCTL_WIN32_SHARED_PROC;
1306 #endif
1307
1308         /* Get the status of the service.. */
1309
1310         memset(command, 0, sizeof(command));
1311
1312 #if 0
1313         slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, service_info->filename, "status");
1314
1315         DEBUG(10, ("_svcctl_query_service_status_ex: status command is [%s]\n", command));
1316
1317         /* TODO  - wrap in privilege check */
1318
1319         ret = smbrun(command, &fd);
1320         DEBUGADD(10, ("returned [%d]\n", ret));
1321         close(fd);
1322         if(ret != 0)
1323                 DEBUG(10, ("_svcctl_query_service_status_ex: Command returned  [%d]\n", ret));
1324
1325         /* SET all service_stats bits here... */
1326         if (ret == 0) {
1327                 ssp.state              = SVCCTL_RUNNING;
1328                 ssp.controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
1329         } else {
1330                 ssp.state              = SVCCTL_STOPPED;
1331                 ssp.controls_accepted  = 0;
1332         }
1333 #endif
1334
1335         return WERR_OK;
1336 }
1337
1338 /********************************************************************
1339 ********************************************************************/
1340
1341 WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
1342 {
1343         POLICY_HND *handle;
1344         SERVICE_INFO *service_info;
1345         uint32      needed_size;
1346
1347         /* we have to set the outgoing buffer size to the same as the 
1348            incoming buffer size (even in the case of failure */
1349
1350         r_u->needed      = q_u->buffer_size;
1351
1352         /* need to find the service name by the handle that is open */
1353         handle = &(q_u->handle);
1354
1355         service_info = find_service_info_by_hnd(p, handle);
1356
1357 #if 0
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));
1364
1365                 return WERR_INSUFFICIENT_BUFFER;
1366         }
1367 #endif
1368         if (!service_info) {
1369                 DEBUG(10, ("_svcctl_query_service_config : Can't find the service for the handle\n"));
1370                 return WERR_BADFID; 
1371         }
1372
1373 #if 0
1374         if ( !(service_config = (SERVICE_CONFIG *)TALLOC_ZERO_P(p->mem_ctx, SERVICE_CONFIG)) )
1375                 return WERR_NOMEM;
1376 #endif
1377
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;
1382
1383         /* Init the strings */
1384
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);
1390
1391 #if 0
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. */
1397         
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);
1402
1403         /* TODO - if someone really cares, perhaps "LocalSystem" should be changed to something else here... */
1404
1405         init_unistr2(r_u->config.startname,"LocalSystem",UNI_STR_TERMINATE);
1406         init_unistr2(r_u->config.displayname,service_info->servicename,UNI_STR_TERMINATE);
1407 #endif
1408
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);
1415         
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));
1423
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;
1432         }
1433
1434         return WERR_OK;
1435 }
1436
1437 /********************************************************************
1438 ********************************************************************/
1439
1440 WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u )
1441 {
1442         POLICY_HND *handle;
1443         SERVICE_INFO *service_info;
1444         uint32   level;
1445  
1446         /* we have to set the outgoing buffer size to the same as the 
1447            incoming buffer size (even in the case of failure */
1448
1449         r_u->needed      = q_u->buffer_size;
1450         r_u->description = NULL;               
1451         r_u->returned = q_u->buffer_size;
1452         r_u->offset = 4;                       
1453
1454         handle = &(q_u->handle);
1455
1456         service_info = find_service_info_by_hnd(p, handle);
1457
1458         if (!service_info) {
1459                 DEBUG(10, ("_svcctl_query_service_config2 : Can't find the service for the handle\n"));
1460                 return WERR_BADFID; 
1461         }
1462         
1463         /* 
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...
1466         */
1467
1468         level = q_u->info_level;
1469
1470 #if 0
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));
1477             
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);
1482                         }
1483                 }
1484                 else { 
1485                         string_buffer_size = 0;
1486                 }
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;
1493                 }
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));
1496
1497                 return WERR_OK;    
1498         } 
1499 #endif
1500
1501         return WERR_ACCESS_DENIED;
1502 }