xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c (revision b819cea2f73f98c5662230cc9affc8cc84f77fcf)
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
132 svcctl_initialize(void)
133 {
134 	(void) ndr_svc_register(&svcctl_service);
135 	svcctl_init();
136 }
137 
138 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 *
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
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 *
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 *
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 *
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
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 *)&param->handle;
335 
336 	svcctl_hdfree(mxa, id);
337 
338 	bzero(&param->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
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 *)&param->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
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 *)&param->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
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 *)&param->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
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 *)&param->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
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(&param->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, &param->handle, sizeof (svcctl_handle_t));
537 		param->status = ERROR_SUCCESS;
538 	} else {
539 		bzero(&param->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
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 *)&param->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(&param->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(&param->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(&param->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, &param->service_handle, sizeof (svcctl_handle_t));
597 		param->status = ERROR_SUCCESS;
598 	} else {
599 		bzero(&param->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
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 *)&param->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
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 *)&param->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
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 *)&param->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
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 *)&param->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 = &param->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
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 *)&param->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
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 *)&param->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
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 *)&param->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
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(&param->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, &param->handle, sizeof (svcctl_handle_t));
1043 		param->status = ERROR_SUCCESS;
1044 	} else {
1045 		bzero(&param->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
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 *)&param->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(&param->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(&param->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(&param->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, &param->service_handle, sizeof (svcctl_handle_t));
1103 		param->status = ERROR_SUCCESS;
1104 	} else {
1105 		bzero(&param->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
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 *)&param->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
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 *)&param->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 *)&param->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
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 *)&param->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