r20269: merge -r20264:20267 from SAMBA_3_0_24
[kai/samba-autobuild/.git] / source3 / libmsrpc / cac_svcctl.c
1
2 /* 
3  *  Unix SMB/CIFS implementation.
4  *  MS-RPC client library implementation (SVCCTL pipe)
5  *  Copyright (C) Chris Nicholls              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 #include "libmsrpc.h"
23 #include "libsmb_internal.h"
24
25 #define WAIT_SLEEP_TIME 300000
26
27 int cac_WaitForService( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
28                         POLICY_HND * svc_hnd, uint32 state, uint32 timeout,
29                         SERVICE_STATUS * status );
30
31 int cac_SvcOpenScm( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
32                     struct SvcOpenScm *op )
33 {
34         SMBCSRV *srv = NULL;
35         struct rpc_pipe_client *pipe_hnd = NULL;
36         WERROR err;
37
38         POLICY_HND *scm_out = NULL;
39
40         if ( !hnd )
41                 return CAC_FAILURE;
42
43         if ( !hnd->_internal.ctx ) {
44                 hnd->status = NT_STATUS_INVALID_HANDLE;
45                 return CAC_FAILURE;
46         }
47
48         if ( !op || op->in.access == 0 || !mem_ctx ) {
49                 hnd->status = NT_STATUS_INVALID_PARAMETER;
50                 return CAC_FAILURE;
51         }
52
53         srv = cac_GetServer( hnd );
54         if ( !srv ) {
55                 hnd->status = NT_STATUS_INVALID_CONNECTION;
56                 return CAC_FAILURE;
57         }
58
59         /*initialize for samr pipe if we have to */
60         if ( !hnd->_internal.pipes[PI_SVCCTL] ) {
61                 if ( !
62                      ( pipe_hnd =
63                        cli_rpc_pipe_open_noauth( srv->cli, PI_SVCCTL,
64                                                  &( hnd->status ) ) ) ) {
65                         hnd->status = NT_STATUS_UNSUCCESSFUL;
66                         return CAC_FAILURE;
67                 }
68
69                 hnd->_internal.pipes[PI_SVCCTL] = True;
70         }
71
72         scm_out = talloc( mem_ctx, POLICY_HND );
73         if ( !scm_out ) {
74                 hnd->status = NT_STATUS_NO_MEMORY;
75                 return CAC_FAILURE;
76         }
77
78         err = rpccli_svcctl_open_scm( pipe_hnd, mem_ctx, scm_out,
79                                       op->in.access );
80         hnd->status = werror_to_ntstatus( err );
81
82         if ( !NT_STATUS_IS_OK( hnd->status ) )
83                 return CAC_FAILURE;
84
85         op->out.scm_hnd = scm_out;
86
87         return CAC_SUCCESS;
88 }
89
90 int cac_SvcClose( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
91                   POLICY_HND * scm_hnd )
92 {
93         struct rpc_pipe_client *pipe_hnd = NULL;
94         WERROR err;
95
96         if ( !hnd )
97                 return CAC_FAILURE;
98
99         if ( !hnd->_internal.ctx ) {
100                 hnd->status = NT_STATUS_INVALID_HANDLE;
101                 return CAC_FAILURE;
102         }
103
104         if ( !scm_hnd || !mem_ctx ) {
105                 hnd->status = NT_STATUS_INVALID_PARAMETER;
106                 return CAC_FAILURE;
107         }
108
109         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
110         if ( !pipe_hnd ) {
111                 hnd->status = NT_STATUS_INVALID_HANDLE;
112                 return CAC_FAILURE;
113         }
114
115         err = rpccli_svcctl_close_service( pipe_hnd, mem_ctx, scm_hnd );
116         hnd->status = werror_to_ntstatus( err );
117
118         if ( !NT_STATUS_IS_OK( hnd->status ) )
119                 return CAC_FAILURE;
120
121         return CAC_SUCCESS;
122 }
123
124 int cac_SvcEnumServices( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
125                          struct SvcEnumServices *op )
126 {
127         struct rpc_pipe_client *pipe_hnd = NULL;
128         WERROR err;
129
130         uint32 type_buf = 0;
131         uint32 state_buf = 0;
132
133         uint32 num_svc_out = 0;
134
135         ENUM_SERVICES_STATUS *svc_buf = NULL;
136
137         if ( !hnd )
138                 return CAC_FAILURE;
139
140         if ( !hnd->_internal.ctx ) {
141                 hnd->status = NT_STATUS_INVALID_HANDLE;
142                 return CAC_FAILURE;
143         }
144
145         if ( !op || !op->in.scm_hnd || !mem_ctx ) {
146                 hnd->status = NT_STATUS_INVALID_PARAMETER;
147                 return CAC_FAILURE;
148         }
149
150         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
151         if ( !pipe_hnd ) {
152                 hnd->status = NT_STATUS_INVALID_HANDLE;
153                 return CAC_FAILURE;
154         }
155
156         type_buf =
157                 ( op->in.type !=
158                   0 ) ? op->in.
159                 type : ( SVCCTL_TYPE_DRIVER | SVCCTL_TYPE_WIN32 );
160         state_buf = ( op->in.state != 0 ) ? op->in.state : SVCCTL_STATE_ALL;
161
162         err = rpccli_svcctl_enumerate_services( pipe_hnd, mem_ctx,
163                                                 op->in.scm_hnd, type_buf,
164                                                 state_buf, &num_svc_out,
165                                                 &svc_buf );
166         hnd->status = werror_to_ntstatus( err );
167
168         if ( !NT_STATUS_IS_OK( hnd->status ) )
169                 return CAC_FAILURE;
170
171         op->out.services =
172                 cac_MakeServiceArray( mem_ctx, svc_buf, num_svc_out );
173
174         if ( !op->out.services ) {
175                 hnd->status = NT_STATUS_NO_MEMORY;
176                 return CAC_FAILURE;
177         }
178
179         TALLOC_FREE( svc_buf );
180
181         op->out.num_services = num_svc_out;
182
183         return CAC_SUCCESS;
184 }
185
186 int cac_SvcOpenService( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
187                         struct SvcOpenService *op )
188 {
189         struct rpc_pipe_client *pipe_hnd = NULL;
190         WERROR err;
191
192         POLICY_HND *svc_hnd_out = NULL;
193
194         if ( !hnd )
195                 return CAC_FAILURE;
196
197         if ( !hnd->_internal.ctx ) {
198                 hnd->status = NT_STATUS_INVALID_HANDLE;
199                 return CAC_FAILURE;
200         }
201
202         if ( !op || !op->in.scm_hnd || !op->in.name || !mem_ctx ) {
203                 hnd->status = NT_STATUS_INVALID_PARAMETER;
204                 return CAC_FAILURE;
205         }
206
207         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
208         if ( !pipe_hnd ) {
209                 hnd->status = NT_STATUS_INVALID_HANDLE;
210                 return CAC_FAILURE;
211         }
212
213         svc_hnd_out = talloc( mem_ctx, POLICY_HND );
214         if ( !svc_hnd_out ) {
215                 hnd->status = NT_STATUS_NO_MEMORY;
216                 return CAC_FAILURE;
217         }
218
219         err = rpccli_svcctl_open_service( pipe_hnd, mem_ctx, op->in.scm_hnd,
220                                           svc_hnd_out, op->in.name,
221                                           op->in.access );
222         hnd->status = werror_to_ntstatus( err );
223
224         if ( !NT_STATUS_IS_OK( hnd->status ) )
225                 return CAC_FAILURE;
226
227         op->out.svc_hnd = svc_hnd_out;
228
229         return CAC_SUCCESS;
230 }
231
232 int cac_SvcControlService( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
233                            struct SvcControlService *op )
234 {
235         struct rpc_pipe_client *pipe_hnd = NULL;
236         WERROR err;
237
238         SERVICE_STATUS status_out;
239
240         if ( !hnd )
241                 return CAC_FAILURE;
242
243         if ( !hnd->_internal.ctx ) {
244                 hnd->status = NT_STATUS_INVALID_HANDLE;
245                 return CAC_FAILURE;
246         }
247
248         if ( !op || !op->in.svc_hnd || !mem_ctx ) {
249                 hnd->status = NT_STATUS_INVALID_PARAMETER;
250                 return CAC_FAILURE;
251         }
252
253         if ( op->in.control < SVCCTL_CONTROL_STOP
254              || op->in.control > SVCCTL_CONTROL_SHUTDOWN ) {
255                 hnd->status = NT_STATUS_INVALID_PARAMETER;
256                 return CAC_FAILURE;
257         }
258
259         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
260         if ( !pipe_hnd ) {
261                 hnd->status = NT_STATUS_INVALID_HANDLE;
262                 return CAC_FAILURE;
263         }
264
265         err = rpccli_svcctl_control_service( pipe_hnd, mem_ctx,
266                                              op->in.svc_hnd, op->in.control,
267                                              &status_out );
268         hnd->status = werror_to_ntstatus( err );
269
270         if ( !NT_STATUS_IS_OK( hnd->status ) )
271                 return CAC_FAILURE;
272
273         return CAC_SUCCESS;
274 }
275
276 int cac_SvcGetStatus( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
277                       struct SvcGetStatus *op )
278 {
279         struct rpc_pipe_client *pipe_hnd = NULL;
280         WERROR err;
281
282         SERVICE_STATUS status_out;
283
284         if ( !hnd )
285                 return CAC_FAILURE;
286
287         if ( !hnd->_internal.ctx ) {
288                 hnd->status = NT_STATUS_INVALID_HANDLE;
289                 return CAC_FAILURE;
290         }
291
292         if ( !op || !op->in.svc_hnd || !mem_ctx ) {
293                 hnd->status = NT_STATUS_INVALID_PARAMETER;
294                 return CAC_FAILURE;
295         }
296
297         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
298         if ( !pipe_hnd ) {
299                 hnd->status = NT_STATUS_INVALID_HANDLE;
300                 return CAC_FAILURE;
301         }
302
303         err = rpccli_svcctl_query_status( pipe_hnd, mem_ctx, op->in.svc_hnd,
304                                           &status_out );
305         hnd->status = werror_to_ntstatus( err );
306
307         if ( !NT_STATUS_IS_OK( hnd->status ) )
308                 return CAC_FAILURE;
309
310         op->out.status = status_out;
311
312         return CAC_SUCCESS;
313 }
314
315
316
317 /*Internal function - similar to code found in utils/net_rpc_service.c
318  * Waits for a service to reach a specific state.
319  * svc_hnd - Handle to the service
320  * state   - the state we are waiting for
321  * timeout - number of seconds to wait
322  * returns CAC_FAILURE if the state is never reached
323  *      or CAC_SUCCESS if the state is reached
324  */
325 int cac_WaitForService( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
326                         POLICY_HND * svc_hnd, uint32 state, uint32 timeout,
327                         SERVICE_STATUS * status )
328 {
329         struct rpc_pipe_client *pipe_hnd = NULL;
330
331         /*number of milliseconds we have spent */
332         uint32 time_spent = 0;
333         WERROR err;
334
335         if ( !hnd || !mem_ctx || !svc_hnd || !status )
336                 return CAC_FAILURE;
337
338         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
339         if ( !pipe_hnd ) {
340                 hnd->status = NT_STATUS_INVALID_HANDLE;
341                 return CAC_FAILURE;
342         }
343
344         while ( status->state != state && time_spent < ( timeout * 1000000 )
345                 && NT_STATUS_IS_OK( hnd->status ) ) {
346                 /*if this is the first call, then we _just_ got the status.. sleep now */
347                 usleep( WAIT_SLEEP_TIME );
348                 time_spent += WAIT_SLEEP_TIME;
349
350                 err = rpccli_svcctl_query_status( pipe_hnd, mem_ctx, svc_hnd,
351                                                   status );
352                 hnd->status = werror_to_ntstatus( err );
353         }
354
355         if ( status->state == state )
356                 return CAC_SUCCESS;
357
358         return CAC_FAILURE;
359 }
360
361 int cac_SvcStartService( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
362                          struct SvcStartService *op )
363 {
364         struct rpc_pipe_client *pipe_hnd = NULL;
365         WERROR err;
366
367         SERVICE_STATUS status_buf;
368
369         if ( !hnd )
370                 return CAC_FAILURE;
371
372         if ( !hnd->_internal.ctx ) {
373                 hnd->status = NT_STATUS_INVALID_HANDLE;
374                 return CAC_FAILURE;
375         }
376
377         if ( !op || !op->in.svc_hnd || !mem_ctx ) {
378                 hnd->status = NT_STATUS_INVALID_PARAMETER;
379                 return CAC_FAILURE;
380         }
381
382         if ( op->in.num_parms != 0 && op->in.parms == NULL ) {
383                 hnd->status = NT_STATUS_INVALID_PARAMETER;
384                 return CAC_FAILURE;
385         }
386
387         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
388         if ( !pipe_hnd ) {
389                 hnd->status = NT_STATUS_INVALID_HANDLE;
390                 return CAC_FAILURE;
391         }
392
393         err = rpccli_svcctl_start_service( pipe_hnd, mem_ctx, op->in.svc_hnd,
394                                            ( const char ** ) op->in.parms,
395                                            op->in.num_parms );
396         hnd->status = werror_to_ntstatus( err );
397
398         if ( !NT_STATUS_IS_OK( hnd->status ) )
399                 return CAC_FAILURE;
400
401         if ( op->in.timeout == 0 )
402                 return CAC_SUCCESS;
403
404         return cac_WaitForService( hnd, mem_ctx, op->in.svc_hnd,
405                                    SVCCTL_RUNNING, op->in.timeout,
406                                    &status_buf );
407 }
408
409 int cac_SvcStopService( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
410                         struct SvcStopService *op )
411 {
412         struct rpc_pipe_client *pipe_hnd = NULL;
413         WERROR err;
414
415         SERVICE_STATUS status_out;
416
417         if ( !hnd )
418                 return CAC_FAILURE;
419
420         if ( !hnd->_internal.ctx ) {
421                 hnd->status = NT_STATUS_INVALID_HANDLE;
422                 return CAC_FAILURE;
423         }
424
425         if ( !op || !op->in.svc_hnd || !mem_ctx ) {
426                 hnd->status = NT_STATUS_INVALID_PARAMETER;
427                 return CAC_FAILURE;
428         }
429
430         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
431         if ( !pipe_hnd ) {
432                 hnd->status = NT_STATUS_INVALID_HANDLE;
433                 return CAC_FAILURE;
434         }
435
436         err = rpccli_svcctl_control_service( pipe_hnd, mem_ctx,
437                                              op->in.svc_hnd,
438                                              SVCCTL_CONTROL_STOP,
439                                              &status_out );
440         hnd->status = werror_to_ntstatus( err );
441
442         if ( !NT_STATUS_IS_OK( hnd->status ) )
443                 return CAC_FAILURE;
444
445         op->out.status = status_out;
446
447         if ( op->in.timeout == 0 )
448                 return CAC_SUCCESS;
449
450         return cac_WaitForService( hnd, mem_ctx, op->in.svc_hnd,
451                                    SVCCTL_STOPPED, op->in.timeout,
452                                    &op->out.status );
453 }
454
455 int cac_SvcPauseService( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
456                          struct SvcPauseService *op )
457 {
458         struct rpc_pipe_client *pipe_hnd = NULL;
459         WERROR err;
460
461         SERVICE_STATUS status_out;
462
463         if ( !hnd )
464                 return CAC_FAILURE;
465
466         if ( !hnd->_internal.ctx ) {
467                 hnd->status = NT_STATUS_INVALID_HANDLE;
468                 return CAC_FAILURE;
469         }
470
471         if ( !op || !op->in.svc_hnd || !mem_ctx ) {
472                 hnd->status = NT_STATUS_INVALID_PARAMETER;
473                 return CAC_FAILURE;
474         }
475
476         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
477         if ( !pipe_hnd ) {
478                 hnd->status = NT_STATUS_INVALID_HANDLE;
479                 return CAC_FAILURE;
480         }
481
482         err = rpccli_svcctl_control_service( pipe_hnd, mem_ctx,
483                                              op->in.svc_hnd,
484                                              SVCCTL_CONTROL_PAUSE,
485                                              &status_out );
486         hnd->status = werror_to_ntstatus( err );
487
488         if ( !NT_STATUS_IS_OK( hnd->status ) )
489                 return CAC_FAILURE;
490
491         op->out.status = status_out;
492
493         if ( op->in.timeout == 0 )
494                 return CAC_SUCCESS;
495
496         return cac_WaitForService( hnd, mem_ctx, op->in.svc_hnd,
497                                    SVCCTL_PAUSED, op->in.timeout,
498                                    &op->out.status );
499 }
500
501 int cac_SvcContinueService( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
502                             struct SvcContinueService *op )
503 {
504         struct rpc_pipe_client *pipe_hnd = NULL;
505         WERROR err;
506
507         SERVICE_STATUS status_out;
508
509         if ( !hnd )
510                 return CAC_FAILURE;
511
512         if ( !hnd->_internal.ctx ) {
513                 hnd->status = NT_STATUS_INVALID_HANDLE;
514                 return CAC_FAILURE;
515         }
516
517         if ( !op || !op->in.svc_hnd || !mem_ctx ) {
518                 hnd->status = NT_STATUS_INVALID_PARAMETER;
519                 return CAC_FAILURE;
520         }
521
522         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
523         if ( !pipe_hnd ) {
524                 hnd->status = NT_STATUS_INVALID_HANDLE;
525                 return CAC_FAILURE;
526         }
527
528         err = rpccli_svcctl_control_service( pipe_hnd, mem_ctx,
529                                              op->in.svc_hnd,
530                                              SVCCTL_CONTROL_CONTINUE,
531                                              &status_out );
532         hnd->status = werror_to_ntstatus( err );
533
534         if ( !NT_STATUS_IS_OK( hnd->status ) )
535                 return CAC_FAILURE;
536
537         op->out.status = status_out;
538
539         if ( op->in.timeout == 0 )
540                 return CAC_SUCCESS;
541
542         return cac_WaitForService( hnd, mem_ctx, op->in.svc_hnd,
543                                    SVCCTL_RUNNING, op->in.timeout,
544                                    &op->out.status );
545 }
546
547 int cac_SvcGetDisplayName( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
548                            struct SvcGetDisplayName *op )
549 {
550         struct rpc_pipe_client *pipe_hnd = NULL;
551         WERROR err;
552
553         fstring disp_name_out;
554
555         if ( !hnd )
556                 return CAC_FAILURE;
557
558         if ( !hnd->_internal.ctx ) {
559                 hnd->status = NT_STATUS_INVALID_HANDLE;
560                 return CAC_FAILURE;
561         }
562
563         if ( !op || !op->in.svc_hnd || !mem_ctx ) {
564                 hnd->status = NT_STATUS_INVALID_PARAMETER;
565                 return CAC_FAILURE;
566         }
567
568         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
569         if ( !pipe_hnd ) {
570                 hnd->status = NT_STATUS_INVALID_HANDLE;
571                 return CAC_FAILURE;
572         }
573
574         err = rpccli_svcctl_get_dispname( pipe_hnd, mem_ctx, op->in.svc_hnd,
575                                           disp_name_out );
576         hnd->status = werror_to_ntstatus( err );
577
578         if ( !NT_STATUS_IS_OK( hnd->status ) )
579                 return CAC_FAILURE;
580
581         op->out.display_name = talloc_strdup( mem_ctx, disp_name_out );
582
583         if ( !op->out.display_name ) {
584                 hnd->status = NT_STATUS_NO_MEMORY;
585                 return CAC_FAILURE;
586         }
587
588         return CAC_SUCCESS;
589 }
590
591
592 int cac_SvcGetServiceConfig( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
593                              struct SvcGetServiceConfig *op )
594 {
595         struct rpc_pipe_client *pipe_hnd = NULL;
596         WERROR err;
597
598         SERVICE_CONFIG config_out;
599
600         if ( !hnd )
601                 return CAC_FAILURE;
602
603         if ( !hnd->_internal.ctx ) {
604                 hnd->status = NT_STATUS_INVALID_HANDLE;
605                 return CAC_FAILURE;
606         }
607
608         if ( !op || !op->in.svc_hnd || !mem_ctx ) {
609                 hnd->status = NT_STATUS_INVALID_PARAMETER;
610                 return CAC_FAILURE;
611         }
612
613         pipe_hnd = cac_GetPipe( hnd, PI_SVCCTL );
614         if ( !pipe_hnd ) {
615                 hnd->status = NT_STATUS_INVALID_HANDLE;
616                 return CAC_FAILURE;
617         }
618
619         err = rpccli_svcctl_query_config( pipe_hnd, mem_ctx, op->in.svc_hnd,
620                                           &config_out );
621         hnd->status = werror_to_ntstatus( err );
622
623         if ( !NT_STATUS_IS_OK( hnd->status ) )
624                 return CAC_FAILURE;
625
626         if ( !cac_InitCacServiceConfig
627              ( mem_ctx, &config_out, &op->out.config ) ) {
628                 hnd->status = NT_STATUS_NO_MEMORY;
629                 return CAC_FAILURE;
630         }
631
632         return CAC_SUCCESS;
633
634 }