r7613: small changes to _svcctl_open_service() and create_open_service_handle() to...
[amitay/samba.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 struct service_control_op_table {
42         const char *name;
43         SERVICE_CONTROL_OPS *ops;
44 };
45
46 extern SERVICE_CONTROL_OPS spoolss_svc_ops;
47
48 struct service_control_op_table svcctl_ops[] = { 
49         { "Spooler",    &spoolss_svc_ops },
50         { "NETLOGON",   NULL },
51         { NULL,         NULL }
52 };
53
54
55 /********************************************************************
56 ********************************************************************/
57
58 static NTSTATUS svcctl_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token, 
59                                      uint32 access_desired, uint32 *access_granted )
60 {
61         NTSTATUS result;
62         
63         /* maybe add privilege checks in here later */
64         
65         se_access_check( sec_desc, token, access_desired, access_granted, &result );
66         
67         return result;
68 }
69
70 /********************************************************************
71 ********************************************************************/
72
73 static SEC_DESC* construct_scm_sd( TALLOC_CTX *ctx )
74 {
75         SEC_ACE ace[2]; 
76         SEC_ACCESS mask;
77         size_t i = 0;
78         SEC_DESC *sd;
79         SEC_ACL *acl;
80         uint32 sd_size;
81
82         /* basic access for Everyone */
83         
84         init_sec_access(&mask, SC_MANAGER_READ_ACCESS );
85         init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
86         
87         /* Full Access 'BUILTIN\Administrators' */
88         
89         init_sec_access(&mask,SC_MANAGER_ALL_ACCESS );
90         init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
91         
92         
93         /* create the security descriptor */
94         
95         if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
96                 return NULL;
97
98         if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
99                 return NULL;
100
101         return sd;
102 }
103
104 /********************************************************************
105 ********************************************************************/
106
107 static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx )
108 {
109         SEC_ACE ace[4]; 
110         SEC_ACCESS mask;
111         size_t i = 0;
112         SEC_DESC *sd;
113         SEC_ACL *acl;
114         uint32 sd_size;
115
116         /* basic access for Everyone */
117         
118         init_sec_access(&mask, SERVICE_READ_ACCESS );
119         init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
120                 
121         init_sec_access(&mask,SERVICE_EXECUTE_ACCESS );
122         init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
123         
124         init_sec_access(&mask,SERVICE_ALL_ACCESS );
125         init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
126         init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
127         
128         /* create the security descriptor */
129         
130         if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
131                 return NULL;
132
133         if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
134                 return NULL;
135
136         return sd;
137 }
138
139 /******************************************************************
140  free() function for REGISTRY_KEY
141  *****************************************************************/
142  
143 static void free_service_handle_info(void *ptr)
144 {
145         SERVICE_INFO *info = (SERVICE_INFO*)ptr;
146         
147         SAFE_FREE(info->name);
148         SAFE_FREE(info);
149 }
150
151 /******************************************************************
152  Find a registry key handle and return a SERVICE_INFO
153  *****************************************************************/
154
155 static SERVICE_INFO *find_service_info_by_hnd(pipes_struct *p, POLICY_HND *hnd)
156 {
157         SERVICE_INFO *service_info = NULL;
158
159         if( !find_policy_by_hnd( p, hnd, (void **)&service_info) ) {
160                 DEBUG(2,("find_service_info_by_hnd: handle not found"));
161                 return NULL;
162         }
163
164         return service_info;
165 }
166
167 /******************************************************************
168  *****************************************************************/
169  
170 static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle, 
171                                           const char *service, uint32 access_granted )
172 {
173         SERVICE_INFO *info = NULL;
174         WERROR result = WERR_OK;
175         
176         if ( !(info = SMB_MALLOC_P( SERVICE_INFO )) )
177                 return WERR_NOMEM;
178
179         ZERO_STRUCTP( info );
180                 
181         /* the Service Manager has a NULL name */
182         
183         if ( !service ) {
184                 info->type = SVC_HANDLE_IS_SCM;
185         } else {
186                 int i;
187
188                 info->type = SVC_HANDLE_IS_SERVICE;
189                 
190                 /* lookup the SERVICE_CONTROL_OPS */
191
192                 for ( i=0; svcctl_ops[i].name; i++ ) {
193                         if ( strequal( svcctl_ops[i].name, service ) )  {
194                                 info->ops = svcctl_ops[i].ops;
195                                 break;
196                         }
197                 }
198
199                 if ( !svcctl_ops[i].name ) {
200                         result = WERR_NO_SUCH_SERVICE;
201                         goto done;
202                 }
203
204                 if ( !(info->name  = SMB_STRDUP( service )) ) {
205                         result = WERR_NOMEM;
206                         goto done;
207                 }
208         }
209
210         info->access_granted = access_granted;  
211         
212         /* store the SERVICE_INFO and create an open handle */
213         
214         if ( !create_policy_hnd( p, handle, free_service_handle_info, info ) ) {
215                 result = WERR_ACCESS_DENIED;
216                 goto done;
217         }
218                 
219 done:
220         if ( !W_ERROR_IS_OK(result) )
221                 free_service_handle_info( info );
222
223         return result;
224 }
225
226 /********************************************************************
227 ********************************************************************/
228
229 WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVCCTL_R_OPEN_SCMANAGER *r_u)
230 {
231         SEC_DESC *sec_desc;
232         uint32 access_granted = 0;
233         NTSTATUS status;
234         
235         /* perform access checks */
236         
237         if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) )
238                 return WERR_NOMEM;
239                 
240         status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
241         if ( !NT_STATUS_IS_OK(status) )
242                 return ntstatus_to_werror( status );
243                 
244         return create_open_service_handle( p, &r_u->handle, NULL, access_granted );
245 }
246
247 /********************************************************************
248 ********************************************************************/
249
250 WERROR _svcctl_open_service(pipes_struct *p, SVCCTL_Q_OPEN_SERVICE *q_u, SVCCTL_R_OPEN_SERVICE *r_u)
251 {
252         SEC_DESC *sec_desc;
253         uint32 access_granted = 0;
254         NTSTATUS status;
255         pstring service;
256         SERVICE_INFO *scm_info;
257
258         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
259         
260         DEBUG(5, ("_svcctl_open_service: Attempting to open Service [%s], \n", service));
261
262         
263         /* based on my tests you can open a service if you have a valid scm handle */
264         
265         if ( !(scm_info = find_service_info_by_hnd( p, &q_u->handle )) )
266                 return WERR_BADFID;
267                         
268         /* perform access checks */
269         
270         if ( !(sec_desc = construct_service_sd( p->mem_ctx )) )
271                 return WERR_NOMEM;
272                 
273         status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
274         if ( !NT_STATUS_IS_OK(status) )
275                 return ntstatus_to_werror( status );
276                 
277 #if 0   /* FIXME!!! */
278         if ( ! get_service_info(service_tdb, service, info) ) {
279                 return WERR_NO_SUCH_SERVICE;
280 #endif
281         
282         return create_open_service_handle( p, &r_u->handle, service, access_granted );
283 }
284
285 /********************************************************************
286 ********************************************************************/
287
288 WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCTL_R_CLOSE_SERVICE *r_u)
289 {
290         return close_policy_hnd( p, &q_u->handle ) ? WERR_OK : WERR_BADFID;
291 }
292
293 /********************************************************************
294 ********************************************************************/
295
296 WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, SVCCTL_R_GET_DISPLAY_NAME *r_u)
297 {
298         fstring service;
299         fstring displayname;
300         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
301         
302         /* can only use an SCM handle here */
303         
304         if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
305                 return WERR_BADFID;
306                 
307         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
308
309         /* need a tdb lookup here or something */
310         
311         fstrcpy( displayname, "FIX ME!" );
312
313         init_svcctl_r_get_display_name( r_u, displayname );
314
315         return WERR_OK;
316 }
317
318 /********************************************************************
319 ********************************************************************/
320
321 WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_R_QUERY_STATUS *r_u)
322 {
323         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
324         
325         /* perform access checks */
326
327         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
328                 return WERR_BADFID;
329                 
330         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
331                 return WERR_ACCESS_DENIED;
332                 
333         /* try the service specific status call */
334
335         if ( info->ops ) 
336                 return info->ops->service_status( &r_u->svc_status );
337
338         /* default action for now */
339
340         r_u->svc_status.type = 0x0020;
341         r_u->svc_status.state = 0x0004;
342         r_u->svc_status.controls_accepted = 0x0005;
343
344         return WERR_OK;
345 }
346
347
348 /*********************************************************************
349  TODO - for internal services, do similar to external services, except 
350  we have to call the right status routine...
351 **********************************************************************/
352
353 static WERROR enum_internal_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services, int *added) 
354 {
355         int num_services = 2;
356         int i = 0;
357         ENUM_SERVICES_STATUS *services=NULL;
358
359         if (!svc_ptr || !(*svc_ptr)) 
360                 return WERR_NOMEM;
361
362         services = *svc_ptr;
363
364 #if 0
365         /* *svc_ptr has the pointer to the array if there is one already. NULL if not. */
366         if ((existing_services>0) && svc_ptr && *svc_ptr) { /* reallocate vs. allocate */
367                 DEBUG(8,("enum_internal_services: REALLOCing %d services\n", num_services));
368                 services = TALLOC_REALLOC_ARRAY(tcx,*svc_ptr,ENUM_SERVICES_STATUS,existing_services+num_services);
369                 if (!rsvcs) 
370                         return WERR_NOMEM;
371                 *svc_ptr = services;
372         } else {
373                 if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
374                         return WERR_NOMEM;
375         }
376 #endif
377
378         if (existing_services > 0) {
379                 i += existing_services;
380         }
381         DEBUG(8,("enum_internal_services: Creating %d services, starting index %d\n", num_services,existing_services));
382                                 
383         init_unistr( &services[i].servicename, "Spooler" );
384         init_unistr( &services[i].displayname, "Print Spooler" );
385         
386         services[i].status.type               = 0x110;
387         services[i].status.controls_accepted  = 0x0;
388         services[i].status.win32_exit_code    = 0x0;
389         services[i].status.service_exit_code  = 0x0;
390         services[i].status.check_point        = 0x0;
391         services[i].status.wait_hint          = 0x0;
392         if ( !lp_disable_spoolss() ) 
393                 services[i].status.state              = SVCCTL_RUNNING;
394         else
395                 services[i].status.state              = SVCCTL_STOPPED;
396
397         i++;            
398         
399         init_unistr( &services[i].servicename, "NETLOGON" );
400         init_unistr( &services[i].displayname, "Net Logon" );
401         
402         services[i].status.type               = 0x20;   
403         services[i].status.controls_accepted  = 0x0;
404         services[i].status.win32_exit_code    = 0x0;
405         services[i].status.service_exit_code  = 0x0;
406         services[i].status.check_point        = 0x0;
407         services[i].status.wait_hint          = 0x0;
408         if ( lp_servicenumber("NETLOGON") != -1 ) 
409                 services[i].status.state              = SVCCTL_RUNNING;
410         else
411                 services[i].status.state              = SVCCTL_STOPPED;
412
413         *added = num_services;
414
415         return WERR_OK;
416 }
417
418 /********************************************************************
419 ********************************************************************/
420
421 WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
422 {
423         ENUM_SERVICES_STATUS *services = NULL;
424         uint32 num_int_services = 0;
425         uint32 num_ext_services = 0;
426         int i = 0;
427         size_t buffer_size;
428         WERROR result = WERR_OK;
429         WERROR ext_result = WERR_OK;
430         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
431         
432         /* perform access checks */
433
434         if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
435                 return WERR_BADFID;
436                 
437         if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) )
438                 return WERR_ACCESS_DENIED;
439
440         /* num_services = str_list_count( lp_enable_svcctl() ); */
441
442         /* here's where we'll read the db of external services */
443         /* _svcctl_read_LSB_data(NULL,NULL); */
444         /* init_svcctl_db(); */
445         
446         num_int_services = 0;
447
448         num_int_services = num_internal_services();
449
450         num_ext_services =  num_external_services();
451
452         if ( !(services = TALLOC_ARRAY(p->mem_ctx, ENUM_SERVICES_STATUS, num_int_services+num_ext_services )) )
453           return WERR_NOMEM;
454
455         result = enum_internal_services(p->mem_ctx, &services, 0, &num_int_services);
456
457         if (W_ERROR_IS_OK(result)) {
458                 DEBUG(8,("_svcctl_enum_services_status: Got %d internal services\n", num_int_services));
459         } 
460
461         ext_result=enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services);
462
463         if (W_ERROR_IS_OK(ext_result)) {
464                 DEBUG(8,("_svcctl_enum_services_status: Got %d external services\n", num_ext_services));
465         } 
466
467         DEBUG(8,("_svcctl_enum_services_status: total of %d services\n", num_int_services+num_ext_services));
468
469         buffer_size = 0;
470         for (i=0;i<num_int_services+num_ext_services;i++) {
471           buffer_size += svcctl_sizeof_enum_services_status(&services[i]);
472         }
473
474         /* */
475         buffer_size += buffer_size % 4;
476         DEBUG(8,("_svcctl_enum_services_status: buffer size passed %d, we need %d\n",
477                  q_u->buffer_size, buffer_size));
478
479         if (buffer_size > q_u->buffer_size ) {
480                 num_int_services = 0;
481                 num_ext_services = 0;
482                 result = WERR_MORE_DATA;
483         }
484
485         rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
486
487         if ( W_ERROR_IS_OK(result) ) {
488                 for ( i=0; i<num_int_services+num_ext_services; i++ )
489                         svcctl_io_enum_services_status( "", &services[i], &r_u->buffer, 0 );
490         }
491
492         r_u->needed      = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
493         r_u->returned    = num_int_services+num_ext_services;
494
495         if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) )
496                 return WERR_NOMEM;
497
498         *r_u->resume = 0x0;
499
500         return result;
501 }
502
503 /********************************************************************
504 ********************************************************************/
505
506 WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCTL_R_START_SERVICE *r_u)
507 {
508         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
509         
510         /* perform access checks */
511
512         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
513                 return WERR_BADFID;
514         
515         if ( !(info->access_granted & SC_RIGHT_SVC_START) )
516                 return WERR_ACCESS_DENIED;
517                 
518         return info->ops->start_service();
519 }
520
521 /********************************************************************
522 ********************************************************************/
523
524 WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, SVCCTL_R_CONTROL_SERVICE *r_u)
525 {
526         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
527         
528         /* perform access checks */
529         /* we only support stop so don't get complicated */
530
531         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
532                 return WERR_BADFID;     
533         
534         if ( q_u->control != SVCCTL_CONTROL_STOP )
535                 return WERR_ACCESS_DENIED;
536                 
537         if ( !(info->access_granted & SC_RIGHT_SVC_STOP) )
538                 return WERR_ACCESS_DENIED;
539                 
540         return info->ops->stop_service( &r_u->svc_status );
541 }
542
543 /********************************************************************
544 ********************************************************************/
545
546 WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT_SERVICES *q_u, SVCCTL_R_ENUM_DEPENDENT_SERVICES *r_u )
547 {
548         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
549         
550         /* perform access checks */
551
552         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
553                 return WERR_BADFID;     
554         
555         if ( !(info->access_granted & SC_RIGHT_SVC_ENUMERATE_DEPENDENTS) )
556                 return WERR_ACCESS_DENIED;
557                         
558         /* we have to set the outgoing buffer size to the same as the 
559            incoming buffer size (even in the case of failure */
560
561         rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
562                                 
563         r_u->needed      = q_u->buffer_size;
564         
565         /* no dependent services...basically a stub function */
566         r_u->returned    = 0;
567
568         return WERR_OK;
569 }
570
571 /********************************************************************
572 ********************************************************************/
573
574 WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u )
575 {
576         SERVICE_STATUS_PROCESS ssp;
577         POLICY_HND *handle;
578         SERVICE_INFO *service_info;
579         pstring     command;
580         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
581         
582         /* perform access checks */
583
584         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
585                 return WERR_BADFID;     
586         
587         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
588                 return WERR_ACCESS_DENIED;
589
590         /* we have to set the outgoing buffer size to the same as the 
591            incoming buffer size (even in the case of failure */
592
593         r_u->needed      = q_u->buffer_size;
594
595         /* need to find the service name by the handle that is open */
596         handle = &(q_u->handle);
597
598
599         /* get rid of the easy errors */
600
601         if (q_u->info_level != SVC_STATUS_PROCESS_INFO) {
602                 DEBUG(10, ("_svcctl_query_service_status_ex :  Invalid information level specified\n"));
603                 return WERR_UNKNOWN_LEVEL; 
604         }
605
606         service_info = find_service_info_by_hnd(p, handle);
607
608         if (!service_info) {
609                 DEBUG(10, ("_svcctl_query_service_status_ex : Can't find the service for the handle\n"));
610                 return WERR_BADFID; 
611         }
612         
613         if (r_u->needed < (sizeof(SERVICE_STATUS_PROCESS)+sizeof(uint32)+sizeof(uint32))) {
614                 DEBUG(10, ("_svcctl_query_service_status_ex : buffer size of [%d] is too small.\n",r_u->needed));
615                 return WERR_INSUFFICIENT_BUFFER;
616         }
617
618         ZERO_STRUCT(ssp); 
619             
620 #if 0
621         if (!strwicmp(service_info->servicetype,"EXTERNAL")) 
622                 ssp.type = SVCCTL_WIN32_OWN_PROC;
623         else 
624                 ssp.type = SVCCTL_WIN32_SHARED_PROC;
625 #endif
626
627         /* Get the status of the service.. */
628
629         memset(command, 0, sizeof(command));
630
631 #if 0
632         slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, service_info->filename, "status");
633
634         DEBUG(10, ("_svcctl_query_service_status_ex: status command is [%s]\n", command));
635
636         /* TODO  - wrap in privilege check */
637
638         ret = smbrun(command, &fd);
639         DEBUGADD(10, ("returned [%d]\n", ret));
640         close(fd);
641         if(ret != 0)
642                 DEBUG(10, ("_svcctl_query_service_status_ex: Command returned  [%d]\n", ret));
643
644         /* SET all service_stats bits here... */
645         if (ret == 0) {
646                 ssp.state              = SVCCTL_RUNNING;
647                 ssp.controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
648         } else {
649                 ssp.state              = SVCCTL_STOPPED;
650                 ssp.controls_accepted  = 0;
651         }
652 #endif
653
654         return WERR_OK;
655 }
656
657 /********************************************************************
658 ********************************************************************/
659
660 WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
661 {
662         POLICY_HND *handle;
663         SERVICE_INFO *service_info;
664         uint32      needed_size;
665         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
666         
667         /* perform access checks */
668
669         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
670                 return WERR_BADFID;     
671         
672         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
673                 return WERR_ACCESS_DENIED;
674
675         /* we have to set the outgoing buffer size to the same as the 
676            incoming buffer size (even in the case of failure */
677
678         r_u->needed      = q_u->buffer_size;
679
680         /* need to find the service name by the handle that is open */
681         handle = &(q_u->handle);
682
683         service_info = find_service_info_by_hnd(p, handle);
684
685 #if 0
686         if (q_u->buffer_size < sizeof(Service_info)) {
687                 /* have to report need more... */
688                 /* TODO worst case -- should actualy calc what we need here. */
689                 r_u->needed = sizeof(Service_info)+sizeof(pstring)*5; 
690                 DEBUG(10, ("_svcctl_query_service_config: NOT ENOUGH BUFFER ALLOCATED FOR RETURN DATA -- provided %d wanted %d\n",
691                 q_u->buffer_size,r_u->needed));
692
693                 return WERR_INSUFFICIENT_BUFFER;
694         }
695 #endif
696         if (!service_info) {
697                 DEBUG(10, ("_svcctl_query_service_config : Can't find the service for the handle\n"));
698                 return WERR_BADFID; 
699         }
700
701 #if 0
702         if ( !(service_config = (SERVICE_CONFIG *)TALLOC_ZERO_P(p->mem_ctx, SERVICE_CONFIG)) )
703                 return WERR_NOMEM;
704 #endif
705
706         r_u->config.service_type       = SVCCTL_WIN32_OWN_PROC;
707         r_u->config.start_type         = SVCCTL_DEMAND_START;
708         r_u->config.error_control      = SVCCTL_SVC_ERROR_IGNORE;
709         r_u->config.tag_id = 0x00000000;
710
711         /* Init the strings */
712
713         r_u->config.executablepath = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
714         r_u->config.loadordergroup = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
715         r_u->config.dependencies = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
716         r_u->config.startname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
717         r_u->config.displayname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
718
719 #if 0
720         pstrcpy(fullpathinfo,dyn_LIBDIR);
721         pstrcat(fullpathinfo,SVCCTL_SCRIPT_DIR);
722         pstrcat(fullpathinfo,service_info->filename);
723         /* Get and calculate the size of the fields. Note that we're still building the fields in the "too-small buffer case"
724            even though we throw it away. */
725         
726         DEBUG(10, ("_svcctl_query_service_config: fullpath info [%s]\n",fullpathinfo));
727         init_unistr2(r_u->config.executablepath,fullpathinfo,UNI_STR_TERMINATE);
728         init_unistr2(r_u->config.loadordergroup,"",UNI_STR_TERMINATE);
729         init_unistr2(r_u->config.dependencies,service_info->dependencies,UNI_STR_TERMINATE);
730
731         /* TODO - if someone really cares, perhaps "LocalSystem" should be changed to something else here... */
732
733         init_unistr2(r_u->config.startname,"LocalSystem",UNI_STR_TERMINATE);
734         init_unistr2(r_u->config.displayname,service_info->servicename,UNI_STR_TERMINATE);
735 #endif
736
737         needed_size = 0x04 + sizeof(SERVICE_CONFIG)+ 2*(
738                       r_u->config.executablepath->uni_str_len +
739                       r_u->config.loadordergroup->uni_str_len + 
740                       r_u->config.dependencies->uni_str_len + 
741                       r_u->config.startname->uni_str_len + 
742                       r_u->config.displayname->uni_str_len);
743         
744         DEBUG(10, ("_svcctl_query_service_config: ****** need to have a buffer of [%d], [%d] for struct \n",needed_size,
745                    sizeof(SERVICE_CONFIG)));
746         DEBUG(10, ("\tsize of executable path : %d\n",r_u->config.executablepath->uni_str_len));
747         DEBUG(10, ("\tsize of loadordergroup  : %d\n", r_u->config.loadordergroup->uni_str_len)); 
748         DEBUG(10, ("\tsize of dependencies    : %d\n", r_u->config.dependencies->uni_str_len)); 
749         DEBUG(10, ("\tsize of startname       : %d\n", r_u->config.startname->uni_str_len));
750         DEBUG(10, ("\tsize of displayname     : %d\n", r_u->config.displayname->uni_str_len));
751
752         if (q_u->buffer_size < needed_size) {
753                 /* have to report need more...*/
754                 r_u->needed = needed_size;
755                 DEBUG(10, ("_svcctl_query_service_config: ****** zeroing strings for return\n"));
756                 memset(&r_u->config,0,sizeof(SERVICE_CONFIG));
757                 DEBUG(10, ("_svcctl_query_service_config: Not enouh buffer provided for return -- provided %d wanted %d\n",
758                         q_u->buffer_size,needed_size));
759                 return WERR_INSUFFICIENT_BUFFER;
760         }
761
762         return WERR_OK;
763 }
764
765 /********************************************************************
766 ********************************************************************/
767
768 WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u )
769 {
770         POLICY_HND *handle;
771         SERVICE_INFO *service_info;
772         uint32   level;
773         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
774         
775         /* perform access checks */
776
777         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
778                 return WERR_BADFID;     
779         
780         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
781                 return WERR_ACCESS_DENIED;
782  
783         /* we have to set the outgoing buffer size to the same as the 
784            incoming buffer size (even in the case of failure */
785
786         r_u->needed      = q_u->buffer_size;
787         r_u->description = NULL;               
788         r_u->returned = q_u->buffer_size;
789         r_u->offset = 4;                       
790
791         handle = &(q_u->handle);
792
793         service_info = find_service_info_by_hnd(p, handle);
794
795         if (!service_info) {
796                 DEBUG(10, ("_svcctl_query_service_config2 : Can't find the service for the handle\n"));
797                 return WERR_BADFID; 
798         }
799         
800         /* 
801            TODO - perhaps move the RPC_DATA_BLOB into the R_QUERY_SERVICE_CONFIG structure, and to the processing in here, vs
802            in the *r_query_config2 marshalling routine...
803         */
804
805         level = q_u->info_level;
806
807 #if 0
808         if (SERVICE_CONFIG_DESCRIPTION == level) {
809                 if (service_info && service_info->shortdescription) {
810                         /* length of the string, plus the terminator... */
811                         string_buffer_size = strlen(service_info->shortdescription)+1; 
812                         DEBUG(10, ("_svcctl_query_service_config: copying the description [%s] length [%d]\n",
813                         service_info->shortdescription,string_buffer_size));
814             
815                         if (q_u->buffer_size >= ((string_buffer_size)*2+4)) {
816                                 r_u->description = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
817                                 if (!r_u->description) return WERR_NOMEM;
818                                         init_unistr2(r_u->description,service_info->shortdescription,UNI_STR_TERMINATE);
819                         }
820                 }
821                 else { 
822                         string_buffer_size = 0;
823                 }
824                 DEBUG(10, ("_svcctl_query_service_config2: buffer needed is [%x], return buffer size is [%x]\n",
825                         string_buffer_size,q_u->buffer_size));
826                 if (((string_buffer_size)*2+4) > q_u->buffer_size) {
827                         r_u->needed = (string_buffer_size+1)*2+4;
828                         DEBUG(10, ("_svcctl_query_service_config2: INSUFFICIENT BUFFER\n"));
829                         return WERR_INSUFFICIENT_BUFFER;
830                 }
831                 DEBUG(10, ("_svcctl_query_service_config2: returning ok, needed is [%x], buffer size is [%x]\n",
832                 r_u->needed,q_u->buffer_size));
833
834                 return WERR_OK;    
835         } 
836 #endif
837
838         return WERR_ACCESS_DENIED;
839 }