1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Service Control Services (SVCCTL) RPC interface definition.
28 * This interface provides remote access to list SMF services
29 * from a Windows client.
30 *
31 * SVCCTL access is restricted to administrators: members of the
32 * Domain Admins or Administrators groups.
33 */
34
35 #include <stdio.h>
36 #include <strings.h>
37
38 #include <smbsrv/libsmb.h>
39 #include <smbsrv/libmlsvc.h>
40 #include <smbsrv/nmpipes.h>
41 #include <smbsrv/ntifs.h>
42 #include <smbsrv/winsvc.h>
43 #include <smbsrv/ndl/svcctl.ndl>
44 #include <smbsrv/libmlsvc.h>
45
46 #define SVCCTL_SECURITY_BUFSIZE 256
47 #define SVCCTL_ENUMSERVICES_MINBUFSIZE 1024
48
49 #define SVCCTL_OPENSVC_OP_UNIMPLEMENTED(S) \
50 ((S) & SERVICE_CHANGE_CONFIG) || \
51 ((S) & SERVICE_PAUSE_CONTINUE) || \
52 ((S) & SERVICE_START) || \
53 ((S) & SERVICE_STOP) || \
54 ((S) & SERVICE_ENUMERATE_DEPENDENTS)
55
56 typedef union {
57 uint8_t *svc_buf;
58 svc_description_t *svc_desc;
59 svc_failure_actions_t *svc_fac;
60 svc_delayed_auto_start_t *svc_dstart;
61 svc_config_failure_action_t *svc_cfa;
62 } svc_config_rsp_t;
63
64 static int svcctl_s_Close(void *, ndr_xa_t *);
65 static int svcctl_s_ControlService(void *, ndr_xa_t *);
66 static int svcctl_s_DeleteService(void *, ndr_xa_t *);
67 static int svcctl_s_QueryServiceSecurity(void *, ndr_xa_t *);
68 static int svcctl_s_SetServiceSecurity(void *, ndr_xa_t *);
69 static int svcctl_s_OpenManager(void *, ndr_xa_t *);
70 static int svcctl_s_OpenService(void *, ndr_xa_t *);
71 static int svcctl_s_QueryServiceStatus(void *, ndr_xa_t *);
72 static int svcctl_s_QueryServiceConfig(void *, ndr_xa_t *);
73 static int svcctl_s_StartService(void *, ndr_xa_t *);
74 static int svcctl_s_EnumDependentServices(void *, ndr_xa_t *);
75 static int svcctl_s_EnumServicesStatus(void *, ndr_xa_t *);
76 static int svcctl_s_GetServiceDisplayNameW(void *, ndr_xa_t *);
77 static int svcctl_s_GetServiceKeyNameW(void *, ndr_xa_t *);
78 static int svcctl_s_OpenSCManagerA(void *, ndr_xa_t *);
79 static int svcctl_s_OpenServiceA(void *, ndr_xa_t *);
80 static int svcctl_s_EnumServicesStatusA(void *, ndr_xa_t *);
81 static int svcctl_s_QueryServiceConfig2W(void *, ndr_xa_t *);
82 static int svcctl_s_QueryServiceStatusEx(void *, ndr_xa_t *);
83
84 static ndr_stub_table_t svcctl_stub_table[] = {
85 { svcctl_s_Close, SVCCTL_OPNUM_Close },
86 { svcctl_s_ControlService, SVCCTL_OPNUM_ControlService },
87 { svcctl_s_DeleteService, SVCCTL_OPNUM_DeleteService },
88 { svcctl_s_QueryServiceSecurity, SVCCTL_OPNUM_QueryServiceSecurity },
89 { svcctl_s_SetServiceSecurity, SVCCTL_OPNUM_SetServiceSecurity },
90 { svcctl_s_OpenManager, SVCCTL_OPNUM_OpenManager },
91 { svcctl_s_OpenService, SVCCTL_OPNUM_OpenService },
92 { svcctl_s_QueryServiceStatus, SVCCTL_OPNUM_QueryServiceStatus },
93 { svcctl_s_QueryServiceConfig, SVCCTL_OPNUM_QueryServiceConfig },
94 { svcctl_s_StartService, SVCCTL_OPNUM_StartService },
95 { svcctl_s_EnumDependentServices,
96 SVCCTL_OPNUM_EnumDependentServices },
97 { svcctl_s_EnumServicesStatus, SVCCTL_OPNUM_EnumServicesStatus },
98 { svcctl_s_GetServiceDisplayNameW,
99 SVCCTL_OPNUM_GetServiceDisplayNameW },
100 { svcctl_s_GetServiceKeyNameW, SVCCTL_OPNUM_GetServiceKeyNameW },
101 { svcctl_s_OpenSCManagerA, SVCCTL_OPNUM_OpenSCManagerA },
102 { svcctl_s_OpenServiceA, SVCCTL_OPNUM_OpenServiceA },
103 { svcctl_s_EnumServicesStatusA, SVCCTL_OPNUM_EnumServicesStatusA },
104 { svcctl_s_QueryServiceConfig2W, SVCCTL_OPNUM_QueryServiceConfig2W },
105 { svcctl_s_QueryServiceStatusEx, SVCCTL_OPNUM_QueryServiceStatusEx },
106 {0}
107 };
108
109 static ndr_service_t svcctl_service = {
110 "SVCCTL", /* name */
111 "Service Control Services", /* desc */
112 "\\svcctl", /* endpoint */
113 PIPE_NTSVCS, /* sec_addr_port */
114 "367abb81-9844-35f1-ad32-98f038001003", 2, /* abstract */
115 NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */
116 0, /* no bind_instance_size */
117 0, /* no bind_req() */
118 0, /* no unbind_and_close() */
119 0, /* use generic_call_stub() */
120 &TYPEINFO(svcctl_interface), /* interface ti */
121 svcctl_stub_table /* stub_table */
122 };
123
124 /*
125 * svcctl_initialize
126 *
127 * This function registers the SVCCTL RPC interface with the RPC runtime
128 * library. It must be called in order to use either the client side
129 * or the server side functions.
130 */
131 void
svcctl_initialize(void)132 svcctl_initialize(void)
133 {
134 (void) ndr_svc_register(&svcctl_service);
135 svcctl_init();
136 }
137
138 void
svcctl_finalize(void)139 svcctl_finalize(void)
140 {
141 svcctl_fini();
142 }
143
144 /*
145 * svcctl_hdlookup
146 *
147 * Handle lookup wrapper to validate the local service and/or manager context.
148 */
149 static ndr_handle_t *
svcctl_hdlookup(ndr_xa_t * mxa,ndr_hdid_t * id,svcctl_context_type_t type)150 svcctl_hdlookup(ndr_xa_t *mxa, ndr_hdid_t *id, svcctl_context_type_t type)
151 {
152 ndr_handle_t *hd;
153 svcctl_context_t *ctx;
154
155 if ((hd = ndr_hdlookup(mxa, id)) == NULL)
156 return (NULL);
157
158 if ((ctx = (svcctl_context_t *)hd->nh_data) == NULL)
159 return (NULL);
160
161 if ((ctx->c_type != type) || (ctx->c_ctx.uc_cp == NULL))
162 return (NULL);
163
164 return (hd);
165 }
166
167 /*
168 * svcctl_hdfree
169 *
170 * Handle deallocation wrapper to free the local service and/or manager context.
171 */
172 static void
svcctl_hdfree(ndr_xa_t * mxa,ndr_hdid_t * id)173 svcctl_hdfree(ndr_xa_t *mxa, ndr_hdid_t *id)
174 {
175 ndr_handle_t *hd;
176 svcctl_context_t *ctx;
177 svcctl_manager_context_t *mgr_ctx;
178 svcctl_service_context_t *svc_ctx;
179
180 if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
181 ctx = (svcctl_context_t *)hd->nh_data;
182
183 switch (ctx->c_type) {
184 case SVCCTL_MANAGER_CONTEXT:
185 mgr_ctx = ctx->c_ctx.uc_mgr;
186 svcctl_scm_fini(mgr_ctx);
187 svcctl_scm_scf_handle_fini(mgr_ctx);
188 free(mgr_ctx);
189 break;
190
191 case SVCCTL_SERVICE_CONTEXT:
192 svc_ctx = ctx->c_ctx.uc_svc;
193 free(svc_ctx->sc_mgrid);
194 free(svc_ctx->sc_svcname);
195 free(svc_ctx);
196 break;
197
198 default:
199 break;
200 }
201
202 free(ctx);
203 ndr_hdfree(mxa, id);
204 }
205 }
206
207 /*
208 * svcctl_mgr_hdalloc
209 *
210 * Handle allocation wrapper to setup the local manager context.
211 */
212 static ndr_hdid_t *
svcctl_mgr_hdalloc(ndr_xa_t * mxa)213 svcctl_mgr_hdalloc(ndr_xa_t *mxa)
214 {
215 svcctl_context_t *ctx;
216 svcctl_manager_context_t *mgr_ctx;
217
218 if ((ctx = malloc(sizeof (svcctl_context_t))) == NULL)
219 return (NULL);
220 ctx->c_type = SVCCTL_MANAGER_CONTEXT;
221
222 if ((mgr_ctx = malloc(sizeof (svcctl_manager_context_t))) == NULL) {
223 free(ctx);
224 return (NULL);
225 }
226 bzero(mgr_ctx, sizeof (svcctl_manager_context_t));
227
228 if (svcctl_scm_scf_handle_init(mgr_ctx) < 0) {
229 free(mgr_ctx);
230 free(ctx);
231 return (NULL);
232 }
233
234 if (svcctl_scm_init(mgr_ctx) < 0) {
235 svcctl_scm_scf_handle_fini(mgr_ctx);
236 free(mgr_ctx);
237 free(ctx);
238 return (NULL);
239 }
240
241 ctx->c_ctx.uc_mgr = mgr_ctx;
242
243 return (ndr_hdalloc(mxa, ctx));
244 }
245
246 /*
247 * svcctl_get_mgr_ctx
248 *
249 * This function looks up a reference to local manager context.
250 */
251 static svcctl_manager_context_t *
svcctl_get_mgr_ctx(ndr_xa_t * mxa,ndr_hdid_t * mgr_id)252 svcctl_get_mgr_ctx(ndr_xa_t *mxa, ndr_hdid_t *mgr_id)
253 {
254 ndr_handle_t *hd;
255 svcctl_manager_context_t *mgr_ctx;
256
257 hd = svcctl_hdlookup(mxa, mgr_id, SVCCTL_MANAGER_CONTEXT);
258 if (hd == NULL)
259 return (NULL);
260
261 mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
262
263 return (mgr_ctx);
264 }
265
266 /*
267 * svcctl_svc_hdalloc
268 *
269 * Handle allocation wrapper to setup the local service context.
270 */
271 static ndr_hdid_t *
svcctl_svc_hdalloc(ndr_xa_t * mxa,ndr_hdid_t * mgr_id,char * svc_name)272 svcctl_svc_hdalloc(ndr_xa_t *mxa, ndr_hdid_t *mgr_id, char *svc_name)
273 {
274 svcctl_context_t *ctx;
275 svcctl_service_context_t *svc_ctx;
276 svcctl_manager_context_t *mgr_ctx;
277 int max_name_sz = 0;
278 char *svcname;
279
280 mgr_ctx = svcctl_get_mgr_ctx(mxa, mgr_id);
281 if (mgr_ctx == NULL)
282 return (NULL);
283 max_name_sz = mgr_ctx->mc_scf_max_fmri_len;
284
285 if ((ctx = malloc(sizeof (svcctl_context_t))) == NULL) {
286 svcctl_hdfree(mxa, mgr_id);
287 return (NULL);
288 }
289 ctx->c_type = SVCCTL_SERVICE_CONTEXT;
290
291 if ((svc_ctx = malloc(sizeof (svcctl_service_context_t))) == NULL) {
292 svcctl_hdfree(mxa, mgr_id);
293 free(ctx);
294 return (NULL);
295 }
296 bzero(svc_ctx, sizeof (svcctl_service_context_t));
297
298 svc_ctx->sc_mgrid = malloc(sizeof (ndr_hdid_t));
299 svcname = malloc(max_name_sz);
300
301 if ((svc_ctx->sc_mgrid == NULL) || (svcname == NULL)) {
302 free(svc_ctx->sc_mgrid);
303 free(svc_ctx);
304 svcctl_hdfree(mxa, mgr_id);
305 free(ctx);
306 return (NULL);
307 }
308
309 svc_ctx->sc_svcname = svcname;
310
311 bcopy(mgr_id, svc_ctx->sc_mgrid, sizeof (ndr_hdid_t));
312 (void) strlcpy(svc_ctx->sc_svcname, svc_name, max_name_sz);
313
314 ctx->c_ctx.uc_svc = svc_ctx;
315
316 return (ndr_hdalloc(mxa, ctx));
317 }
318
319 /*
320 * svcctl_s_Close
321 *
322 * This is a request to close the SVCCTL interface specified by the
323 * handle. Free the handle and zero out the result handle for the
324 * client.
325 *
326 * Returns:
327 * ERROR_SUCCESS
328 * ERROR_INVALID_HANDLE
329 */
330 static int
svcctl_s_Close(void * arg,ndr_xa_t * mxa)331 svcctl_s_Close(void *arg, ndr_xa_t *mxa)
332 {
333 struct svcctl_Close *param = arg;
334 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
335
336 svcctl_hdfree(mxa, id);
337
338 bzero(¶m->result_handle, sizeof (svcctl_handle_t));
339 param->status = ERROR_SUCCESS;
340 return (NDR_DRC_OK);
341 }
342
343 /*
344 * svcctl_s_ControlService
345 */
346 static int
svcctl_s_ControlService(void * arg,ndr_xa_t * mxa)347 svcctl_s_ControlService(void *arg, ndr_xa_t *mxa)
348 {
349 struct svcctl_ControlService *param = arg;
350 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
351 ndr_handle_t *hd;
352 svcctl_manager_context_t *mgr_ctx;
353 svcctl_service_context_t *svc_ctx;
354 svcctl_svc_node_t *svc;
355
356 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
357 if (hd == NULL) {
358 bzero(param, sizeof (struct svcctl_ControlService));
359 param->status = ERROR_INVALID_HANDLE;
360 return (NDR_DRC_OK);
361 }
362
363 svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
364 mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
365 if (mgr_ctx == NULL) {
366 bzero(param, sizeof (struct svcctl_ControlService));
367 param->status = ERROR_INVALID_HANDLE;
368 return (NDR_DRC_OK);
369 }
370
371 switch (param->control) {
372 case SERVICE_CONTROL_STOP:
373 case SERVICE_CONTROL_PAUSE:
374 case SERVICE_CONTROL_CONTINUE:
375 case SERVICE_CONTROL_INTERROGATE:
376 case SERVICE_CONTROL_SHUTDOWN:
377 case SERVICE_CONTROL_PARAMCHANGE:
378 case SERVICE_CONTROL_NETBINDADD:
379 case SERVICE_CONTROL_NETBINDREMOVE:
380 case SERVICE_CONTROL_NETBINDENABLE:
381 case SERVICE_CONTROL_NETBINDDISABLE:
382 break;
383 default:
384 bzero(param, sizeof (struct svcctl_ControlService));
385 param->status = ERROR_INVALID_PARAMETER;
386 return (NDR_DRC_OK);
387 }
388
389 svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
390 if (svc == NULL || svc->sn_state == NULL) {
391 bzero(param, sizeof (struct svcctl_ControlService));
392 param->status = ERROR_SERVICE_DOES_NOT_EXIST;
393 return (NDR_DRC_OK);
394 }
395
396 param->service_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
397 param->service_status.cur_state = svcctl_scm_map_status(svc->sn_state);
398 param->service_status.ctrl_accepted = 0;
399 param->service_status.w32_exitcode = 0;
400 param->service_status.svc_specified_exitcode = 0;
401 param->service_status.check_point = 0;
402 param->service_status.wait_hint = 0;
403
404 param->status = ERROR_SUCCESS;
405 return (NDR_DRC_OK);
406 }
407
408 /*
409 * svcctl_s_DeleteService
410 */
411 static int
svcctl_s_DeleteService(void * arg,ndr_xa_t * mxa)412 svcctl_s_DeleteService(void *arg, ndr_xa_t *mxa)
413 {
414 struct svcctl_DeleteService *param = arg;
415 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
416 ndr_handle_t *hd;
417
418 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
419 if (hd == NULL) {
420 param->status = ERROR_INVALID_HANDLE;
421 return (NDR_DRC_OK);
422 }
423
424 param->status = ERROR_SUCCESS;
425 return (NDR_DRC_OK);
426 }
427
428 /*
429 * svcctl_s_QueryServiceSecurity
430 */
431 static int
svcctl_s_QueryServiceSecurity(void * arg,ndr_xa_t * mxa)432 svcctl_s_QueryServiceSecurity(void *arg, ndr_xa_t *mxa)
433 {
434 struct svcctl_QueryServiceSecurity *param = arg;
435 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
436 ndr_handle_t *hd;
437 uint32_t sec_info;
438 uint32_t bytes_needed = 0;
439 uint32_t status;
440
441 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
442 if (hd == NULL) {
443 status = ERROR_INVALID_HANDLE;
444 goto query_service_security_error;
445 }
446
447 sec_info = param->security_info & SMB_ALL_SECINFO;
448 if (sec_info == 0) {
449 status = ERROR_INVALID_PARAMETER;
450 goto query_service_security_error;
451 }
452
453 if (param->buf_size < SVCCTL_SECURITY_BUFSIZE) {
454 bytes_needed = SVCCTL_SECURITY_BUFSIZE;
455 status = ERROR_INSUFFICIENT_BUFFER;
456 goto query_service_security_error;
457 }
458
459 param->buffer = NDR_MALLOC(mxa, SVCCTL_SECURITY_BUFSIZE);
460 if (param->buffer == NULL) {
461 status = ERROR_NOT_ENOUGH_MEMORY;
462 goto query_service_security_error;
463 }
464
465 bzero(param->buffer, sizeof (SVCCTL_SECURITY_BUFSIZE));
466 param->buf_size = SVCCTL_SECURITY_BUFSIZE;
467 param->bytes_needed = 0;
468 param->status = ERROR_SUCCESS;
469 return (NDR_DRC_OK);
470
471 query_service_security_error:
472 bzero(param, sizeof (struct svcctl_QueryServiceSecurity));
473 param->buf_size = 0;
474 param->buffer = NDR_MALLOC(mxa, sizeof (uint32_t));
475 param->bytes_needed = bytes_needed;
476 param->status = status;
477 return (NDR_DRC_OK);
478 }
479
480
481 /*
482 * svcctl_s_SetServiceSecurity
483 */
484 static int
svcctl_s_SetServiceSecurity(void * arg,ndr_xa_t * mxa)485 svcctl_s_SetServiceSecurity(void *arg, ndr_xa_t *mxa)
486 {
487 struct svcctl_SetServiceSecurity *param = arg;
488 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
489 ndr_handle_t *hd;
490
491 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
492 if (hd == NULL) {
493 param->status = ERROR_INVALID_HANDLE;
494 return (NDR_DRC_OK);
495 }
496
497 if ((param->security_info & SMB_ALL_SECINFO) == 0) {
498 param->status = ERROR_INVALID_PARAMETER;
499 return (NDR_DRC_OK);
500 }
501
502 param->status = ERROR_ACCESS_DENIED;
503 return (NDR_DRC_OK);
504 }
505
506 /*
507 * svcctl_s_OpenManager
508 *
509 * Request to open the service control manager.
510 * The caller must have administrator rights in order to open this
511 * interface. We don't support write (SC_MANAGER_LOCK) access.
512 *
513 * Returns:
514 * ERROR_SUCCESS
515 * ERROR_ACCESS_DENIED
516 *
517 * On success, returns a handle for use with subsequent svcctl requests.
518 */
519 static int
svcctl_s_OpenManager(void * arg,ndr_xa_t * mxa)520 svcctl_s_OpenManager(void *arg, ndr_xa_t *mxa)
521 {
522 struct svcctl_OpenManager *param = arg;
523 ndr_hdid_t *id = NULL;
524 int rc;
525
526 rc = ndr_is_admin(mxa);
527
528 if ((rc == 0) || (param->desired_access & SC_MANAGER_LOCK) != 0) {
529 bzero(¶m->handle, sizeof (svcctl_handle_t));
530 param->status = ERROR_ACCESS_DENIED;
531 return (NDR_DRC_OK);
532 }
533
534 id = svcctl_mgr_hdalloc(mxa);
535 if (id) {
536 bcopy(id, ¶m->handle, sizeof (svcctl_handle_t));
537 param->status = ERROR_SUCCESS;
538 } else {
539 bzero(¶m->handle, sizeof (svcctl_handle_t));
540 param->status = ERROR_ACCESS_DENIED;
541 }
542
543 return (NDR_DRC_OK);
544 }
545
546 /*
547 * svcctl_s_OpenService
548 *
549 * Return a handle for use with subsequent svcctl requests.
550 *
551 * Returns:
552 * ERROR_SUCCESS
553 * ERROR_INVALID_HANDLE
554 * ERROR_SERVICE_DOES_NOT_EXIST
555 * ERROR_CALL_NOT_IMPLEMENTED
556 */
557 static int
svcctl_s_OpenService(void * arg,ndr_xa_t * mxa)558 svcctl_s_OpenService(void *arg, ndr_xa_t *mxa)
559 {
560 struct svcctl_OpenService *param = arg;
561 ndr_hdid_t *mgrid = (ndr_hdid_t *)¶m->manager_handle;
562 ndr_hdid_t *id = NULL;
563 ndr_handle_t *hd;
564 DWORD status;
565 svcctl_manager_context_t *mgr_ctx;
566 char *svc_name = (char *)param->service_name;
567 boolean_t unimplemented_operations = B_FALSE;
568
569 /* Allow service handle allocations for only status & config queries */
570 unimplemented_operations =
571 SVCCTL_OPENSVC_OP_UNIMPLEMENTED(param->desired_access);
572
573 if (unimplemented_operations) {
574 bzero(¶m->service_handle, sizeof (svcctl_handle_t));
575 param->status = ERROR_CALL_NOT_IMPLEMENTED;
576 return (NDR_DRC_OK);
577 }
578
579 hd = svcctl_hdlookup(mxa, mgrid, SVCCTL_MANAGER_CONTEXT);
580 if (hd == NULL) {
581 bzero(¶m->service_handle, sizeof (svcctl_handle_t));
582 param->status = ERROR_INVALID_HANDLE;
583 return (NDR_DRC_OK);
584 }
585
586 mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
587 status = svcctl_scm_validate_service(mgr_ctx, svc_name);
588 if (status != ERROR_SUCCESS) {
589 bzero(¶m->service_handle, sizeof (svcctl_handle_t));
590 param->status = status;
591 return (NDR_DRC_OK);
592 }
593
594 id = svcctl_svc_hdalloc(mxa, mgrid, svc_name);
595 if (id) {
596 bcopy(id, ¶m->service_handle, sizeof (svcctl_handle_t));
597 param->status = ERROR_SUCCESS;
598 } else {
599 bzero(¶m->service_handle, sizeof (svcctl_handle_t));
600 param->status = ERROR_ACCESS_DENIED;
601 }
602
603 return (NDR_DRC_OK);
604 }
605
606 /*
607 * svcctl_s_QueryServiceStatus
608 *
609 * Returns:
610 * ERROR_SUCCESS
611 * ERROR_INVALID_HANDLE
612 */
613 static int
svcctl_s_QueryServiceStatus(void * arg,ndr_xa_t * mxa)614 svcctl_s_QueryServiceStatus(void *arg, ndr_xa_t *mxa)
615 {
616 struct svcctl_QueryServiceStatus *param = arg;
617 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
618 ndr_handle_t *hd;
619 svcctl_manager_context_t *mgr_ctx;
620 svcctl_service_context_t *svc_ctx;
621 svcctl_svc_node_t *svc;
622
623 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
624 if (hd == NULL) {
625 bzero(param, sizeof (struct svcctl_QueryServiceStatus));
626 param->status = ERROR_INVALID_HANDLE;
627 return (NDR_DRC_OK);
628 }
629
630 svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
631 mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
632 if (mgr_ctx == NULL) {
633 bzero(param, sizeof (struct svcctl_QueryServiceStatus));
634 param->status = ERROR_INVALID_HANDLE;
635 return (NDR_DRC_OK);
636 }
637
638 svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
639 if (svc == NULL || svc->sn_state == NULL) {
640 bzero(param, sizeof (struct svcctl_QueryServiceStatus));
641 param->status = ERROR_SERVICE_DOES_NOT_EXIST;
642 return (NDR_DRC_OK);
643 }
644
645 param->service_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
646 param->service_status.cur_state = svcctl_scm_map_status(svc->sn_state);
647 param->service_status.ctrl_accepted = 0;
648 param->service_status.w32_exitcode = 0;
649 param->service_status.svc_specified_exitcode = 0;
650 param->service_status.check_point = 0;
651 param->service_status.wait_hint = 0;
652
653 param->status = ERROR_SUCCESS;
654 return (NDR_DRC_OK);
655 }
656
657 /*
658 * svcctl_s_EnumDependentServices
659 *
660 * Enumerate the list of services that depend on the specified service.
661 */
662 static int
svcctl_s_EnumDependentServices(void * arg,ndr_xa_t * mxa)663 svcctl_s_EnumDependentServices(void *arg, ndr_xa_t *mxa)
664 {
665 struct svcctl_EnumDependentServices *param = arg;
666 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
667 ndr_handle_t *hd;
668 svcctl_manager_context_t *mgr_ctx;
669 svcctl_service_context_t *svc_ctx;
670 svcctl_svc_node_t *svc;
671 int input_bufsize = 0;
672 uint32_t status;
673
674 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
675 if (hd == NULL) {
676 status = ERROR_INVALID_HANDLE;
677 goto enum_dependent_services_error;
678 }
679
680 svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
681 mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
682 if (mgr_ctx == NULL) {
683 status = ERROR_INVALID_HANDLE;
684 goto enum_dependent_services_error;
685 }
686
687 svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
688 if (svc == NULL || svc->sn_state == NULL) {
689 status = ERROR_SERVICE_DOES_NOT_EXIST;
690 goto enum_dependent_services_error;
691 }
692
693 switch (param->svc_state) {
694 case SERVICE_STOPPED:
695 case SERVICE_START_PENDING:
696 case SERVICE_STOP_PENDING:
697 case SERVICE_RUNNING:
698 case SERVICE_CONTINUE_PENDING:
699 case SERVICE_PAUSE_PENDING:
700 case SERVICE_PAUSED:
701 break;
702 default:
703 status = ERROR_INVALID_PARAMETER;
704 goto enum_dependent_services_error;
705 }
706
707 if ((input_bufsize = param->buf_size) == 0) {
708 bzero(param, sizeof (struct svcctl_EnumDependentServices));
709 param->buf_size = input_bufsize;
710 param->services = NDR_STRDUP(mxa, "");
711 param->bytes_needed = 1024;
712 param->svc_num = 0;
713 param->status = ERROR_MORE_DATA;
714 return (NDR_DRC_OK);
715 }
716
717 param->services = NDR_MALLOC(mxa, input_bufsize);
718 if (param->services == NULL) {
719 status = ERROR_NOT_ENOUGH_MEMORY;
720 goto enum_dependent_services_error;
721 }
722
723 bzero(param->services, input_bufsize);
724 param->buf_size = input_bufsize;
725 param->bytes_needed = 0;
726 param->svc_num = 0;
727 param->status = ERROR_SUCCESS;
728 return (NDR_DRC_OK);
729
730 enum_dependent_services_error:
731 bzero(param, sizeof (struct svcctl_EnumDependentServices));
732 param->services = NDR_STRDUP(mxa, "");
733 param->status = status;
734 return (NDR_DRC_OK);
735 }
736
737 /*
738 * svcctl_s_EnumServicesStatus
739 *
740 * Enumerate the list of services we support.
741 */
742 static int
svcctl_s_EnumServicesStatus(void * arg,ndr_xa_t * mxa)743 svcctl_s_EnumServicesStatus(void *arg, ndr_xa_t *mxa)
744 {
745 struct svcctl_EnumServicesStatus *param = arg;
746 ndr_hdid_t *id = (ndr_hdid_t *)¶m->manager_handle;
747 ndr_handle_t *hd;
748 svcctl_manager_context_t *mgr_ctx;
749 uint32_t buf_size = 0;
750 uint32_t svc_num;
751 uint32_t resume_handle = 0;
752 uint32_t status;
753
754 if (param->resume_handle != NULL)
755 resume_handle = *param->resume_handle;
756
757 hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
758 if (hd == NULL) {
759 status = ERROR_INVALID_HANDLE;
760 goto enum_services_status_error;
761 }
762
763 mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
764 if (svcctl_scm_refresh(mgr_ctx) != 0) {
765 status = ERROR_INVALID_HANDLE;
766 goto enum_services_status_error;
767 }
768
769 buf_size = param->buf_size;
770 param->services = NDR_MALLOC(mxa, buf_size);
771 if (param->services == NULL) {
772 status = ERROR_NOT_ENOUGH_MEMORY;
773 goto enum_services_status_error;
774 }
775 bzero(param->services, buf_size);
776
777 if (buf_size < SVCCTL_ENUMSERVICES_MINBUFSIZE) {
778 param->bytes_needed = mgr_ctx->mc_bytes_needed;
779 param->svc_num = 0;
780 if (param->resume_handle)
781 *param->resume_handle = 0;
782 param->status = ERROR_MORE_DATA;
783 return (NDR_DRC_OK);
784 }
785
786 svc_num = svcctl_scm_enum_services(mgr_ctx, param->services,
787 buf_size, &resume_handle, B_TRUE);
788
789 param->buf_size = buf_size;
790 param->svc_num = svc_num;
791
792 if (resume_handle != 0) {
793 if (param->resume_handle != NULL)
794 *param->resume_handle = resume_handle;
795 param->bytes_needed = mgr_ctx->mc_bytes_needed;
796 param->status = ERROR_MORE_DATA;
797 } else {
798 if (param->resume_handle)
799 *param->resume_handle = 0;
800 param->bytes_needed = 0;
801 param->status = ERROR_SUCCESS;
802 }
803 return (NDR_DRC_OK);
804
805 enum_services_status_error:
806 bzero(param, sizeof (struct svcctl_EnumServicesStatus));
807 param->services = NDR_STRDUP(mxa, "");
808 param->status = status;
809 return (NDR_DRC_OK);
810 }
811
812 /*
813 * svcctl_s_QueryServiceConfig
814 *
815 * Returns:
816 * ERROR_SUCCESS
817 * ERROR_INVALID_HANDLE
818 */
819 static int
svcctl_s_QueryServiceConfig(void * arg,ndr_xa_t * mxa)820 svcctl_s_QueryServiceConfig(void *arg, ndr_xa_t *mxa)
821 {
822 struct svcctl_QueryServiceConfig *param = arg;
823 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
824 ndr_handle_t *hd;
825 svcctl_manager_context_t *mgr_ctx;
826 svcctl_service_context_t *svc_ctx;
827 svcctl_svc_node_t *svc;
828 int bytes_needed = 0;
829 svc_config_t *cfg;
830
831 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
832 if (hd == NULL) {
833 bzero(param, sizeof (struct svcctl_QueryServiceConfig));
834 param->status = ERROR_INVALID_HANDLE;
835 return (NDR_DRC_OK);
836 }
837
838 svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
839 mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
840 if (mgr_ctx == NULL) {
841 bzero(param, sizeof (struct svcctl_QueryServiceConfig));
842 param->status = ERROR_INVALID_HANDLE;
843 return (NDR_DRC_OK);
844 }
845
846 svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
847 if (svc == NULL || svc->sn_fmri == NULL) {
848 bzero(param, sizeof (struct svcctl_QueryServiceConfig));
849 param->status = ERROR_SERVICE_DOES_NOT_EXIST;
850 return (NDR_DRC_OK);
851 }
852
853 cfg = ¶m->service_cfg;
854 cfg->service_type = SERVICE_WIN32_SHARE_PROCESS;
855 cfg->start_type = SERVICE_AUTO_START;
856 cfg->error_control = SERVICE_ERROR_IGNORE;
857 cfg->binary_pathname = NDR_STRDUP(mxa, "");
858 cfg->loadorder_group = NDR_STRDUP(mxa, "");
859 cfg->tag_id = 0;
860 cfg->dependencies = NDR_STRDUP(mxa, "");
861 cfg->service_startname = NDR_STRDUP(mxa, "");
862 cfg->display_name = NDR_STRDUP(mxa, svc->sn_fmri);
863
864 bytes_needed = sizeof (svc_config_t);
865 bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->binary_pathname);
866 bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->loadorder_group);
867 bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->dependencies);
868 bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->service_startname);
869 bytes_needed += SVCCTL_WNSTRLEN(svc->sn_fmri);
870
871 if (param->buf_size < bytes_needed) {
872 bzero(param, sizeof (struct svcctl_QueryServiceConfig));
873 param->cfg_bytes = bytes_needed;
874 param->status = ERROR_INSUFFICIENT_BUFFER;
875 return (NDR_DRC_OK);
876 }
877
878 param->cfg_bytes = bytes_needed;
879 param->status = ERROR_SUCCESS;
880 return (NDR_DRC_OK);
881 }
882
883 /*
884 * svcctl_s_StartService
885 */
886 static int
svcctl_s_StartService(void * arg,ndr_xa_t * mxa)887 svcctl_s_StartService(void *arg, ndr_xa_t *mxa)
888 {
889 struct svcctl_StartService *param = arg;
890 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
891 ndr_handle_t *hd;
892 svcctl_manager_context_t *mgr_ctx;
893 svcctl_service_context_t *svc_ctx;
894 svcctl_svc_node_t *svc;
895
896 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
897 if (hd == NULL) {
898 param->status = ERROR_INVALID_HANDLE;
899 return (NDR_DRC_OK);
900 }
901
902 svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
903 mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
904 if (mgr_ctx == NULL) {
905 param->status = ERROR_INVALID_HANDLE;
906 return (NDR_DRC_OK);
907 }
908
909 svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
910 if (svc == NULL || svc->sn_fmri == NULL)
911 param->status = ERROR_SERVICE_DOES_NOT_EXIST;
912 else
913 param->status = ERROR_SERVICE_ALREADY_RUNNING;
914 return (NDR_DRC_OK);
915 }
916
917
918 /*
919 * svcctl_s_GetServiceDisplayNameW
920 *
921 * Returns:
922 * ERROR_SUCCESS
923 * ERROR_INVALID_HANDLE
924 * ERROR_SERVICE_DOES_NOT_EXIST
925 */
926 static int
svcctl_s_GetServiceDisplayNameW(void * arg,ndr_xa_t * mxa)927 svcctl_s_GetServiceDisplayNameW(void *arg, ndr_xa_t *mxa)
928 {
929 struct svcctl_GetServiceDisplayNameW *param = arg;
930 ndr_hdid_t *id = (ndr_hdid_t *)¶m->manager_handle;
931 ndr_handle_t *hd;
932 svcctl_svc_node_t *svc;
933 svcctl_manager_context_t *mgr_ctx;
934
935 hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
936 if (hd == NULL) {
937 bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
938 param->display_name = NDR_STRDUP(mxa, "");
939 param->status = ERROR_INVALID_HANDLE;
940 return (NDR_DRC_OK);
941 }
942
943 mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
944 svc = svcctl_scm_find_service(mgr_ctx, (char *)param->service_name);
945 if (svc == NULL || svc->sn_fmri == NULL) {
946 bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
947 param->display_name = NDR_STRDUP(mxa, "");
948 param->status = ERROR_SERVICE_DOES_NOT_EXIST;
949 return (NDR_DRC_OK);
950 }
951
952 param->display_name = NDR_STRDUP(mxa, svc->sn_fmri);
953 if (param->display_name == NULL) {
954 bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
955 param->display_name = NDR_STRDUP(mxa, "");
956 param->status = ERROR_NOT_ENOUGH_MEMORY;
957 return (NDR_DRC_OK);
958 }
959
960 param->buf_size = strlen(svc->sn_fmri);
961 param->status = ERROR_SUCCESS;
962 return (NDR_DRC_OK);
963 }
964
965 /*
966 * svcctl_s_GetServiceKeyNameW
967 *
968 * Returns:
969 * ERROR_SUCCESS
970 * ERROR_INVALID_HANDLE
971 * ERROR_SERVICE_DOES_NOT_EXIST
972 */
973 static int
svcctl_s_GetServiceKeyNameW(void * arg,ndr_xa_t * mxa)974 svcctl_s_GetServiceKeyNameW(void *arg, ndr_xa_t *mxa)
975 {
976 struct svcctl_GetServiceKeyNameW *param = arg;
977 ndr_hdid_t *id = (ndr_hdid_t *)¶m->manager_handle;
978 ndr_handle_t *hd;
979 svcctl_svc_node_t *svc;
980 svcctl_manager_context_t *mgr_ctx;
981
982 hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
983 if (hd == NULL) {
984 bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
985 param->key_name = NDR_STRDUP(mxa, "");
986 param->status = ERROR_INVALID_HANDLE;
987 return (NDR_DRC_OK);
988 }
989
990 mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
991 svc = svcctl_scm_find_service(mgr_ctx, (char *)param->service_name);
992 if (svc == NULL || svc->sn_name == NULL) {
993 bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
994 param->key_name = NDR_STRDUP(mxa, "");
995 param->status = ERROR_SERVICE_DOES_NOT_EXIST;
996 return (NDR_DRC_OK);
997 }
998
999 param->key_name = NDR_STRDUP(mxa, svc->sn_name);
1000 if (param->key_name == NULL) {
1001 bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
1002 param->key_name = NDR_STRDUP(mxa, "");
1003 param->status = ERROR_NOT_ENOUGH_MEMORY;
1004 return (NDR_DRC_OK);
1005 }
1006
1007 param->buf_size = strlen(svc->sn_name);
1008 param->status = ERROR_SUCCESS;
1009 return (NDR_DRC_OK);
1010 }
1011
1012 /*
1013 * svcctl_s_OpenSCManagerA
1014 *
1015 * Request to open the service control manager.
1016 * The caller must have administrator rights in order to open this
1017 * interface. We don't support write (SC_MANAGER_LOCK) access.
1018 *
1019 * Returns:
1020 * ERROR_SUCCESS
1021 * ERROR_ACCESS_DENIED
1022 *
1023 * On success, returns a handle for use with subsequent svcctl requests.
1024 */
1025 static int
svcctl_s_OpenSCManagerA(void * arg,ndr_xa_t * mxa)1026 svcctl_s_OpenSCManagerA(void *arg, ndr_xa_t *mxa)
1027 {
1028 struct svcctl_OpenSCManagerA *param = arg;
1029 ndr_hdid_t *id = NULL;
1030 int rc;
1031
1032 rc = ndr_is_admin(mxa);
1033
1034 if ((rc == 0) || (param->desired_access & SC_MANAGER_LOCK) != 0) {
1035 bzero(¶m->handle, sizeof (svcctl_handle_t));
1036 param->status = ERROR_ACCESS_DENIED;
1037 return (NDR_DRC_OK);
1038 }
1039
1040 id = svcctl_mgr_hdalloc(mxa);
1041 if (id) {
1042 bcopy(id, ¶m->handle, sizeof (svcctl_handle_t));
1043 param->status = ERROR_SUCCESS;
1044 } else {
1045 bzero(¶m->handle, sizeof (svcctl_handle_t));
1046 param->status = ERROR_ACCESS_DENIED;
1047 }
1048
1049 return (NDR_DRC_OK);
1050 }
1051
1052 /*
1053 * svcctl_s_OpenServiceA
1054 *
1055 * Return a handle for use with subsequent svcctl requests.
1056 *
1057 * Returns:
1058 * ERROR_SUCCESS
1059 * ERROR_INVALID_HANDLE
1060 * ERROR_SERVICE_DOES_NOT_EXIST
1061 * ERROR_CALL_NOT_IMPLEMENTED
1062 */
1063 static int
svcctl_s_OpenServiceA(void * arg,ndr_xa_t * mxa)1064 svcctl_s_OpenServiceA(void *arg, ndr_xa_t *mxa)
1065 {
1066 struct svcctl_OpenServiceA *param = arg;
1067 ndr_hdid_t *mgrid = (ndr_hdid_t *)¶m->manager_handle;
1068 ndr_hdid_t *id = NULL;
1069 ndr_handle_t *hd;
1070 DWORD status;
1071 svcctl_manager_context_t *mgr_ctx;
1072 char *svc_name = (char *)param->service_name->value;
1073 boolean_t unimplemented_operations = B_FALSE;
1074
1075 /* Allow service handle allocations for only status & config queries */
1076 unimplemented_operations =
1077 SVCCTL_OPENSVC_OP_UNIMPLEMENTED(param->desired_access);
1078
1079 if (unimplemented_operations) {
1080 bzero(¶m->service_handle, sizeof (svcctl_handle_t));
1081 param->status = ERROR_CALL_NOT_IMPLEMENTED;
1082 return (NDR_DRC_OK);
1083 }
1084
1085 hd = svcctl_hdlookup(mxa, mgrid, SVCCTL_MANAGER_CONTEXT);
1086 if (hd == NULL) {
1087 bzero(¶m->service_handle, sizeof (svcctl_handle_t));
1088 param->status = ERROR_INVALID_HANDLE;
1089 return (NDR_DRC_OK);
1090 }
1091
1092 mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
1093 status = svcctl_scm_validate_service(mgr_ctx, svc_name);
1094 if (status != ERROR_SUCCESS) {
1095 bzero(¶m->service_handle, sizeof (svcctl_handle_t));
1096 param->status = status;
1097 return (NDR_DRC_OK);
1098 }
1099
1100 id = svcctl_svc_hdalloc(mxa, mgrid, svc_name);
1101 if (id) {
1102 bcopy(id, ¶m->service_handle, sizeof (svcctl_handle_t));
1103 param->status = ERROR_SUCCESS;
1104 } else {
1105 bzero(¶m->service_handle, sizeof (svcctl_handle_t));
1106 param->status = ERROR_ACCESS_DENIED;
1107 }
1108
1109 return (NDR_DRC_OK);
1110 }
1111
1112 /*
1113 * svcctl_s_EnumServicesStatusA
1114 *
1115 * Enumerate the list of services we support as ASCII.
1116 */
1117 static int
svcctl_s_EnumServicesStatusA(void * arg,ndr_xa_t * mxa)1118 svcctl_s_EnumServicesStatusA(void *arg, ndr_xa_t *mxa)
1119 {
1120 struct svcctl_EnumServicesStatusA *param = arg;
1121 ndr_hdid_t *id = (ndr_hdid_t *)¶m->manager_handle;
1122 ndr_handle_t *hd;
1123 svcctl_manager_context_t *mgr_ctx;
1124 uint32_t buf_size;
1125 uint32_t svc_num;
1126 uint32_t resume_handle = 0;
1127 uint32_t status;
1128
1129 buf_size = param->buf_size;
1130 if (param->resume_handle != NULL)
1131 resume_handle = *param->resume_handle;
1132
1133 hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
1134 if (hd == NULL) {
1135 status = ERROR_INVALID_HANDLE;
1136 goto enum_services_status_error;
1137 }
1138
1139 mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
1140 if (svcctl_scm_refresh(mgr_ctx) != 0) {
1141 status = ERROR_INVALID_HANDLE;
1142 goto enum_services_status_error;
1143 }
1144
1145 param->services = NDR_MALLOC(mxa, buf_size);
1146 if (param->services == NULL) {
1147 status = ERROR_NOT_ENOUGH_MEMORY;
1148 goto enum_services_status_error;
1149 }
1150 bzero(param->services, buf_size);
1151
1152 svc_num = svcctl_scm_enum_services(mgr_ctx, param->services,
1153 buf_size, &resume_handle, B_FALSE);
1154
1155 param->buf_size = buf_size;
1156 param->svc_num = svc_num;
1157
1158 if (resume_handle != 0) {
1159 if (param->resume_handle != NULL)
1160 *param->resume_handle = resume_handle;
1161 param->bytes_needed = mgr_ctx->mc_bytes_needed;
1162 param->status = ERROR_MORE_DATA;
1163 } else {
1164 if (param->resume_handle)
1165 *param->resume_handle = 0;
1166 param->bytes_needed = 0;
1167 param->status = ERROR_SUCCESS;
1168 }
1169 return (NDR_DRC_OK);
1170
1171 enum_services_status_error:
1172 bzero(param, sizeof (struct svcctl_EnumServicesStatusA));
1173 param->services = NDR_STRDUP(mxa, "");
1174 param->status = status;
1175 return (NDR_DRC_OK);
1176 }
1177
1178 /*
1179 * svcctl_s_QueryServiceConfig2W
1180 *
1181 * Returns:
1182 * ERROR_SUCCESS
1183 * ERROR_INVALID_HANDLE
1184 * ERROR_INVALID_LEVEL
1185 * ERROR_NOT_ENOUGH_MEMORY
1186 */
1187 static int
svcctl_s_QueryServiceConfig2W(void * arg,ndr_xa_t * mxa)1188 svcctl_s_QueryServiceConfig2W(void *arg, ndr_xa_t *mxa)
1189 {
1190 struct svcctl_QueryServiceConfig2W *param = arg;
1191 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
1192 ndr_handle_t *hd;
1193 svcctl_manager_context_t *mgr_ctx;
1194 svcctl_service_context_t *svc_ctx;
1195 svcctl_svc_node_t *svc;
1196 svc_config_rsp_t svc_rsp;
1197 int offset, input_bufsize, bytes_needed = 0;
1198 smb_wchar_t *wide_desc;
1199 char *desc;
1200 DWORD status;
1201
1202 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
1203 if (hd == NULL) {
1204 bzero(param, sizeof (struct svcctl_QueryServiceConfig2W));
1205 param->buffer = NDR_STRDUP(mxa, "");
1206 param->status = ERROR_INVALID_HANDLE;
1207 return (NDR_DRC_OK);
1208 }
1209
1210 input_bufsize = param->buf_size;
1211 param->buffer = NDR_MALLOC(mxa, input_bufsize);
1212 if (param->buffer == NULL) {
1213 bzero(param, sizeof (struct svcctl_QueryServiceConfig2W));
1214 param->buffer = NDR_STRDUP(mxa, "");
1215 param->status = ERROR_NOT_ENOUGH_MEMORY;
1216 return (NDR_DRC_OK);
1217 }
1218 bzero(param->buffer, input_bufsize);
1219
1220 svc_rsp.svc_buf = param->buffer;
1221 status = ERROR_SUCCESS;
1222 switch (param->info_level) {
1223 case SERVICE_CONFIG_DESCRIPTION:
1224 svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
1225 mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
1226 if (mgr_ctx == NULL) {
1227 param->status = ERROR_INVALID_HANDLE;
1228 break;
1229 }
1230
1231 svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
1232 if (svc == NULL || svc->sn_desc == NULL) {
1233 status = ERROR_SERVICE_DOES_NOT_EXIST;
1234 break;
1235 }
1236
1237 desc = svc->sn_desc;
1238 bytes_needed = SVCCTL_WNSTRLEN(desc);
1239
1240 if (input_bufsize <= bytes_needed) {
1241 param->bytes_needed = bytes_needed;
1242 param->status = ERROR_INSUFFICIENT_BUFFER;
1243 return (NDR_DRC_OK);
1244 }
1245
1246 offset = sizeof (svc_description_t);
1247 svc_rsp.svc_desc->desc = offset;
1248 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1249 wide_desc = (smb_wchar_t *)¶m->buffer[offset];
1250 (void) smb_mbstowcs(wide_desc, desc, (strlen(desc) + 1));
1251 offset += SVCCTL_WNSTRLEN(desc);
1252
1253 param->bytes_needed = offset;
1254 break;
1255
1256 case SERVICE_CONFIG_FAILURE_ACTIONS:
1257 bzero(svc_rsp.svc_fac, sizeof (svc_failure_actions_t));
1258 bytes_needed = sizeof (svc_failure_actions_t);
1259 if (input_bufsize <= bytes_needed) {
1260 param->bytes_needed = bytes_needed;
1261 param->status = ERROR_INSUFFICIENT_BUFFER;
1262 return (NDR_DRC_OK);
1263 }
1264 param->bytes_needed = bytes_needed;
1265 break;
1266
1267 case SERVICE_CONFIG_DELAYED_AUTO_START_INFO:
1268 svc_rsp.svc_dstart->dstart = 0;
1269 param->bytes_needed = sizeof (svc_delayed_auto_start_t);
1270 break;
1271
1272 case SERVICE_CONFIG_FAILURE_ACTIONS_FLAG:
1273 svc_rsp.svc_cfa->cfa = 0;
1274 param->bytes_needed = sizeof (svc_config_failure_action_t);
1275 break;
1276
1277 case SERVICE_CONFIG_SERVICE_SID_INFO:
1278 case SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO:
1279 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1280 case SERVICE_CONFIG_TRIGGER_INFO:
1281 case SERVICE_CONFIG_PREFERRED_NODE:
1282 default:
1283 status = ERROR_INVALID_LEVEL;
1284 break;
1285 }
1286
1287 if (status != ERROR_SUCCESS) {
1288 bzero(param, sizeof (struct svcctl_QueryServiceConfig2W));
1289 param->buffer = NDR_STRDUP(mxa, "");
1290 param->status = status;
1291 return (NDR_DRC_OK);
1292 }
1293
1294 param->status = ERROR_SUCCESS;
1295 return (NDR_DRC_OK);
1296 }
1297
1298 /*
1299 * svcctl_s_QueryServiceStatusEx
1300 */
1301 static int
svcctl_s_QueryServiceStatusEx(void * arg,ndr_xa_t * mxa)1302 svcctl_s_QueryServiceStatusEx(void *arg, ndr_xa_t *mxa)
1303 {
1304 struct svcctl_QueryServiceStatusEx *param = arg;
1305 ndr_hdid_t *id = (ndr_hdid_t *)¶m->service_handle;
1306 ndr_handle_t *hd;
1307 svcctl_manager_context_t *mgr_ctx;
1308 svcctl_service_context_t *svc_ctx;
1309 svcctl_svc_node_t *svc;
1310 svc_status_ex_t *svc_status_ex;
1311 uint32_t input_bufsize;
1312 uint32_t bytes_needed;
1313 DWORD status;
1314
1315 hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
1316 if (hd == NULL) {
1317 status = ERROR_INVALID_HANDLE;
1318 goto query_service_status_ex_error;
1319 }
1320
1321 svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
1322 mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
1323 if (mgr_ctx == NULL) {
1324 status = ERROR_INVALID_HANDLE;
1325 goto query_service_status_ex_error;
1326 }
1327
1328 if (param->info_level != SC_STATUS_PROCESS_INFO) {
1329 status = ERROR_INVALID_PARAMETER;
1330 goto query_service_status_ex_error;
1331 }
1332
1333 bytes_needed = sizeof (svc_status_ex_t);
1334
1335 if ((input_bufsize = param->buf_size) < bytes_needed) {
1336 bzero(param, sizeof (struct svcctl_QueryServiceStatusEx));
1337 param->buf_size = input_bufsize;
1338 param->buffer = NDR_STRDUP(mxa, "");
1339 param->bytes_needed = bytes_needed;
1340 param->status = ERROR_INSUFFICIENT_BUFFER;
1341 return (NDR_DRC_OK);
1342 }
1343
1344 if ((svc_status_ex = NDR_MALLOC(mxa, bytes_needed)) == NULL) {
1345 status = ERROR_NOT_ENOUGH_MEMORY;
1346 goto query_service_status_ex_error;
1347 }
1348
1349 svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
1350 if (svc == NULL || svc->sn_state == NULL) {
1351 status = ERROR_SERVICE_DOES_NOT_EXIST;
1352 goto query_service_status_ex_error;
1353 }
1354
1355 svc_status_ex->service_type = SERVICE_WIN32_SHARE_PROCESS;
1356 svc_status_ex->cur_state = svcctl_scm_map_status(svc->sn_state);
1357 svc_status_ex->ctrl_accepted = 0;
1358 svc_status_ex->w32_exitcode = 0;
1359 svc_status_ex->svc_specified_exitcode = 0;
1360 svc_status_ex->check_point = 0;
1361 svc_status_ex->wait_hint = 0;
1362 svc_status_ex->process_id = 1;
1363 svc_status_ex->service_flags = 1;
1364
1365 param->buffer = (uint8_t *)svc_status_ex;
1366 param->buf_size = input_bufsize;
1367 param->bytes_needed = bytes_needed;
1368 param->status = ERROR_SUCCESS;
1369 return (NDR_DRC_OK);
1370
1371 query_service_status_ex_error:
1372 bzero(param, sizeof (struct svcctl_QueryServiceStatusEx));
1373 param->buffer = NDR_STRDUP(mxa, "");
1374 param->status = status;
1375 return (NDR_DRC_OK);
1376 }
1377