Initial import
[samba] / source / libmsrpc / cac_svcctl.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  MS-RPC client library implementation (SVCCTL pipe)
4  *  Copyright (C) Chris Nicholls              2005.
5  *  
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.
10  *  
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.
15  *  
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.
19  */
20
21 #include "libmsrpc.h"
22 #include "libsmb_internal.h"
23
24 #define WAIT_SLEEP_TIME 300000
25
26 int cac_SvcOpenScm(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcOpenScm *op) {
27    SMBCSRV *srv        = NULL;
28    struct rpc_pipe_client *pipe_hnd = NULL;
29    WERROR err;
30
31    POLICY_HND *scm_out = NULL;
32
33    if(!hnd) 
34       return CAC_FAILURE;
35
36    if(!hnd->_internal.ctx) {
37       hnd->status = NT_STATUS_INVALID_HANDLE;
38       return CAC_FAILURE;
39    }
40
41    if(!op || op->in.access == 0 || !mem_ctx) {
42       hnd->status = NT_STATUS_INVALID_PARAMETER;
43       return CAC_FAILURE;
44    }
45    
46    srv = cac_GetServer(hnd);
47    if(!srv) {
48       hnd->status = NT_STATUS_INVALID_CONNECTION;
49       return CAC_FAILURE;
50    }
51
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;
56          return CAC_FAILURE;
57       }
58
59       hnd->_internal.pipes[PI_SVCCTL] = True;
60    }
61
62    scm_out = talloc(mem_ctx, POLICY_HND);
63    if(!scm_out) {
64       hnd->status = NT_STATUS_NO_MEMORY;
65       return CAC_FAILURE;
66    }
67
68    err = rpccli_svcctl_open_scm( pipe_hnd, mem_ctx, scm_out, op->in.access);
69    hnd->status = werror_to_ntstatus(err);
70
71    if(!NT_STATUS_IS_OK(hnd->status))
72       return CAC_FAILURE;
73
74    op->out.scm_hnd = scm_out;
75
76    return CAC_SUCCESS;
77 }
78
79 int cac_SvcClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *scm_hnd) {
80    struct rpc_pipe_client *pipe_hnd        = NULL;
81    WERROR err;
82
83    if(!hnd) 
84       return CAC_FAILURE;
85
86    if(!hnd->_internal.ctx) {
87       hnd->status = NT_STATUS_INVALID_HANDLE;
88       return CAC_FAILURE;
89    }
90
91    if(!scm_hnd || !mem_ctx) {
92       hnd->status = NT_STATUS_INVALID_PARAMETER;
93       return CAC_FAILURE;
94    }
95
96    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
97    if(!pipe_hnd) {
98       hnd->status = NT_STATUS_INVALID_HANDLE;
99       return CAC_FAILURE;
100    }
101
102    err = rpccli_svcctl_close_service( pipe_hnd, mem_ctx, scm_hnd);
103    hnd->status = werror_to_ntstatus(err);
104
105    if(!NT_STATUS_IS_OK(hnd->status))
106       return CAC_FAILURE;
107
108    return CAC_SUCCESS;
109 }
110
111 int cac_SvcEnumServices(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcEnumServices *op) {
112    struct rpc_pipe_client *pipe_hnd        = NULL;
113    WERROR err;
114
115    uint32 type_buf  = 0;
116    uint32 state_buf = 0;
117
118    uint32 num_svc_out = 0;
119
120    ENUM_SERVICES_STATUS *svc_buf = NULL;
121
122    if(!hnd) 
123       return CAC_FAILURE;
124
125    if(!hnd->_internal.ctx) {
126       hnd->status = NT_STATUS_INVALID_HANDLE;
127       return CAC_FAILURE;
128    }
129
130    if(!op || !op->in.scm_hnd || !mem_ctx) {
131       hnd->status = NT_STATUS_INVALID_PARAMETER;
132       return CAC_FAILURE;
133    }
134
135    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
136    if(!pipe_hnd) {
137       hnd->status = NT_STATUS_INVALID_HANDLE;
138       return CAC_FAILURE;
139    }
140
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;
143
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);
146
147    if(!NT_STATUS_IS_OK(hnd->status))
148       return CAC_FAILURE;
149
150    op->out.services = cac_MakeServiceArray(mem_ctx, svc_buf, num_svc_out);
151
152    if(!op->out.services) {
153       hnd->status = NT_STATUS_NO_MEMORY;
154       return CAC_FAILURE;
155    }
156
157    talloc_free(svc_buf);
158
159    op->out.num_services = num_svc_out;
160
161    return CAC_SUCCESS;
162 }
163
164 int cac_SvcOpenService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcOpenService *op) {
165    struct rpc_pipe_client *pipe_hnd        = NULL;
166    WERROR err;
167
168    POLICY_HND *svc_hnd_out = NULL;
169
170    if(!hnd) 
171       return CAC_FAILURE;
172
173    if(!hnd->_internal.ctx) {
174       hnd->status = NT_STATUS_INVALID_HANDLE;
175       return CAC_FAILURE;
176    }
177
178    if(!op || !op->in.scm_hnd || !op->in.name || !mem_ctx) {
179       hnd->status = NT_STATUS_INVALID_PARAMETER;
180       return CAC_FAILURE;
181    }
182
183    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
184    if(!pipe_hnd) {
185       hnd->status = NT_STATUS_INVALID_HANDLE;
186       return CAC_FAILURE;
187    }
188
189    svc_hnd_out = talloc(mem_ctx, POLICY_HND);
190    if(!svc_hnd_out) {
191       hnd->status = NT_STATUS_NO_MEMORY;
192       return CAC_FAILURE;
193    }
194
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);
197
198    if(!NT_STATUS_IS_OK(hnd->status))
199       return CAC_FAILURE;
200
201    op->out.svc_hnd = svc_hnd_out;
202
203    return CAC_SUCCESS;
204 }
205
206 int cac_SvcControlService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcControlService *op) {
207    struct rpc_pipe_client *pipe_hnd        = NULL;
208    WERROR err;
209
210    SERVICE_STATUS status_out;
211
212    if(!hnd) 
213       return CAC_FAILURE;
214
215    if(!hnd->_internal.ctx) {
216       hnd->status = NT_STATUS_INVALID_HANDLE;
217       return CAC_FAILURE;
218    }
219
220    if(!op || !op->in.svc_hnd || !mem_ctx) {
221       hnd->status = NT_STATUS_INVALID_PARAMETER;
222       return CAC_FAILURE;
223    }
224
225    if(op->in.control < SVCCTL_CONTROL_STOP || op->in.control > SVCCTL_CONTROL_SHUTDOWN) {
226       hnd->status = NT_STATUS_INVALID_PARAMETER;
227       return CAC_FAILURE;
228    }
229
230    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
231    if(!pipe_hnd) {
232       hnd->status = NT_STATUS_INVALID_HANDLE;
233       return CAC_FAILURE;
234    }
235
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);
238
239    if(!NT_STATUS_IS_OK(hnd->status))
240       return CAC_FAILURE;
241
242    return CAC_SUCCESS;
243 }
244
245 int cac_SvcGetStatus(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetStatus *op) {
246    struct rpc_pipe_client *pipe_hnd        = NULL;
247    WERROR err;
248
249    SERVICE_STATUS status_out;
250
251    if(!hnd) 
252       return CAC_FAILURE;
253
254    if(!hnd->_internal.ctx) {
255       hnd->status = NT_STATUS_INVALID_HANDLE;
256       return CAC_FAILURE;
257    }
258
259    if(!op || !op->in.svc_hnd || !mem_ctx) {
260       hnd->status = NT_STATUS_INVALID_PARAMETER;
261       return CAC_FAILURE;
262    }
263
264    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
265    if(!pipe_hnd) {
266       hnd->status = NT_STATUS_INVALID_HANDLE;
267       return CAC_FAILURE;
268    }
269
270    err = rpccli_svcctl_query_status( pipe_hnd, mem_ctx, op->in.svc_hnd, &status_out);
271    hnd->status = werror_to_ntstatus(err);
272
273    if(!NT_STATUS_IS_OK(hnd->status))
274       return CAC_FAILURE;
275
276    op->out.status = status_out;
277
278    return CAC_SUCCESS;
279 }
280
281
282
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
290  */
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;
295    WERROR err;
296
297    if(!hnd || !mem_ctx || !svc_hnd || !status)
298       return CAC_FAILURE;
299
300    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
301    if(!pipe_hnd) {
302       hnd->status = NT_STATUS_INVALID_HANDLE;
303       return CAC_FAILURE;
304    }
305
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;
310
311       err = rpccli_svcctl_query_status(pipe_hnd, mem_ctx, svc_hnd, status);
312       hnd->status = werror_to_ntstatus(err);
313    }
314
315    if(status->state == state) 
316       return CAC_SUCCESS;
317
318    return CAC_FAILURE;
319 }
320
321 int cac_SvcStartService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcStartService *op) {
322    struct rpc_pipe_client *pipe_hnd        = NULL;
323    WERROR err;
324
325    SERVICE_STATUS status_buf;
326
327    if(!hnd) 
328       return CAC_FAILURE;
329
330    if(!hnd->_internal.ctx) {
331       hnd->status = NT_STATUS_INVALID_HANDLE;
332       return CAC_FAILURE;
333    }
334
335    if(!op || !op->in.svc_hnd || !mem_ctx) {
336       hnd->status = NT_STATUS_INVALID_PARAMETER;
337       return CAC_FAILURE;
338    }
339
340    if(op->in.num_parms != 0 && op->in.parms == NULL) {
341       hnd->status = NT_STATUS_INVALID_PARAMETER;
342       return CAC_FAILURE;
343    }
344
345    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
346    if(!pipe_hnd) {
347       hnd->status = NT_STATUS_INVALID_HANDLE;
348       return CAC_FAILURE;
349    }
350
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);
353
354    if(!NT_STATUS_IS_OK(hnd->status))
355       return CAC_FAILURE;
356
357    if(op->in.timeout == 0)
358       return CAC_SUCCESS;
359
360    return cac_WaitForService(hnd, mem_ctx, op->in.svc_hnd, SVCCTL_RUNNING, op->in.timeout, &status_buf);
361 }
362
363 int cac_SvcStopService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcStopService *op) {
364    struct rpc_pipe_client *pipe_hnd        = NULL;
365    WERROR err;
366
367    SERVICE_STATUS status_out;
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    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
383    if(!pipe_hnd) {
384       hnd->status = NT_STATUS_INVALID_HANDLE;
385       return CAC_FAILURE;
386    }
387
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);
390
391    if(!NT_STATUS_IS_OK(hnd->status))
392       return CAC_FAILURE;
393
394    op->out.status = status_out;
395
396    if(op->in.timeout == 0)
397       return CAC_SUCCESS;
398
399    return cac_WaitForService(hnd, mem_ctx, op->in.svc_hnd, SVCCTL_STOPPED, op->in.timeout, &op->out.status);
400 }
401
402 int cac_SvcPauseService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcPauseService *op) {
403    struct rpc_pipe_client *pipe_hnd        = NULL;
404    WERROR err;
405
406    SERVICE_STATUS status_out;
407
408    if(!hnd) 
409       return CAC_FAILURE;
410
411    if(!hnd->_internal.ctx) {
412       hnd->status = NT_STATUS_INVALID_HANDLE;
413       return CAC_FAILURE;
414    }
415
416    if(!op || !op->in.svc_hnd || !mem_ctx) {
417       hnd->status = NT_STATUS_INVALID_PARAMETER;
418       return CAC_FAILURE;
419    }
420
421    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
422    if(!pipe_hnd) {
423       hnd->status = NT_STATUS_INVALID_HANDLE;
424       return CAC_FAILURE;
425    }
426
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);
429
430    if(!NT_STATUS_IS_OK(hnd->status))
431       return CAC_FAILURE;
432
433    op->out.status = status_out;
434
435    if(op->in.timeout == 0)
436       return CAC_SUCCESS;
437
438    return cac_WaitForService(hnd, mem_ctx, op->in.svc_hnd, SVCCTL_PAUSED, op->in.timeout, &op->out.status);
439 }
440
441 int cac_SvcContinueService(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcContinueService *op) {
442    struct rpc_pipe_client *pipe_hnd        = NULL;
443    WERROR err;
444
445    SERVICE_STATUS status_out;
446
447    if(!hnd) 
448       return CAC_FAILURE;
449
450    if(!hnd->_internal.ctx) {
451       hnd->status = NT_STATUS_INVALID_HANDLE;
452       return CAC_FAILURE;
453    }
454
455    if(!op || !op->in.svc_hnd || !mem_ctx) {
456       hnd->status = NT_STATUS_INVALID_PARAMETER;
457       return CAC_FAILURE;
458    }
459
460    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
461    if(!pipe_hnd) {
462       hnd->status = NT_STATUS_INVALID_HANDLE;
463       return CAC_FAILURE;
464    }
465
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);
468
469    if(!NT_STATUS_IS_OK(hnd->status))
470       return CAC_FAILURE;
471
472    op->out.status = status_out;
473
474    if(op->in.timeout == 0)
475       return CAC_SUCCESS;
476
477    return cac_WaitForService(hnd, mem_ctx, op->in.svc_hnd, SVCCTL_RUNNING, op->in.timeout, &op->out.status);
478 }
479
480 int cac_SvcGetDisplayName(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetDisplayName *op) {
481    struct rpc_pipe_client *pipe_hnd        = NULL;
482    WERROR err;
483
484    fstring disp_name_out;
485
486    if(!hnd) 
487       return CAC_FAILURE;
488
489    if(!hnd->_internal.ctx) {
490       hnd->status = NT_STATUS_INVALID_HANDLE;
491       return CAC_FAILURE;
492    }
493
494    if(!op || !op->in.svc_hnd || !mem_ctx) {
495       hnd->status = NT_STATUS_INVALID_PARAMETER;
496       return CAC_FAILURE;
497    }
498
499    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
500    if(!pipe_hnd) {
501       hnd->status = NT_STATUS_INVALID_HANDLE;
502       return CAC_FAILURE;
503    }
504
505    err = rpccli_svcctl_get_dispname( pipe_hnd, mem_ctx, op->in.svc_hnd, disp_name_out);
506    hnd->status = werror_to_ntstatus(err);
507
508    if(!NT_STATUS_IS_OK(hnd->status))
509       return CAC_FAILURE;
510
511    op->out.display_name = talloc_strdup(mem_ctx, disp_name_out);
512
513    if(!op->out.display_name) {
514       hnd->status = NT_STATUS_NO_MEMORY;
515       return CAC_FAILURE;
516    }
517
518    return CAC_SUCCESS;
519 }
520
521
522 int cac_SvcGetServiceConfig(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct SvcGetServiceConfig *op) {
523    struct rpc_pipe_client *pipe_hnd        = NULL;
524    WERROR err;
525
526    SERVICE_CONFIG config_out;
527    
528    if(!hnd) 
529       return CAC_FAILURE;
530
531    if(!hnd->_internal.ctx) {
532       hnd->status = NT_STATUS_INVALID_HANDLE;
533       return CAC_FAILURE;
534    }
535
536    if(!op || !op->in.svc_hnd || !mem_ctx) {
537       hnd->status = NT_STATUS_INVALID_PARAMETER;
538       return CAC_FAILURE;
539    }
540
541    pipe_hnd = cac_GetPipe(hnd, PI_SVCCTL);
542    if(!pipe_hnd) {
543       hnd->status = NT_STATUS_INVALID_HANDLE;
544       return CAC_FAILURE;
545    }
546
547    err = rpccli_svcctl_query_config( pipe_hnd, mem_ctx, op->in.svc_hnd, &config_out);
548    hnd->status = werror_to_ntstatus(err);
549
550    if(!NT_STATUS_IS_OK(hnd->status))
551       return CAC_FAILURE;
552
553    if(!cac_InitCacServiceConfig(mem_ctx, &config_out, &op->out.config)) {
554       hnd->status = NT_STATUS_NO_MEMORY;
555       return CAC_FAILURE;
556    }
557
558    return CAC_SUCCESS;
559
560 }