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