r7610: can successfully stop and start the 'spooler' service by setting the state...
[jerry/samba.git] / source / rpc_server / srv_svcctl_nt.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Gerald (Jerry) Carter             2005,
5  *  Copyright (C) Marcin Krzysztof Porwit           2005.
6  *  
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *  
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *  
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 /* TODO - Do the OpenService service name matching case-independently, or at least make it an option. */
23
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_RPC_SRV
29
30 #define SERVICEDB_VERSION_V1 1 /* Will there be more? */
31 #define INTERNAL_SERVICES_LIST "NETLOGON Spooler"
32
33 /*                                                                                                                     */
34 /* scripts will execute from the following libdir, if they are in the enable svcctl=<list of scripts>                  */
35 /* these should likely be symbolic links. Note that information about them will be extracted from the files themselves */
36 /* using the LSB standard keynames for various information                                                             */
37
38 #define SVCCTL_SCRIPT_DIR  "/svcctl/"
39
40
41 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         
175         if ( !(info = SMB_MALLOC_P( SERVICE_INFO )) )
176                 return WERR_NOMEM;
177
178         ZERO_STRUCTP( info );
179                 
180         /* the Service Manager has a NULL name */
181         
182         if ( !service ) {
183                 info->type = SVC_HANDLE_IS_SCM;
184         } else {
185                 int i;
186
187                 info->type = SVC_HANDLE_IS_SERVICE;
188                 
189                 if ( !(info->name  = SMB_STRDUP( service )) ) {
190                         free_service_handle_info( info );
191                         WERR_NOMEM;
192                 }
193                 
194                 /* lookup the SERVICE_CONTROL_OPS */
195
196                 for ( i=0; svcctl_ops[i].name; i++ ) {
197                         if ( strequal( svcctl_ops[i].name, service ) ) 
198                                 info->ops = svcctl_ops[i].ops;
199                 }
200         }
201
202         info->access_granted = access_granted;  
203         
204         /* store the SERVICE_INFO and create an open handle */
205         
206         if ( !create_policy_hnd( p, handle, free_service_handle_info, info ) ) {
207                 free_service_handle_info( info );
208                 return WERR_ACCESS_DENIED;
209         }
210                 
211         return WERR_OK;
212 }
213
214 /********************************************************************
215 ********************************************************************/
216
217 WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVCCTL_R_OPEN_SCMANAGER *r_u)
218 {
219         SEC_DESC *sec_desc;
220         uint32 access_granted = 0;
221         NTSTATUS status;
222         
223         /* perform access checks */
224         
225         if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) )
226                 return WERR_NOMEM;
227                 
228         status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
229         if ( !NT_STATUS_IS_OK(status) )
230                 return ntstatus_to_werror( status );
231                 
232         return create_open_service_handle( p, &r_u->handle, NULL, access_granted );
233 }
234
235 /********************************************************************
236 ********************************************************************/
237
238 WERROR _svcctl_open_service(pipes_struct *p, SVCCTL_Q_OPEN_SERVICE *q_u, SVCCTL_R_OPEN_SERVICE *r_u)
239 {
240         SEC_DESC *sec_desc;
241         uint32 access_granted = 0;
242         NTSTATUS status;
243         pstring service;
244         SERVICE_INFO *scm_info;
245
246         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
247         
248         DEBUG(5, ("_svcctl_open_service: Attempting to open Service [%s], \n", service));
249
250         
251         /* based on my tests you can open a service if you have a valid scm handle */
252         
253         if ( !(scm_info = find_service_info_by_hnd( p, &q_u->handle )) )
254                 return WERR_BADFID;
255                         
256         /* perform access checks */
257         
258         if ( !(sec_desc = construct_service_sd( p->mem_ctx )) )
259                 return WERR_NOMEM;
260                 
261         status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
262         if ( !NT_STATUS_IS_OK(status) )
263                 return ntstatus_to_werror( status );
264                 
265 #if 0   /* FIXME!!! */
266         if ( ! get_service_info(service_tdb, service, info) ) {
267                 return WERR_NO_SUCH_SERVICE;
268 #endif
269         
270         return create_open_service_handle( p, &r_u->handle, service, access_granted );
271 }
272
273 /********************************************************************
274 ********************************************************************/
275
276 WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCTL_R_CLOSE_SERVICE *r_u)
277 {
278         return close_policy_hnd( p, &q_u->handle ) ? WERR_OK : WERR_BADFID;
279 }
280
281 /********************************************************************
282 ********************************************************************/
283
284 WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, SVCCTL_R_GET_DISPLAY_NAME *r_u)
285 {
286         fstring service;
287         fstring displayname;
288         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
289         
290         /* can only use an SCM handle here */
291         
292         if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
293                 return WERR_BADFID;
294                 
295         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
296
297         /* need a tdb lookup here or something */
298         
299         fstrcpy( displayname, "FIX ME!" );
300
301         init_svcctl_r_get_display_name( r_u, displayname );
302
303         return WERR_OK;
304 }
305
306 /********************************************************************
307 ********************************************************************/
308
309 WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_R_QUERY_STATUS *r_u)
310 {
311         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
312         
313         /* perform access checks */
314
315         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
316                 return WERR_BADFID;
317                 
318         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
319                 return WERR_ACCESS_DENIED;
320                 
321         /* try the service specific status call */
322
323         if ( info->ops ) 
324                 return info->ops->service_status( &r_u->svc_status );
325
326         /* default action for now */
327
328         r_u->svc_status.type = 0x0020;
329         r_u->svc_status.state = 0x0004;
330         r_u->svc_status.controls_accepted = 0x0005;
331
332         return WERR_OK;
333 }
334
335
336 /*********************************************************************
337  TODO - for internal services, do similar to external services, except 
338  we have to call the right status routine...
339 **********************************************************************/
340
341 static WERROR enum_internal_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services, int *added) 
342 {
343         int num_services = 2;
344         int i = 0;
345         ENUM_SERVICES_STATUS *services=NULL;
346
347         if (!svc_ptr || !(*svc_ptr)) 
348                 return WERR_NOMEM;
349
350         services = *svc_ptr;
351
352 #if 0
353         /* *svc_ptr has the pointer to the array if there is one already. NULL if not. */
354         if ((existing_services>0) && svc_ptr && *svc_ptr) { /* reallocate vs. allocate */
355                 DEBUG(8,("enum_internal_services: REALLOCing %d services\n", num_services));
356                 services = TALLOC_REALLOC_ARRAY(tcx,*svc_ptr,ENUM_SERVICES_STATUS,existing_services+num_services);
357                 if (!rsvcs) 
358                         return WERR_NOMEM;
359                 *svc_ptr = services;
360         } else {
361                 if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
362                         return WERR_NOMEM;
363         }
364 #endif
365
366         if (existing_services > 0) {
367                 i += existing_services;
368         }
369         DEBUG(8,("enum_internal_services: Creating %d services, starting index %d\n", num_services,existing_services));
370                                 
371         init_unistr( &services[i].servicename, "Spooler" );
372         init_unistr( &services[i].displayname, "Print Spooler" );
373         
374         services[i].status.type               = 0x110;
375         services[i].status.controls_accepted  = 0x0;
376         services[i].status.win32_exit_code    = 0x0;
377         services[i].status.service_exit_code  = 0x0;
378         services[i].status.check_point        = 0x0;
379         services[i].status.wait_hint          = 0x0;
380         if ( !lp_disable_spoolss() ) 
381                 services[i].status.state              = SVCCTL_RUNNING;
382         else
383                 services[i].status.state              = SVCCTL_STOPPED;
384
385         i++;            
386         
387         init_unistr( &services[i].servicename, "NETLOGON" );
388         init_unistr( &services[i].displayname, "Net Logon" );
389         
390         services[i].status.type               = 0x20;   
391         services[i].status.controls_accepted  = 0x0;
392         services[i].status.win32_exit_code    = 0x0;
393         services[i].status.service_exit_code  = 0x0;
394         services[i].status.check_point        = 0x0;
395         services[i].status.wait_hint          = 0x0;
396         if ( lp_servicenumber("NETLOGON") != -1 ) 
397                 services[i].status.state              = SVCCTL_RUNNING;
398         else
399                 services[i].status.state              = SVCCTL_STOPPED;
400
401         *added = num_services;
402
403         return WERR_OK;
404 }
405
406 /********************************************************************
407 ********************************************************************/
408
409 WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
410 {
411         ENUM_SERVICES_STATUS *services = NULL;
412         uint32 num_int_services = 0;
413         uint32 num_ext_services = 0;
414         int i = 0;
415         size_t buffer_size;
416         WERROR result = WERR_OK;
417         WERROR ext_result = WERR_OK;
418         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
419         
420         /* perform access checks */
421
422         if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
423                 return WERR_BADFID;
424                 
425         if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) )
426                 return WERR_ACCESS_DENIED;
427
428         /* num_services = str_list_count( lp_enable_svcctl() ); */
429
430         /* here's where we'll read the db of external services */
431         /* _svcctl_read_LSB_data(NULL,NULL); */
432         /* init_svcctl_db(); */
433         
434         num_int_services = 0;
435
436         num_int_services = num_internal_services();
437
438         num_ext_services =  num_external_services();
439
440         if ( !(services = TALLOC_ARRAY(p->mem_ctx, ENUM_SERVICES_STATUS, num_int_services+num_ext_services )) )
441           return WERR_NOMEM;
442
443         result = enum_internal_services(p->mem_ctx, &services, 0, &num_int_services);
444
445         if (W_ERROR_IS_OK(result)) {
446                 DEBUG(8,("_svcctl_enum_services_status: Got %d internal services\n", num_int_services));
447         } 
448
449         ext_result=enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services);
450
451         if (W_ERROR_IS_OK(ext_result)) {
452                 DEBUG(8,("_svcctl_enum_services_status: Got %d external services\n", num_ext_services));
453         } 
454
455         DEBUG(8,("_svcctl_enum_services_status: total of %d services\n", num_int_services+num_ext_services));
456
457         buffer_size = 0;
458         for (i=0;i<num_int_services+num_ext_services;i++) {
459           buffer_size += svcctl_sizeof_enum_services_status(&services[i]);
460         }
461
462         /* */
463         buffer_size += buffer_size % 4;
464         DEBUG(8,("_svcctl_enum_services_status: buffer size passed %d, we need %d\n",
465                  q_u->buffer_size, buffer_size));
466
467         if (buffer_size > q_u->buffer_size ) {
468                 num_int_services = 0;
469                 num_ext_services = 0;
470                 result = WERR_MORE_DATA;
471         }
472
473         rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
474
475         if ( W_ERROR_IS_OK(result) ) {
476                 for ( i=0; i<num_int_services+num_ext_services; i++ )
477                         svcctl_io_enum_services_status( "", &services[i], &r_u->buffer, 0 );
478         }
479
480         r_u->needed      = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
481         r_u->returned    = num_int_services+num_ext_services;
482
483         if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) )
484                 return WERR_NOMEM;
485
486         *r_u->resume = 0x0;
487
488         return result;
489 }
490
491 /********************************************************************
492 ********************************************************************/
493
494 WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCTL_R_START_SERVICE *r_u)
495 {
496         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
497         
498         /* perform access checks */
499
500         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
501                 return WERR_BADFID;
502         
503         if ( !(info->access_granted & SC_RIGHT_SVC_START) )
504                 return WERR_ACCESS_DENIED;
505                 
506         return info->ops->start_service();
507 }
508
509 /********************************************************************
510 ********************************************************************/
511
512 WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, SVCCTL_R_CONTROL_SERVICE *r_u)
513 {
514         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
515         
516         /* perform access checks */
517         /* we only support stop so don't get complicated */
518
519         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
520                 return WERR_BADFID;     
521         
522         if ( q_u->control != SVCCTL_CONTROL_STOP )
523                 return WERR_ACCESS_DENIED;
524                 
525         if ( !(info->access_granted & SC_RIGHT_SVC_STOP) )
526                 return WERR_ACCESS_DENIED;
527                 
528         return info->ops->stop_service( &r_u->svc_status );
529 }
530
531 /********************************************************************
532 ********************************************************************/
533
534 WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT_SERVICES *q_u, SVCCTL_R_ENUM_DEPENDENT_SERVICES *r_u )
535 {
536         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
537         
538         /* perform access checks */
539
540         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
541                 return WERR_BADFID;     
542         
543         if ( !(info->access_granted & SC_RIGHT_SVC_ENUMERATE_DEPENDENTS) )
544                 return WERR_ACCESS_DENIED;
545                         
546         /* we have to set the outgoing buffer size to the same as the 
547            incoming buffer size (even in the case of failure */
548
549         rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
550                                 
551         r_u->needed      = q_u->buffer_size;
552         
553         /* no dependent services...basically a stub function */
554         r_u->returned    = 0;
555
556         return WERR_OK;
557 }
558
559 /********************************************************************
560 ********************************************************************/
561
562 WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u )
563 {
564         SERVICE_STATUS_PROCESS ssp;
565         POLICY_HND *handle;
566         SERVICE_INFO *service_info;
567         pstring     command;
568         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
569         
570         /* perform access checks */
571
572         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
573                 return WERR_BADFID;     
574         
575         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
576                 return WERR_ACCESS_DENIED;
577
578         /* we have to set the outgoing buffer size to the same as the 
579            incoming buffer size (even in the case of failure */
580
581         r_u->needed      = q_u->buffer_size;
582
583         /* need to find the service name by the handle that is open */
584         handle = &(q_u->handle);
585
586
587         /* get rid of the easy errors */
588
589         if (q_u->info_level != SVC_STATUS_PROCESS_INFO) {
590                 DEBUG(10, ("_svcctl_query_service_status_ex :  Invalid information level specified\n"));
591                 return WERR_UNKNOWN_LEVEL; 
592         }
593
594         service_info = find_service_info_by_hnd(p, handle);
595
596         if (!service_info) {
597                 DEBUG(10, ("_svcctl_query_service_status_ex : Can't find the service for the handle\n"));
598                 return WERR_BADFID; 
599         }
600         
601         if (r_u->needed < (sizeof(SERVICE_STATUS_PROCESS)+sizeof(uint32)+sizeof(uint32))) {
602                 DEBUG(10, ("_svcctl_query_service_status_ex : buffer size of [%d] is too small.\n",r_u->needed));
603                 return WERR_INSUFFICIENT_BUFFER;
604         }
605
606         ZERO_STRUCT(ssp); 
607             
608 #if 0
609         if (!strwicmp(service_info->servicetype,"EXTERNAL")) 
610                 ssp.type = SVCCTL_WIN32_OWN_PROC;
611         else 
612                 ssp.type = SVCCTL_WIN32_SHARED_PROC;
613 #endif
614
615         /* Get the status of the service.. */
616
617         memset(command, 0, sizeof(command));
618
619 #if 0
620         slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, service_info->filename, "status");
621
622         DEBUG(10, ("_svcctl_query_service_status_ex: status command is [%s]\n", command));
623
624         /* TODO  - wrap in privilege check */
625
626         ret = smbrun(command, &fd);
627         DEBUGADD(10, ("returned [%d]\n", ret));
628         close(fd);
629         if(ret != 0)
630                 DEBUG(10, ("_svcctl_query_service_status_ex: Command returned  [%d]\n", ret));
631
632         /* SET all service_stats bits here... */
633         if (ret == 0) {
634                 ssp.state              = SVCCTL_RUNNING;
635                 ssp.controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
636         } else {
637                 ssp.state              = SVCCTL_STOPPED;
638                 ssp.controls_accepted  = 0;
639         }
640 #endif
641
642         return WERR_OK;
643 }
644
645 /********************************************************************
646 ********************************************************************/
647
648 WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
649 {
650         POLICY_HND *handle;
651         SERVICE_INFO *service_info;
652         uint32      needed_size;
653         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
654         
655         /* perform access checks */
656
657         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
658                 return WERR_BADFID;     
659         
660         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
661                 return WERR_ACCESS_DENIED;
662
663         /* we have to set the outgoing buffer size to the same as the 
664            incoming buffer size (even in the case of failure */
665
666         r_u->needed      = q_u->buffer_size;
667
668         /* need to find the service name by the handle that is open */
669         handle = &(q_u->handle);
670
671         service_info = find_service_info_by_hnd(p, handle);
672
673 #if 0
674         if (q_u->buffer_size < sizeof(Service_info)) {
675                 /* have to report need more... */
676                 /* TODO worst case -- should actualy calc what we need here. */
677                 r_u->needed = sizeof(Service_info)+sizeof(pstring)*5; 
678                 DEBUG(10, ("_svcctl_query_service_config: NOT ENOUGH BUFFER ALLOCATED FOR RETURN DATA -- provided %d wanted %d\n",
679                 q_u->buffer_size,r_u->needed));
680
681                 return WERR_INSUFFICIENT_BUFFER;
682         }
683 #endif
684         if (!service_info) {
685                 DEBUG(10, ("_svcctl_query_service_config : Can't find the service for the handle\n"));
686                 return WERR_BADFID; 
687         }
688
689 #if 0
690         if ( !(service_config = (SERVICE_CONFIG *)TALLOC_ZERO_P(p->mem_ctx, SERVICE_CONFIG)) )
691                 return WERR_NOMEM;
692 #endif
693
694         r_u->config.service_type       = SVCCTL_WIN32_OWN_PROC;
695         r_u->config.start_type         = SVCCTL_DEMAND_START;
696         r_u->config.error_control      = SVCCTL_SVC_ERROR_IGNORE;
697         r_u->config.tag_id = 0x00000000;
698
699         /* Init the strings */
700
701         r_u->config.executablepath = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
702         r_u->config.loadordergroup = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
703         r_u->config.dependencies = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
704         r_u->config.startname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
705         r_u->config.displayname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
706
707 #if 0
708         pstrcpy(fullpathinfo,dyn_LIBDIR);
709         pstrcat(fullpathinfo,SVCCTL_SCRIPT_DIR);
710         pstrcat(fullpathinfo,service_info->filename);
711         /* Get and calculate the size of the fields. Note that we're still building the fields in the "too-small buffer case"
712            even though we throw it away. */
713         
714         DEBUG(10, ("_svcctl_query_service_config: fullpath info [%s]\n",fullpathinfo));
715         init_unistr2(r_u->config.executablepath,fullpathinfo,UNI_STR_TERMINATE);
716         init_unistr2(r_u->config.loadordergroup,"",UNI_STR_TERMINATE);
717         init_unistr2(r_u->config.dependencies,service_info->dependencies,UNI_STR_TERMINATE);
718
719         /* TODO - if someone really cares, perhaps "LocalSystem" should be changed to something else here... */
720
721         init_unistr2(r_u->config.startname,"LocalSystem",UNI_STR_TERMINATE);
722         init_unistr2(r_u->config.displayname,service_info->servicename,UNI_STR_TERMINATE);
723 #endif
724
725         needed_size = 0x04 + sizeof(SERVICE_CONFIG)+ 2*(
726                       r_u->config.executablepath->uni_str_len +
727                       r_u->config.loadordergroup->uni_str_len + 
728                       r_u->config.dependencies->uni_str_len + 
729                       r_u->config.startname->uni_str_len + 
730                       r_u->config.displayname->uni_str_len);
731         
732         DEBUG(10, ("_svcctl_query_service_config: ****** need to have a buffer of [%d], [%d] for struct \n",needed_size,
733                    sizeof(SERVICE_CONFIG)));
734         DEBUG(10, ("\tsize of executable path : %d\n",r_u->config.executablepath->uni_str_len));
735         DEBUG(10, ("\tsize of loadordergroup  : %d\n", r_u->config.loadordergroup->uni_str_len)); 
736         DEBUG(10, ("\tsize of dependencies    : %d\n", r_u->config.dependencies->uni_str_len)); 
737         DEBUG(10, ("\tsize of startname       : %d\n", r_u->config.startname->uni_str_len));
738         DEBUG(10, ("\tsize of displayname     : %d\n", r_u->config.displayname->uni_str_len));
739
740         if (q_u->buffer_size < needed_size) {
741                 /* have to report need more...*/
742                 r_u->needed = needed_size;
743                 DEBUG(10, ("_svcctl_query_service_config: ****** zeroing strings for return\n"));
744                 memset(&r_u->config,0,sizeof(SERVICE_CONFIG));
745                 DEBUG(10, ("_svcctl_query_service_config: Not enouh buffer provided for return -- provided %d wanted %d\n",
746                         q_u->buffer_size,needed_size));
747                 return WERR_INSUFFICIENT_BUFFER;
748         }
749
750         return WERR_OK;
751 }
752
753 /********************************************************************
754 ********************************************************************/
755
756 WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u )
757 {
758         POLICY_HND *handle;
759         SERVICE_INFO *service_info;
760         uint32   level;
761         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
762         
763         /* perform access checks */
764
765         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
766                 return WERR_BADFID;     
767         
768         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
769                 return WERR_ACCESS_DENIED;
770  
771         /* we have to set the outgoing buffer size to the same as the 
772            incoming buffer size (even in the case of failure */
773
774         r_u->needed      = q_u->buffer_size;
775         r_u->description = NULL;               
776         r_u->returned = q_u->buffer_size;
777         r_u->offset = 4;                       
778
779         handle = &(q_u->handle);
780
781         service_info = find_service_info_by_hnd(p, handle);
782
783         if (!service_info) {
784                 DEBUG(10, ("_svcctl_query_service_config2 : Can't find the service for the handle\n"));
785                 return WERR_BADFID; 
786         }
787         
788         /* 
789            TODO - perhaps move the RPC_DATA_BLOB into the R_QUERY_SERVICE_CONFIG structure, and to the processing in here, vs
790            in the *r_query_config2 marshalling routine...
791         */
792
793         level = q_u->info_level;
794
795 #if 0
796         if (SERVICE_CONFIG_DESCRIPTION == level) {
797                 if (service_info && service_info->shortdescription) {
798                         /* length of the string, plus the terminator... */
799                         string_buffer_size = strlen(service_info->shortdescription)+1; 
800                         DEBUG(10, ("_svcctl_query_service_config: copying the description [%s] length [%d]\n",
801                         service_info->shortdescription,string_buffer_size));
802             
803                         if (q_u->buffer_size >= ((string_buffer_size)*2+4)) {
804                                 r_u->description = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
805                                 if (!r_u->description) return WERR_NOMEM;
806                                         init_unistr2(r_u->description,service_info->shortdescription,UNI_STR_TERMINATE);
807                         }
808                 }
809                 else { 
810                         string_buffer_size = 0;
811                 }
812                 DEBUG(10, ("_svcctl_query_service_config2: buffer needed is [%x], return buffer size is [%x]\n",
813                         string_buffer_size,q_u->buffer_size));
814                 if (((string_buffer_size)*2+4) > q_u->buffer_size) {
815                         r_u->needed = (string_buffer_size+1)*2+4;
816                         DEBUG(10, ("_svcctl_query_service_config2: INSUFFICIENT BUFFER\n"));
817                         return WERR_INSUFFICIENT_BUFFER;
818                 }
819                 DEBUG(10, ("_svcctl_query_service_config2: returning ok, needed is [%x], buffer size is [%x]\n",
820                 r_u->needed,q_u->buffer_size));
821
822                 return WERR_OK;    
823         } 
824 #endif
825
826         return WERR_ACCESS_DENIED;
827 }