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