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