2 * Unix SMB/CIFS implementation.
3 * MS-RPC client library implementation (SVCCTL pipe)
4 * Copyright (C) Chris Nicholls 2005.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libsmb_internal.h"
24 #define WAIT_SLEEP_TIME 300000
26 int cac_SvcOpenScm(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcOpenScm
*op
) {
28 struct rpc_pipe_client
*pipe_hnd
= NULL
;
31 POLICY_HND
*scm_out
= NULL
;
36 if(!hnd
->_internal
.ctx
) {
37 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
41 if(!op
|| op
->in
.access
== 0 || !mem_ctx
) {
42 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
46 srv
= cac_GetServer(hnd
);
48 hnd
->status
= NT_STATUS_INVALID_CONNECTION
;
52 /*initialize for samr pipe if we have to*/
53 if(!hnd
->_internal
.pipes
[PI_SVCCTL
]) {
54 if(!(pipe_hnd
= cli_rpc_pipe_open_noauth(&srv
->cli
, PI_SVCCTL
, &(hnd
->status
)))) {
55 hnd
->status
= NT_STATUS_UNSUCCESSFUL
;
59 hnd
->_internal
.pipes
[PI_SVCCTL
] = True
;
62 scm_out
= talloc(mem_ctx
, POLICY_HND
);
64 hnd
->status
= NT_STATUS_NO_MEMORY
;
68 err
= rpccli_svcctl_open_scm( pipe_hnd
, mem_ctx
, scm_out
, op
->in
.access
);
69 hnd
->status
= werror_to_ntstatus(err
);
71 if(!NT_STATUS_IS_OK(hnd
->status
))
74 op
->out
.scm_hnd
= scm_out
;
79 int cac_SvcClose(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, POLICY_HND
*scm_hnd
) {
80 struct rpc_pipe_client
*pipe_hnd
= NULL
;
86 if(!hnd
->_internal
.ctx
) {
87 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
91 if(!scm_hnd
|| !mem_ctx
) {
92 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
96 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
98 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
102 err
= rpccli_svcctl_close_service( pipe_hnd
, mem_ctx
, scm_hnd
);
103 hnd
->status
= werror_to_ntstatus(err
);
105 if(!NT_STATUS_IS_OK(hnd
->status
))
111 int cac_SvcEnumServices(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcEnumServices
*op
) {
112 struct rpc_pipe_client
*pipe_hnd
= NULL
;
116 uint32 state_buf
= 0;
118 uint32 num_svc_out
= 0;
120 ENUM_SERVICES_STATUS
*svc_buf
= NULL
;
125 if(!hnd
->_internal
.ctx
) {
126 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
130 if(!op
|| !op
->in
.scm_hnd
|| !mem_ctx
) {
131 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
135 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
137 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
141 type_buf
= (op
->in
.type
!= 0) ? op
->in
.type
: (SVCCTL_TYPE_DRIVER
| SVCCTL_TYPE_WIN32
);
142 state_buf
= (op
->in
.state
!= 0) ? op
->in
.state
: SVCCTL_STATE_ALL
;
144 err
= rpccli_svcctl_enumerate_services( pipe_hnd
, mem_ctx
, op
->in
.scm_hnd
, type_buf
, state_buf
, &num_svc_out
, &svc_buf
);
145 hnd
->status
= werror_to_ntstatus(err
);
147 if(!NT_STATUS_IS_OK(hnd
->status
))
150 op
->out
.services
= cac_MakeServiceArray(mem_ctx
, svc_buf
, num_svc_out
);
152 if(!op
->out
.services
) {
153 hnd
->status
= NT_STATUS_NO_MEMORY
;
157 TALLOC_FREE(svc_buf
);
159 op
->out
.num_services
= num_svc_out
;
164 int cac_SvcOpenService(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcOpenService
*op
) {
165 struct rpc_pipe_client
*pipe_hnd
= NULL
;
168 POLICY_HND
*svc_hnd_out
= NULL
;
173 if(!hnd
->_internal
.ctx
) {
174 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
178 if(!op
|| !op
->in
.scm_hnd
|| !op
->in
.name
|| !mem_ctx
) {
179 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
183 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
185 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
189 svc_hnd_out
= talloc(mem_ctx
, POLICY_HND
);
191 hnd
->status
= NT_STATUS_NO_MEMORY
;
195 err
= rpccli_svcctl_open_service( pipe_hnd
, mem_ctx
, op
->in
.scm_hnd
, svc_hnd_out
, op
->in
.name
, op
->in
.access
);
196 hnd
->status
= werror_to_ntstatus(err
);
198 if(!NT_STATUS_IS_OK(hnd
->status
))
201 op
->out
.svc_hnd
= svc_hnd_out
;
206 int cac_SvcControlService(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcControlService
*op
) {
207 struct rpc_pipe_client
*pipe_hnd
= NULL
;
210 SERVICE_STATUS status_out
;
215 if(!hnd
->_internal
.ctx
) {
216 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
220 if(!op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
221 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
225 if(op
->in
.control
< SVCCTL_CONTROL_STOP
|| op
->in
.control
> SVCCTL_CONTROL_SHUTDOWN
) {
226 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
230 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
232 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
236 err
= rpccli_svcctl_control_service( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
, op
->in
.control
, &status_out
);
237 hnd
->status
= werror_to_ntstatus(err
);
239 if(!NT_STATUS_IS_OK(hnd
->status
))
245 int cac_SvcGetStatus(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcGetStatus
*op
) {
246 struct rpc_pipe_client
*pipe_hnd
= NULL
;
249 SERVICE_STATUS status_out
;
254 if(!hnd
->_internal
.ctx
) {
255 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
259 if(!op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
260 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
264 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
266 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
270 err
= rpccli_svcctl_query_status( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
, &status_out
);
271 hnd
->status
= werror_to_ntstatus(err
);
273 if(!NT_STATUS_IS_OK(hnd
->status
))
276 op
->out
.status
= status_out
;
283 /*Internal function - similar to code found in utils/net_rpc_service.c
284 * Waits for a service to reach a specific state.
285 * svc_hnd - Handle to the service
286 * state - the state we are waiting for
287 * timeout - number of seconds to wait
288 * returns CAC_FAILURE if the state is never reached
289 * or CAC_SUCCESS if the state is reached
291 int cac_WaitForService(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, POLICY_HND
*svc_hnd
, uint32 state
, uint32 timeout
, SERVICE_STATUS
*status
) {
292 struct rpc_pipe_client
*pipe_hnd
= NULL
;
293 /*number of milliseconds we have spent*/
294 uint32 time_spent
= 0;
297 if(!hnd
|| !mem_ctx
|| !svc_hnd
|| !status
)
300 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
302 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
306 while(status
->state
!= state
&& time_spent
< (timeout
* 1000000) && NT_STATUS_IS_OK(hnd
->status
)) {
307 /*if this is the first call, then we _just_ got the status.. sleep now*/
308 usleep(WAIT_SLEEP_TIME
);
309 time_spent
+= WAIT_SLEEP_TIME
;
311 err
= rpccli_svcctl_query_status(pipe_hnd
, mem_ctx
, svc_hnd
, status
);
312 hnd
->status
= werror_to_ntstatus(err
);
315 if(status
->state
== state
)
321 int cac_SvcStartService(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcStartService
*op
) {
322 struct rpc_pipe_client
*pipe_hnd
= NULL
;
325 SERVICE_STATUS status_buf
;
330 if(!hnd
->_internal
.ctx
) {
331 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
335 if(!op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
336 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
340 if(op
->in
.num_parms
!= 0 && op
->in
.parms
== NULL
) {
341 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
345 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
347 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
351 err
= rpccli_svcctl_start_service(pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
, (const char **)op
->in
.parms
, op
->in
.num_parms
);
352 hnd
->status
= werror_to_ntstatus(err
);
354 if(!NT_STATUS_IS_OK(hnd
->status
))
357 if(op
->in
.timeout
== 0)
360 return cac_WaitForService(hnd
, mem_ctx
, op
->in
.svc_hnd
, SVCCTL_RUNNING
, op
->in
.timeout
, &status_buf
);
363 int cac_SvcStopService(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcStopService
*op
) {
364 struct rpc_pipe_client
*pipe_hnd
= NULL
;
367 SERVICE_STATUS status_out
;
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 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
384 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
388 err
= rpccli_svcctl_control_service( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
, SVCCTL_CONTROL_STOP
, &status_out
);
389 hnd
->status
= werror_to_ntstatus(err
);
391 if(!NT_STATUS_IS_OK(hnd
->status
))
394 op
->out
.status
= status_out
;
396 if(op
->in
.timeout
== 0)
399 return cac_WaitForService(hnd
, mem_ctx
, op
->in
.svc_hnd
, SVCCTL_STOPPED
, op
->in
.timeout
, &op
->out
.status
);
402 int cac_SvcPauseService(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcPauseService
*op
) {
403 struct rpc_pipe_client
*pipe_hnd
= NULL
;
406 SERVICE_STATUS status_out
;
411 if(!hnd
->_internal
.ctx
) {
412 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
416 if(!op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
417 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
421 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
423 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
427 err
= rpccli_svcctl_control_service( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
, SVCCTL_CONTROL_PAUSE
, &status_out
);
428 hnd
->status
= werror_to_ntstatus(err
);
430 if(!NT_STATUS_IS_OK(hnd
->status
))
433 op
->out
.status
= status_out
;
435 if(op
->in
.timeout
== 0)
438 return cac_WaitForService(hnd
, mem_ctx
, op
->in
.svc_hnd
, SVCCTL_PAUSED
, op
->in
.timeout
, &op
->out
.status
);
441 int cac_SvcContinueService(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcContinueService
*op
) {
442 struct rpc_pipe_client
*pipe_hnd
= NULL
;
445 SERVICE_STATUS status_out
;
450 if(!hnd
->_internal
.ctx
) {
451 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
455 if(!op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
456 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
460 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
462 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
466 err
= rpccli_svcctl_control_service( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
, SVCCTL_CONTROL_CONTINUE
, &status_out
);
467 hnd
->status
= werror_to_ntstatus(err
);
469 if(!NT_STATUS_IS_OK(hnd
->status
))
472 op
->out
.status
= status_out
;
474 if(op
->in
.timeout
== 0)
477 return cac_WaitForService(hnd
, mem_ctx
, op
->in
.svc_hnd
, SVCCTL_RUNNING
, op
->in
.timeout
, &op
->out
.status
);
480 int cac_SvcGetDisplayName(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcGetDisplayName
*op
) {
481 struct rpc_pipe_client
*pipe_hnd
= NULL
;
484 fstring disp_name_out
;
489 if(!hnd
->_internal
.ctx
) {
490 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
494 if(!op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
495 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
499 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
501 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
505 err
= rpccli_svcctl_get_dispname( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
, disp_name_out
);
506 hnd
->status
= werror_to_ntstatus(err
);
508 if(!NT_STATUS_IS_OK(hnd
->status
))
511 op
->out
.display_name
= talloc_strdup(mem_ctx
, disp_name_out
);
513 if(!op
->out
.display_name
) {
514 hnd
->status
= NT_STATUS_NO_MEMORY
;
522 int cac_SvcGetServiceConfig(CacServerHandle
*hnd
, TALLOC_CTX
*mem_ctx
, struct SvcGetServiceConfig
*op
) {
523 struct rpc_pipe_client
*pipe_hnd
= NULL
;
526 SERVICE_CONFIG config_out
;
531 if(!hnd
->_internal
.ctx
) {
532 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
536 if(!op
|| !op
->in
.svc_hnd
|| !mem_ctx
) {
537 hnd
->status
= NT_STATUS_INVALID_PARAMETER
;
541 pipe_hnd
= cac_GetPipe(hnd
, PI_SVCCTL
);
543 hnd
->status
= NT_STATUS_INVALID_HANDLE
;
547 err
= rpccli_svcctl_query_config( pipe_hnd
, mem_ctx
, op
->in
.svc_hnd
, &config_out
);
548 hnd
->status
= werror_to_ntstatus(err
);
550 if(!NT_STATUS_IS_OK(hnd
->status
))
553 if(!cac_InitCacServiceConfig(mem_ctx
, &config_out
, &op
->out
.config
)) {
554 hnd
->status
= NT_STATUS_NO_MEMORY
;