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