r8943: Fix segfault in enum_service_status
[kai/samba-autobuild/.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         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
257         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
258         
259         DEBUG(5, ("_svcctl_open_service: Attempting to open Service [%s], \n", service));
260
261         
262         /* based on my tests you can open a service if you have a valid scm handle */
263         
264         if ( !find_service_info_by_hnd( p, &q_u->handle ) )
265                 return WERR_BADFID;
266                         
267         /* perform access checks */
268         
269         if ( !(sec_desc = construct_service_sd( p->mem_ctx )) )
270                 return WERR_NOMEM;
271                 
272         status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
273         if ( !NT_STATUS_IS_OK(status) )
274                 return ntstatus_to_werror( status );
275                 
276 #if 0   /* FIXME!!! */
277         if ( ! get_service_info(service_tdb, service, info) ) {
278                 return WERR_NO_SUCH_SERVICE;
279 #endif
280         
281         return create_open_service_handle( p, &r_u->handle, service, access_granted );
282 }
283
284 /********************************************************************
285 ********************************************************************/
286
287 WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCTL_R_CLOSE_SERVICE *r_u)
288 {
289         return close_policy_hnd( p, &q_u->handle ) ? WERR_OK : WERR_BADFID;
290 }
291
292 /********************************************************************
293 ********************************************************************/
294
295 WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, SVCCTL_R_GET_DISPLAY_NAME *r_u)
296 {
297         fstring service;
298         fstring displayname;
299         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
300         
301         /* can only use an SCM handle here */
302         
303         if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
304                 return WERR_BADFID;
305                 
306         rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
307
308         /* need a tdb lookup here or something */
309         
310         fstrcpy( displayname, "FIX ME!" );
311
312         init_svcctl_r_get_display_name( r_u, displayname );
313
314         return WERR_OK;
315 }
316
317 /********************************************************************
318 ********************************************************************/
319
320 WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_R_QUERY_STATUS *r_u)
321 {
322         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
323         
324         /* perform access checks */
325
326         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
327                 return WERR_BADFID;
328                 
329         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
330                 return WERR_ACCESS_DENIED;
331                 
332         /* try the service specific status call */
333
334         if ( info->ops ) 
335                 return info->ops->service_status( &r_u->svc_status );
336
337         /* default action for now */
338
339         r_u->svc_status.type = 0x0020;
340         r_u->svc_status.state = 0x0004;
341         r_u->svc_status.controls_accepted = 0x0005;
342
343         return WERR_OK;
344 }
345
346
347 /*********************************************************************
348  TODO - for internal services, do similar to external services, except 
349  we have to call the right status routine...
350 **********************************************************************/
351
352 static WERROR enum_internal_services(TALLOC_CTX *ctx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services, uint32 *added) 
353 {
354         int num_services = 2;
355         int i = 0;
356         ENUM_SERVICES_STATUS *services=NULL;
357
358         if (!svc_ptr || !(*svc_ptr)) 
359                 return WERR_NOMEM;
360
361         services = *svc_ptr;
362
363         if ( (existing_services > 0) && svc_ptr && *svc_ptr ) {
364                 ENUM_SERVICES_STATUS *tmp_services = NULL;              
365                 uint32 total_svc = existing_services + num_services;
366                 
367                 if ( !(tmp_services = TALLOC_REALLOC_ARRAY( ctx, services, ENUM_SERVICES_STATUS, total_svc )) )
368                         return WERR_NOMEM;
369                         
370                 services = tmp_services;
371                 i += existing_services;
372         } 
373         else {
374                 if ( !(services = TALLOC_ARRAY( ctx, ENUM_SERVICES_STATUS, num_services )) )
375                         return WERR_NOMEM;
376         }
377
378         DEBUG(8,("enum_internal_services: Creating %d services, starting index %d\n", 
379                 num_services, existing_services));
380                                 
381         init_unistr( &services[i].servicename, "Spooler" );
382         init_unistr( &services[i].displayname, "Print Spooler" );
383         
384         services[i].status.type               = 0x110;
385         services[i].status.controls_accepted  = 0x0;
386         services[i].status.win32_exit_code    = 0x0;
387         services[i].status.service_exit_code  = 0x0;
388         services[i].status.check_point        = 0x0;
389         services[i].status.wait_hint          = 0x0;
390         if ( !lp_disable_spoolss() ) 
391                 services[i].status.state              = SVCCTL_RUNNING;
392         else
393                 services[i].status.state              = SVCCTL_STOPPED;
394
395         i++;            
396         
397         init_unistr( &services[i].servicename, "NETLOGON" );
398         init_unistr( &services[i].displayname, "Net Logon" );
399         
400         services[i].status.type               = 0x20;   
401         services[i].status.controls_accepted  = 0x0;
402         services[i].status.win32_exit_code    = 0x0;
403         services[i].status.service_exit_code  = 0x0;
404         services[i].status.check_point        = 0x0;
405         services[i].status.wait_hint          = 0x0;
406         if ( lp_servicenumber("NETLOGON") != -1 ) 
407                 services[i].status.state              = SVCCTL_RUNNING;
408         else
409                 services[i].status.state              = SVCCTL_STOPPED;
410
411         *added   = num_services;
412         *svc_ptr = services;
413
414         return WERR_OK;
415 }
416
417 /********************************************************************
418 ********************************************************************/
419
420 WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
421 {
422         ENUM_SERVICES_STATUS *services = NULL;
423         uint32 num_int_services, num_ext_services, total_services;
424         int i = 0;
425         size_t buffer_size = 0;
426         WERROR result = WERR_OK;
427         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
428         
429         /* perform access checks */
430
431         if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
432                 return WERR_BADFID;
433                 
434         if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) )
435                 return WERR_ACCESS_DENIED;
436
437         num_int_services = 0;
438         num_ext_services = 0;
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         if ( !(services = TALLOC_ARRAY(p->mem_ctx, ENUM_SERVICES_STATUS, num_int_services+num_ext_services )) )
447                 return WERR_NOMEM;
448
449         if ( W_ERROR_IS_OK(enum_internal_services(p->mem_ctx, &services, 0, &num_int_services)) )
450                 DEBUG(8,("_svcctl_enum_services_status: Got %d internal services\n", num_int_services));
451
452 #if 0   
453         if ( W_ERROR_IS_OK(enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services)) )
454                 DEBUG(8,("_svcctl_enum_services_status: Got %d external services\n", num_ext_services));
455 #endif
456
457         total_services = num_int_services + num_ext_services; 
458
459         DEBUG(8,("_svcctl_enum_services_status: total of %d services\n", total_services ));
460
461         for ( i=0; i<total_services; i++ ) {
462                 buffer_size += svcctl_sizeof_enum_services_status(&services[i]);
463         }
464
465         buffer_size += buffer_size % 4;
466
467         if (buffer_size > q_u->buffer_size ) {
468                 total_services = 0;
469                 result = WERR_MORE_DATA;
470         }
471
472         rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
473
474         if ( W_ERROR_IS_OK(result) ) {
475                 for ( i=0; i<num_int_services+num_ext_services; i++ )
476                         svcctl_io_enum_services_status( "", &services[i], &r_u->buffer, 0 );
477         }
478
479         r_u->needed      = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
480         r_u->returned    = total_services;
481
482         if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) )
483                 return WERR_NOMEM;
484
485         *r_u->resume = 0x0;
486
487         return result;
488 }
489
490 /********************************************************************
491 ********************************************************************/
492
493 WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCTL_R_START_SERVICE *r_u)
494 {
495         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
496         
497         /* perform access checks */
498
499         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
500                 return WERR_BADFID;
501         
502         if ( !(info->access_granted & SC_RIGHT_SVC_START) )
503                 return WERR_ACCESS_DENIED;
504                 
505         return info->ops->start_service();
506 }
507
508 /********************************************************************
509 ********************************************************************/
510
511 WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, SVCCTL_R_CONTROL_SERVICE *r_u)
512 {
513         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
514         
515         /* perform access checks */
516         /* we only support stop so don't get complicated */
517
518         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
519                 return WERR_BADFID;     
520         
521         if ( q_u->control != SVCCTL_CONTROL_STOP )
522                 return WERR_ACCESS_DENIED;
523                 
524         if ( !(info->access_granted & SC_RIGHT_SVC_STOP) )
525                 return WERR_ACCESS_DENIED;
526                 
527         return info->ops->stop_service( &r_u->svc_status );
528 }
529
530 /********************************************************************
531 ********************************************************************/
532
533 WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT_SERVICES *q_u, SVCCTL_R_ENUM_DEPENDENT_SERVICES *r_u )
534 {
535         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
536         
537         /* perform access checks */
538
539         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
540                 return WERR_BADFID;     
541         
542         if ( !(info->access_granted & SC_RIGHT_SVC_ENUMERATE_DEPENDENTS) )
543                 return WERR_ACCESS_DENIED;
544                         
545         /* we have to set the outgoing buffer size to the same as the 
546            incoming buffer size (even in the case of failure */
547
548         rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
549                                 
550         r_u->needed      = q_u->buffer_size;
551         
552         /* no dependent services...basically a stub function */
553         r_u->returned    = 0;
554
555         return WERR_OK;
556 }
557
558 /********************************************************************
559 ********************************************************************/
560
561 WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u )
562 {
563         SERVICE_STATUS_PROCESS ssp;
564         POLICY_HND *handle;
565         SERVICE_INFO *service_info;
566         pstring     command;
567         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
568         
569         /* perform access checks */
570
571         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
572                 return WERR_BADFID;     
573         
574         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
575                 return WERR_ACCESS_DENIED;
576
577         /* we have to set the outgoing buffer size to the same as the 
578            incoming buffer size (even in the case of failure */
579
580         r_u->needed      = q_u->buffer_size;
581
582         /* need to find the service name by the handle that is open */
583         handle = &(q_u->handle);
584
585
586         /* get rid of the easy errors */
587
588         if (q_u->info_level != SVC_STATUS_PROCESS_INFO) {
589                 DEBUG(10, ("_svcctl_query_service_status_ex :  Invalid information level specified\n"));
590                 return WERR_UNKNOWN_LEVEL; 
591         }
592
593         service_info = find_service_info_by_hnd(p, handle);
594
595         if (!service_info) {
596                 DEBUG(10, ("_svcctl_query_service_status_ex : Can't find the service for the handle\n"));
597                 return WERR_BADFID; 
598         }
599         
600         if (r_u->needed < (sizeof(SERVICE_STATUS_PROCESS)+sizeof(uint32)+sizeof(uint32))) {
601                 DEBUG(10, ("_svcctl_query_service_status_ex : buffer size of [%d] is too small.\n",r_u->needed));
602                 return WERR_INSUFFICIENT_BUFFER;
603         }
604
605         ZERO_STRUCT(ssp); 
606             
607 #if 0
608         if (!strwicmp(service_info->servicetype,"EXTERNAL")) 
609                 ssp.type = SVCCTL_WIN32_OWN_PROC;
610         else 
611                 ssp.type = SVCCTL_WIN32_SHARED_PROC;
612 #endif
613
614         /* Get the status of the service.. */
615
616         memset(command, 0, sizeof(command));
617
618 #if 0
619         slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, service_info->filename, "status");
620
621         DEBUG(10, ("_svcctl_query_service_status_ex: status command is [%s]\n", command));
622
623         /* TODO  - wrap in privilege check */
624
625         ret = smbrun(command, &fd);
626         DEBUGADD(10, ("returned [%d]\n", ret));
627         close(fd);
628         if(ret != 0)
629                 DEBUG(10, ("_svcctl_query_service_status_ex: Command returned  [%d]\n", ret));
630
631         /* SET all service_stats bits here... */
632         if (ret == 0) {
633                 ssp.state              = SVCCTL_RUNNING;
634                 ssp.controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
635         } else {
636                 ssp.state              = SVCCTL_STOPPED;
637                 ssp.controls_accepted  = 0;
638         }
639 #endif
640
641         return WERR_OK;
642 }
643
644 /********************************************************************
645 ********************************************************************/
646
647 WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
648 {
649         POLICY_HND *handle;
650         SERVICE_INFO *service_info;
651         uint32      needed_size;
652         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
653         
654         /* perform access checks */
655
656         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
657                 return WERR_BADFID;     
658         
659         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
660                 return WERR_ACCESS_DENIED;
661
662         /* we have to set the outgoing buffer size to the same as the 
663            incoming buffer size (even in the case of failure */
664
665         r_u->needed      = q_u->buffer_size;
666
667         /* need to find the service name by the handle that is open */
668         handle = &(q_u->handle);
669
670         service_info = find_service_info_by_hnd(p, handle);
671
672 #if 0
673         if (q_u->buffer_size < sizeof(Service_info)) {
674                 /* have to report need more... */
675                 /* TODO worst case -- should actualy calc what we need here. */
676                 r_u->needed = sizeof(Service_info)+sizeof(pstring)*5; 
677                 DEBUG(10, ("_svcctl_query_service_config: NOT ENOUGH BUFFER ALLOCATED FOR RETURN DATA -- provided %d wanted %d\n",
678                 q_u->buffer_size,r_u->needed));
679
680                 return WERR_INSUFFICIENT_BUFFER;
681         }
682 #endif
683         if (!service_info) {
684                 DEBUG(10, ("_svcctl_query_service_config : Can't find the service for the handle\n"));
685                 return WERR_BADFID; 
686         }
687
688 #if 0
689         if ( !(service_config = (SERVICE_CONFIG *)TALLOC_ZERO_P(p->mem_ctx, SERVICE_CONFIG)) )
690                 return WERR_NOMEM;
691 #endif
692
693         r_u->config.service_type       = SVCCTL_WIN32_OWN_PROC;
694         r_u->config.start_type         = SVCCTL_DEMAND_START;
695         r_u->config.error_control      = SVCCTL_SVC_ERROR_IGNORE;
696         r_u->config.tag_id = 0x00000000;
697
698         /* Init the strings */
699
700         r_u->config.executablepath = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
701         r_u->config.loadordergroup = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
702         r_u->config.dependencies = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
703         r_u->config.startname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
704         r_u->config.displayname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
705
706 #if 0
707         pstrcpy(fullpathinfo,dyn_LIBDIR);
708         pstrcat(fullpathinfo,SVCCTL_SCRIPT_DIR);
709         pstrcat(fullpathinfo,service_info->filename);
710         /* Get and calculate the size of the fields. Note that we're still building the fields in the "too-small buffer case"
711            even though we throw it away. */
712         
713         DEBUG(10, ("_svcctl_query_service_config: fullpath info [%s]\n",fullpathinfo));
714         init_unistr2(r_u->config.executablepath,fullpathinfo,UNI_STR_TERMINATE);
715         init_unistr2(r_u->config.loadordergroup,"",UNI_STR_TERMINATE);
716         init_unistr2(r_u->config.dependencies,service_info->dependencies,UNI_STR_TERMINATE);
717
718         /* TODO - if someone really cares, perhaps "LocalSystem" should be changed to something else here... */
719
720         init_unistr2(r_u->config.startname,"LocalSystem",UNI_STR_TERMINATE);
721         init_unistr2(r_u->config.displayname,service_info->servicename,UNI_STR_TERMINATE);
722 #endif
723
724         needed_size = 0x04 + sizeof(SERVICE_CONFIG)+ 2*(
725                       r_u->config.executablepath->uni_str_len +
726                       r_u->config.loadordergroup->uni_str_len + 
727                       r_u->config.dependencies->uni_str_len + 
728                       r_u->config.startname->uni_str_len + 
729                       r_u->config.displayname->uni_str_len);
730         
731         DEBUG(10, ("_svcctl_query_service_config: ****** need to have a buffer of [%d], [%d] for struct \n",needed_size,
732                    sizeof(SERVICE_CONFIG)));
733         DEBUG(10, ("\tsize of executable path : %d\n",r_u->config.executablepath->uni_str_len));
734         DEBUG(10, ("\tsize of loadordergroup  : %d\n", r_u->config.loadordergroup->uni_str_len)); 
735         DEBUG(10, ("\tsize of dependencies    : %d\n", r_u->config.dependencies->uni_str_len)); 
736         DEBUG(10, ("\tsize of startname       : %d\n", r_u->config.startname->uni_str_len));
737         DEBUG(10, ("\tsize of displayname     : %d\n", r_u->config.displayname->uni_str_len));
738
739         if (q_u->buffer_size < needed_size) {
740                 /* have to report need more...*/
741                 r_u->needed = needed_size;
742                 DEBUG(10, ("_svcctl_query_service_config: ****** zeroing strings for return\n"));
743                 memset(&r_u->config,0,sizeof(SERVICE_CONFIG));
744                 DEBUG(10, ("_svcctl_query_service_config: Not enouh buffer provided for return -- provided %d wanted %d\n",
745                         q_u->buffer_size,needed_size));
746                 return WERR_INSUFFICIENT_BUFFER;
747         }
748
749         return WERR_OK;
750 }
751
752 /********************************************************************
753 ********************************************************************/
754
755 WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u )
756 {
757         POLICY_HND *handle;
758         SERVICE_INFO *service_info;
759         uint32   level;
760         SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
761         
762         /* perform access checks */
763
764         if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
765                 return WERR_BADFID;     
766         
767         if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) )
768                 return WERR_ACCESS_DENIED;
769  
770         /* we have to set the outgoing buffer size to the same as the 
771            incoming buffer size (even in the case of failure */
772
773         r_u->needed      = q_u->buffer_size;
774         r_u->description = NULL;               
775         r_u->returned = q_u->buffer_size;
776         r_u->offset = 4;                       
777
778         handle = &(q_u->handle);
779
780         service_info = find_service_info_by_hnd(p, handle);
781
782         if (!service_info) {
783                 DEBUG(10, ("_svcctl_query_service_config2 : Can't find the service for the handle\n"));
784                 return WERR_BADFID; 
785         }
786         
787         /* 
788            TODO - perhaps move the RPC_DATA_BLOB into the R_QUERY_SERVICE_CONFIG structure, and to the processing in here, vs
789            in the *r_query_config2 marshalling routine...
790         */
791
792         level = q_u->info_level;
793
794 #if 0
795         if (SERVICE_CONFIG_DESCRIPTION == level) {
796                 if (service_info && service_info->shortdescription) {
797                         /* length of the string, plus the terminator... */
798                         string_buffer_size = strlen(service_info->shortdescription)+1; 
799                         DEBUG(10, ("_svcctl_query_service_config: copying the description [%s] length [%d]\n",
800                         service_info->shortdescription,string_buffer_size));
801             
802                         if (q_u->buffer_size >= ((string_buffer_size)*2+4)) {
803                                 r_u->description = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
804                                 if (!r_u->description) return WERR_NOMEM;
805                                         init_unistr2(r_u->description,service_info->shortdescription,UNI_STR_TERMINATE);
806                         }
807                 }
808                 else { 
809                         string_buffer_size = 0;
810                 }
811                 DEBUG(10, ("_svcctl_query_service_config2: buffer needed is [%x], return buffer size is [%x]\n",
812                         string_buffer_size,q_u->buffer_size));
813                 if (((string_buffer_size)*2+4) > q_u->buffer_size) {
814                         r_u->needed = (string_buffer_size+1)*2+4;
815                         DEBUG(10, ("_svcctl_query_service_config2: INSUFFICIENT BUFFER\n"));
816                         return WERR_INSUFFICIENT_BUFFER;
817                 }
818                 DEBUG(10, ("_svcctl_query_service_config2: returning ok, needed is [%x], buffer size is [%x]\n",
819                 r_u->needed,q_u->buffer_size));
820
821                 return WERR_OK;    
822         } 
823 #endif
824
825         return WERR_ACCESS_DENIED;
826 }