3 * Unix SMB/CIFS implementation.
4 * MS-RPC client library implementation (SVCCTL pipe)
5 * Copyright (C) Chris Nicholls 2005.
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.
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.
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.
23 #include "libsmb_internal.h"
25 #define WAIT_SLEEP_TIME 300000
27 int cac_WaitForService( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
28 POLICY_HND
* svc_hnd
, uint32 state
, uint32 timeout
,
29 SERVICE_STATUS
* status
);
31 int cac_SvcOpenScm( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
32 struct SvcOpenScm
*op
)
35 struct rpc_pipe_client
*pipe_hnd
= NULL
;
38 POLICY_HND
*scm_out
= NULL
;
43 if ( !hnd
->_internal
.ctx
) {
44 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
48 if ( !op
|| op
->in
.access
== 0 || !mem_ctx
) {
49 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
53 srv
= cac_GetServer( hnd
);
55 hnd
->status
= NT_STATUS_INVALID_CONNECTION
;
59 /*initialize for samr pipe if we have to */
60 if ( !hnd
->_internal
.pipes
[PI_SVCCTL
] ) {
63 cli_rpc_pipe_open_noauth( srv
->cli
, PI_SVCCTL
,
64 &( hnd
->status
) ) ) ) {
65 hnd
->status
= NT_STATUS_UNSUCCESSFUL
;
69 hnd
->_internal
.pipes
[PI_SVCCTL
] = True
;
72 scm_out
= talloc( mem_ctx
, POLICY_HND
);
74 hnd
->status
= NT_STATUS_NO_MEMORY
;
78 err
= rpccli_svcctl_open_scm( pipe_hnd
, mem_ctx
, scm_out
,
80 hnd
->status
= werror_to_ntstatus( err
);
82 if ( !NT_STATUS_IS_OK( hnd
->status
) )
85 op
->out
.scm_hnd
= scm_out
;
90 int cac_SvcClose( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
91 POLICY_HND
* scm_hnd
)
93 struct rpc_pipe_client
*pipe_hnd
= NULL
;
99 if ( !hnd
->_internal
.ctx
) {
100 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
104 if ( !scm_hnd
|| !mem_ctx
) {
105 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
109 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
111 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
115 err
= rpccli_svcctl_close_service( pipe_hnd
, mem_ctx
, scm_hnd
);
116 hnd
->status
= werror_to_ntstatus( err
);
118 if ( !NT_STATUS_IS_OK( hnd
->status
) )
124 int cac_SvcEnumServices( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
125 struct SvcEnumServices
*op
)
127 struct rpc_pipe_client
*pipe_hnd
= NULL
;
131 uint32 state_buf
= 0;
133 uint32 num_svc_out
= 0;
135 ENUM_SERVICES_STATUS
*svc_buf
= NULL
;
140 if ( !hnd
->_internal
.ctx
) {
141 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
145 if ( !op
|| !op
->in
.scm_hnd
|| !mem_ctx
) {
146 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
150 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
152 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
159 type
: ( SVCCTL_TYPE_DRIVER
| SVCCTL_TYPE_WIN32
);
160 state_buf
= ( op
->in
.state
!= 0 ) ? op
->in
.state
: SVCCTL_STATE_ALL
;
162 err
= rpccli_svcctl_enumerate_services( pipe_hnd
, mem_ctx
,
163 op
->in
.scm_hnd
, type_buf
,
164 state_buf
, &num_svc_out
,
166 hnd
->status
= werror_to_ntstatus( err
);
168 if ( !NT_STATUS_IS_OK( hnd
->status
) )
172 cac_MakeServiceArray( mem_ctx
, svc_buf
, num_svc_out
);
174 if ( !op
->out
.services
) {
175 hnd
->status
= NT_STATUS_NO_MEMORY
;
179 TALLOC_FREE( svc_buf
);
181 op
->out
.num_services
= num_svc_out
;
186 int cac_SvcOpenService( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
187 struct SvcOpenService
*op
)
189 struct rpc_pipe_client
*pipe_hnd
= NULL
;
192 POLICY_HND
*svc_hnd_out
= NULL
;
197 if ( !hnd
->_internal
.ctx
) {
198 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
202 if ( !op
|| !op
->in
.scm_hnd
|| !op
->in
.name
|| !mem_ctx
) {
203 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
207 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
209 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
213 svc_hnd_out
= talloc( mem_ctx
, POLICY_HND
);
214 if ( !svc_hnd_out
) {
215 hnd
->status
= NT_STATUS_NO_MEMORY
;
219 err
= rpccli_svcctl_open_service( pipe_hnd
, mem_ctx
, op
->in
.scm_hnd
,
220 svc_hnd_out
, op
->in
.name
,
222 hnd
->status
= werror_to_ntstatus( err
);
224 if ( !NT_STATUS_IS_OK( hnd
->status
) )
227 op
->out
.svc_hnd
= svc_hnd_out
;
232 int cac_SvcControlService( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
233 struct SvcControlService
*op
)
235 struct rpc_pipe_client
*pipe_hnd
= NULL
;
238 SERVICE_STATUS status_out
;
243 if ( !hnd
->_internal
.ctx
) {
244 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
248 if ( !op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
249 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
253 if ( op
->in
.control
< SVCCTL_CONTROL_STOP
254 || op
->in
.control
> SVCCTL_CONTROL_SHUTDOWN
) {
255 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
259 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
261 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
265 err
= rpccli_svcctl_control_service( pipe_hnd
, mem_ctx
,
266 op
->in
.svc_hnd
, op
->in
.control
,
268 hnd
->status
= werror_to_ntstatus( err
);
270 if ( !NT_STATUS_IS_OK( hnd
->status
) )
276 int cac_SvcGetStatus( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
277 struct SvcGetStatus
*op
)
279 struct rpc_pipe_client
*pipe_hnd
= NULL
;
282 SERVICE_STATUS status_out
;
287 if ( !hnd
->_internal
.ctx
) {
288 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
292 if ( !op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
293 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
297 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
299 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
303 err
= rpccli_svcctl_query_status( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
,
305 hnd
->status
= werror_to_ntstatus( err
);
307 if ( !NT_STATUS_IS_OK( hnd
->status
) )
310 op
->out
.status
= status_out
;
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
325 int cac_WaitForService( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
326 POLICY_HND
* svc_hnd
, uint32 state
, uint32 timeout
,
327 SERVICE_STATUS
* status
)
329 struct rpc_pipe_client
*pipe_hnd
= NULL
;
331 /*number of milliseconds we have spent */
332 uint32 time_spent
= 0;
335 if ( !hnd
|| !mem_ctx
|| !svc_hnd
|| !status
)
338 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
340 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
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
;
350 err
= rpccli_svcctl_query_status( pipe_hnd
, mem_ctx
, svc_hnd
,
352 hnd
->status
= werror_to_ntstatus( err
);
355 if ( status
->state
== state
)
361 int cac_SvcStartService( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
362 struct SvcStartService
*op
)
364 struct rpc_pipe_client
*pipe_hnd
= NULL
;
367 SERVICE_STATUS status_buf
;
372 if ( !hnd
->_internal
.ctx
) {
373 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
377 if ( !op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
378 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
382 if ( op
->in
.num_parms
!= 0 && op
->in
.parms
== NULL
) {
383 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
387 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
389 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
393 err
= rpccli_svcctl_start_service( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
,
394 ( const char ** ) op
->in
.parms
,
396 hnd
->status
= werror_to_ntstatus( err
);
398 if ( !NT_STATUS_IS_OK( hnd
->status
) )
401 if ( op
->in
.timeout
== 0 )
404 return cac_WaitForService( hnd
, mem_ctx
, op
->in
.svc_hnd
,
405 SVCCTL_RUNNING
, op
->in
.timeout
,
409 int cac_SvcStopService( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
410 struct SvcStopService
*op
)
412 struct rpc_pipe_client
*pipe_hnd
= NULL
;
415 SERVICE_STATUS status_out
;
420 if ( !hnd
->_internal
.ctx
) {
421 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
425 if ( !op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
426 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
430 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
432 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
436 err
= rpccli_svcctl_control_service( pipe_hnd
, mem_ctx
,
440 hnd
->status
= werror_to_ntstatus( err
);
442 if ( !NT_STATUS_IS_OK( hnd
->status
) )
445 op
->out
.status
= status_out
;
447 if ( op
->in
.timeout
== 0 )
450 return cac_WaitForService( hnd
, mem_ctx
, op
->in
.svc_hnd
,
451 SVCCTL_STOPPED
, op
->in
.timeout
,
455 int cac_SvcPauseService( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
456 struct SvcPauseService
*op
)
458 struct rpc_pipe_client
*pipe_hnd
= NULL
;
461 SERVICE_STATUS status_out
;
466 if ( !hnd
->_internal
.ctx
) {
467 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
471 if ( !op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
472 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
476 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
478 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
482 err
= rpccli_svcctl_control_service( pipe_hnd
, mem_ctx
,
484 SVCCTL_CONTROL_PAUSE
,
486 hnd
->status
= werror_to_ntstatus( err
);
488 if ( !NT_STATUS_IS_OK( hnd
->status
) )
491 op
->out
.status
= status_out
;
493 if ( op
->in
.timeout
== 0 )
496 return cac_WaitForService( hnd
, mem_ctx
, op
->in
.svc_hnd
,
497 SVCCTL_PAUSED
, op
->in
.timeout
,
501 int cac_SvcContinueService( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
502 struct SvcContinueService
*op
)
504 struct rpc_pipe_client
*pipe_hnd
= NULL
;
507 SERVICE_STATUS status_out
;
512 if ( !hnd
->_internal
.ctx
) {
513 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
517 if ( !op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
518 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
522 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
524 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
528 err
= rpccli_svcctl_control_service( pipe_hnd
, mem_ctx
,
530 SVCCTL_CONTROL_CONTINUE
,
532 hnd
->status
= werror_to_ntstatus( err
);
534 if ( !NT_STATUS_IS_OK( hnd
->status
) )
537 op
->out
.status
= status_out
;
539 if ( op
->in
.timeout
== 0 )
542 return cac_WaitForService( hnd
, mem_ctx
, op
->in
.svc_hnd
,
543 SVCCTL_RUNNING
, op
->in
.timeout
,
547 int cac_SvcGetDisplayName( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
548 struct SvcGetDisplayName
*op
)
550 struct rpc_pipe_client
*pipe_hnd
= NULL
;
553 fstring disp_name_out
;
558 if ( !hnd
->_internal
.ctx
) {
559 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
563 if ( !op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
564 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
568 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
570 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
574 err
= rpccli_svcctl_get_dispname( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
,
576 hnd
->status
= werror_to_ntstatus( err
);
578 if ( !NT_STATUS_IS_OK( hnd
->status
) )
581 op
->out
.display_name
= talloc_strdup( mem_ctx
, disp_name_out
);
583 if ( !op
->out
.display_name
) {
584 hnd
->status
= NT_STATUS_NO_MEMORY
;
592 int cac_SvcGetServiceConfig( CacServerHandle
* hnd
, TALLOC_CTX
* mem_ctx
,
593 struct SvcGetServiceConfig
*op
)
595 struct rpc_pipe_client
*pipe_hnd
= NULL
;
598 SERVICE_CONFIG config_out
;
603 if ( !hnd
->_internal
.ctx
) {
604 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
608 if ( !op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
609 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
613 pipe_hnd
= cac_GetPipe( hnd
, PI_SVCCTL
);
615 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
619 err
= rpccli_svcctl_query_config( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
,
621 hnd
->status
= werror_to_ntstatus( err
);
623 if ( !NT_STATUS_IS_OK( hnd
->status
) )
626 if ( !cac_InitCacServiceConfig
627 ( mem_ctx
, &config_out
, &op
->out
.config
) ) {
628 hnd
->status
= NT_STATUS_NO_MEMORY
;