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 2008 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 #include <stdio.h>
35 #include <strings.h>
36 
37 #include <smbsrv/ntstatus.h>
38 #include <smbsrv/nmpipes.h>
39 #include <smbsrv/mlsvc_util.h>
40 
41 #include "svcctl_scm.h"
42 
43 #define	SVCCTL_OPENSVC_OP_UNIMPLEMENTED(S)	\
44 	((S) & SERVICE_CHANGE_CONFIG)	||	\
45 	((S) & SERVICE_PAUSE_CONTINUE)	||	\
46 	((S) & SERVICE_START)		||	\
47 	((S) & SERVICE_STOP)		||	\
48 	((S) & SERVICE_ENUMERATE_DEPENDENTS)
49 
50 static int svcctl_s_Close(void *, struct mlrpc_xaction *);
51 static int svcctl_s_OpenManager(void *, struct mlrpc_xaction *);
52 static int svcctl_s_OpenService(void *, struct mlrpc_xaction *);
53 static int svcctl_s_QueryServiceStatus(void *, struct mlrpc_xaction *);
54 static int svcctl_s_QueryServiceConfig(void *, struct mlrpc_xaction *);
55 static int svcctl_s_EnumServicesStatus(void *, struct mlrpc_xaction *);
56 static int svcctl_s_GetServiceDisplayNameW(void *, struct mlrpc_xaction *);
57 static int svcctl_s_GetServiceKeyNameW(void *, struct mlrpc_xaction *);
58 static int svcctl_s_QueryServiceConfig2W(void *, struct mlrpc_xaction *);
59 
60 static mlrpc_stub_table_t svcctl_stub_table[] = {
61 	{ svcctl_s_Close,		SVCCTL_OPNUM_Close },
62 	{ svcctl_s_OpenManager,		SVCCTL_OPNUM_OpenManager },
63 	{ svcctl_s_OpenService,		SVCCTL_OPNUM_OpenService },
64 	{ svcctl_s_QueryServiceStatus,	SVCCTL_OPNUM_QueryServiceStatus },
65 	{ svcctl_s_QueryServiceConfig,	SVCCTL_OPNUM_QueryServiceConfig },
66 	{ svcctl_s_EnumServicesStatus,	SVCCTL_OPNUM_EnumServicesStatus },
67 	{ svcctl_s_GetServiceDisplayNameW,
68 		SVCCTL_OPNUM_GetServiceDisplayNameW },
69 	{ svcctl_s_GetServiceKeyNameW,	SVCCTL_OPNUM_GetServiceKeyNameW },
70 	{ svcctl_s_QueryServiceConfig2W, SVCCTL_OPNUM_QueryServiceConfig2W },
71 	{0}
72 };
73 
74 static mlrpc_service_t svcctl_service = {
75 	"SVCCTL",			/* name */
76 	"Service Control Services",	/* desc */
77 	"\\svcctl",			/* endpoint */
78 	PIPE_NTSVCS,			/* sec_addr_port */
79 	"367abb81-9844-35f1-ad3298f038001003", 2,	/* abstract */
80 	"8a885d04-1ceb-11c9-9fe808002b104860", 2,	/* transfer */
81 	0,				/* no bind_instance_size */
82 	0,				/* no bind_req() */
83 	0,				/* no unbind_and_close() */
84 	0,				/* use generic_call_stub() */
85 	&TYPEINFO(svcctl_interface),	/* interface ti */
86 	svcctl_stub_table		/* stub_table */
87 };
88 
89 /*
90  * svcctl_initialize
91  *
92  * This function registers the SVCCTL RPC interface with the RPC runtime
93  * library. It must be called in order to use either the client side
94  * or the server side functions.
95  */
96 void
97 svcctl_initialize(void)
98 {
99 	(void) mlrpc_register_service(&svcctl_service);
100 }
101 
102 /*
103  * svcctl_hdlookup
104  *
105  * Handle lookup wrapper to validate the local service and/or manager context.
106  */
107 static ndr_handle_t *
108 svcctl_hdlookup(ndr_xa_t *mxa, ndr_hdid_t *id, svcctl_context_type_t type)
109 {
110 	ndr_handle_t *hd;
111 	svcctl_context_t *ctx;
112 
113 	if ((hd = ndr_hdlookup(mxa, id)) == NULL)
114 		return (NULL);
115 
116 	if ((ctx = (svcctl_context_t *)hd->nh_data) == NULL)
117 		return (NULL);
118 
119 	if ((ctx->c_type != type) || (ctx->c_ctx.uc_cp == NULL))
120 		return (NULL);
121 
122 	return (hd);
123 }
124 
125 /*
126  * svcctl_hdfree
127  *
128  * Handle deallocation wrapper to free the local service and/or manager context.
129  */
130 static void
131 svcctl_hdfree(ndr_xa_t *mxa, ndr_hdid_t *id)
132 {
133 	ndr_handle_t *hd;
134 	svcctl_context_t *ctx;
135 	svcctl_manager_context_t *mgr_ctx;
136 	svcctl_service_context_t *svc_ctx;
137 
138 	if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
139 		ctx = (svcctl_context_t *)hd->nh_data;
140 
141 		switch (ctx->c_type) {
142 		case SVCCTL_MANAGER_CONTEXT:
143 			mgr_ctx = ctx->c_ctx.uc_mgr;
144 			svcctl_scm_fini(mgr_ctx);
145 			svcctl_scm_scf_handle_fini(mgr_ctx);
146 			free(mgr_ctx);
147 			break;
148 
149 		case SVCCTL_SERVICE_CONTEXT:
150 			svc_ctx = ctx->c_ctx.uc_svc;
151 			free(svc_ctx->sc_mgrid);
152 			free(svc_ctx->sc_svcname);
153 			free(svc_ctx);
154 			break;
155 
156 		default:
157 			break;
158 		}
159 
160 		free(ctx);
161 		ndr_hdfree(mxa, id);
162 	}
163 }
164 
165 /*
166  * svcctl_mgr_hdalloc
167  *
168  * Handle allocation wrapper to setup the local manager context.
169  */
170 static ndr_hdid_t *
171 svcctl_mgr_hdalloc(ndr_xa_t *mxa)
172 {
173 	svcctl_context_t *ctx;
174 	svcctl_manager_context_t *mgr_ctx;
175 
176 	if ((ctx = malloc(sizeof (svcctl_context_t))) == NULL)
177 		return (NULL);
178 	ctx->c_type = SVCCTL_MANAGER_CONTEXT;
179 
180 	if ((mgr_ctx = malloc(sizeof (svcctl_manager_context_t))) == NULL) {
181 		free(ctx);
182 		return (NULL);
183 	}
184 	bzero(mgr_ctx, sizeof (svcctl_manager_context_t));
185 
186 	if (svcctl_scm_scf_handle_init(mgr_ctx) < 0) {
187 		free(mgr_ctx);
188 		free(ctx);
189 		return (NULL);
190 	}
191 
192 	if (svcctl_scm_init(mgr_ctx) < 0) {
193 		svcctl_scm_scf_handle_fini(mgr_ctx);
194 		free(mgr_ctx);
195 		free(ctx);
196 		return (NULL);
197 	}
198 
199 	ctx->c_ctx.uc_mgr = mgr_ctx;
200 
201 	return (ndr_hdalloc(mxa, ctx));
202 }
203 
204 /*
205  * svcctl_get_mgr_ctx
206  *
207  * This function looks up a reference to local manager context.
208  */
209 static svcctl_manager_context_t *
210 svcctl_get_mgr_ctx(ndr_xa_t *mxa, ndr_hdid_t *mgr_id)
211 {
212 	ndr_handle_t *hd;
213 	svcctl_manager_context_t *mgr_ctx;
214 
215 	hd = svcctl_hdlookup(mxa, mgr_id, SVCCTL_MANAGER_CONTEXT);
216 	if (hd == NULL)
217 		return (NULL);
218 
219 	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
220 
221 	return (mgr_ctx);
222 }
223 
224 /*
225  * svcctl_svc_hdalloc
226  *
227  * Handle allocation wrapper to setup the local service context.
228  */
229 static ndr_hdid_t *
230 svcctl_svc_hdalloc(ndr_xa_t *mxa, ndr_hdid_t *mgr_id, char *svc_name)
231 {
232 	svcctl_context_t *ctx;
233 	svcctl_service_context_t *svc_ctx;
234 	svcctl_manager_context_t *mgr_ctx;
235 	int max_name_sz = 0;
236 	char *svcname;
237 
238 	mgr_ctx = svcctl_get_mgr_ctx(mxa, mgr_id);
239 	if (mgr_ctx == NULL)
240 		return (NULL);
241 	max_name_sz = mgr_ctx->mc_scf_max_fmri_len;
242 
243 	if ((ctx = malloc(sizeof (svcctl_context_t))) == NULL) {
244 		svcctl_hdfree(mxa, mgr_id);
245 		return (NULL);
246 	}
247 	ctx->c_type = SVCCTL_SERVICE_CONTEXT;
248 
249 	if ((svc_ctx = malloc(sizeof (svcctl_service_context_t))) == NULL) {
250 		svcctl_hdfree(mxa, mgr_id);
251 		free(ctx);
252 		return (NULL);
253 	}
254 	bzero(svc_ctx, sizeof (svcctl_service_context_t));
255 
256 	svc_ctx->sc_mgrid = malloc(sizeof (ndr_hdid_t));
257 	svcname = malloc(max_name_sz);
258 
259 	if ((svc_ctx->sc_mgrid == NULL) || (svcname == NULL)) {
260 		free(svc_ctx->sc_mgrid);
261 		free(svc_ctx);
262 		svcctl_hdfree(mxa, mgr_id);
263 		free(ctx);
264 		return (NULL);
265 	}
266 
267 	svc_ctx->sc_svcname = svcname;
268 
269 	bcopy(mgr_id, svc_ctx->sc_mgrid, sizeof (ndr_hdid_t));
270 	(void) strlcpy(svc_ctx->sc_svcname, svc_name, max_name_sz);
271 
272 	ctx->c_ctx.uc_svc = svc_ctx;
273 
274 	return (ndr_hdalloc(mxa, ctx));
275 }
276 
277 /*
278  * svcctl_s_Close
279  *
280  * This is a request to close the SVCCTL interface specified by the
281  * handle. Free the handle and zero out the result handle for the
282  * client.
283  *
284  * Returns:
285  *	ERROR_SUCCESS
286  *	ERROR_INVALID_HANDLE
287  */
288 static int
289 svcctl_s_Close(void *arg, struct mlrpc_xaction *mxa)
290 {
291 	struct svcctl_Close *param = arg;
292 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
293 
294 	svcctl_hdfree(mxa, id);
295 
296 	bzero(&param->result_handle, sizeof (svcctl_handle_t));
297 	param->status = ERROR_SUCCESS;
298 	return (MLRPC_DRC_OK);
299 }
300 
301 /*
302  * svcctl_s_OpenManager
303  *
304  * Request to open the service control manager.
305  * The caller must have administrator rights in order to open this
306  * interface.  We don't support write (SC_MANAGER_LOCK) access.
307  *
308  * Returns:
309  *	ERROR_SUCCESS
310  *	ERROR_ACCESS_DENIED
311  *
312  * On success, returns a handle for use with subsequent svcctl requests.
313  */
314 static int
315 svcctl_s_OpenManager(void *arg, struct mlrpc_xaction *mxa)
316 {
317 	struct svcctl_OpenManager *param = arg;
318 	ndr_hdid_t *id = NULL;
319 	int rc;
320 
321 	rc = ndr_is_admin(mxa);
322 
323 	if ((rc == 0) || (param->desired_access & SC_MANAGER_LOCK) != 0) {
324 		bzero(&param->handle, sizeof (svcctl_handle_t));
325 		param->status = ERROR_ACCESS_DENIED;
326 		return (MLRPC_DRC_OK);
327 	}
328 
329 	id = svcctl_mgr_hdalloc(mxa);
330 	if (id) {
331 		bcopy(id, &param->handle, sizeof (svcctl_handle_t));
332 		param->status = ERROR_SUCCESS;
333 	} else {
334 		bzero(&param->handle, sizeof (svcctl_handle_t));
335 		param->status = ERROR_ACCESS_DENIED;
336 	}
337 
338 	return (MLRPC_DRC_OK);
339 }
340 
341 /*
342  * svcctl_s_OpenService
343  *
344  * Return a handle for use with subsequent svcctl requests.
345  *
346  * Returns:
347  *	ERROR_SUCCESS
348  *	ERROR_INVALID_HANDLE
349  *	ERROR_SERVICE_DOES_NOT_EXIST
350  *	ERROR_CALL_NOT_IMPLEMENTED
351  */
352 static int
353 svcctl_s_OpenService(void *arg, struct mlrpc_xaction *mxa)
354 {
355 	struct svcctl_OpenService *param = arg;
356 	ndr_hdid_t *mgrid = (ndr_hdid_t *)&param->manager_handle;
357 	ndr_hdid_t *id = NULL;
358 	ndr_handle_t *hd;
359 	DWORD status;
360 	svcctl_manager_context_t *mgr_ctx;
361 	char *svc_name = (char *)param->service_name;
362 	boolean_t unimplemented_operations = B_FALSE;
363 
364 	/* Allow service handle allocations for only status & config queries */
365 	unimplemented_operations =
366 	    SVCCTL_OPENSVC_OP_UNIMPLEMENTED(param->desired_access);
367 
368 	if (unimplemented_operations) {
369 		bzero(&param->service_handle, sizeof (svcctl_handle_t));
370 		param->status = ERROR_CALL_NOT_IMPLEMENTED;
371 		return (MLRPC_DRC_OK);
372 	}
373 
374 	hd = svcctl_hdlookup(mxa, mgrid, SVCCTL_MANAGER_CONTEXT);
375 	if (hd == NULL) {
376 		bzero(&param->service_handle, sizeof (svcctl_handle_t));
377 		param->status = ERROR_INVALID_HANDLE;
378 		return (MLRPC_DRC_OK);
379 	}
380 
381 	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
382 	status = svcctl_scm_validate_service(mgr_ctx, svc_name);
383 	if (status != ERROR_SUCCESS) {
384 		bzero(&param->service_handle, sizeof (svcctl_handle_t));
385 		param->status = status;
386 		return (MLRPC_DRC_OK);
387 	}
388 
389 	id = svcctl_svc_hdalloc(mxa, mgrid, svc_name);
390 	if (id) {
391 		bcopy(id, &param->service_handle, sizeof (svcctl_handle_t));
392 		param->status = ERROR_SUCCESS;
393 	} else {
394 		bzero(&param->service_handle, sizeof (svcctl_handle_t));
395 		param->status = ERROR_ACCESS_DENIED;
396 	}
397 
398 	return (MLRPC_DRC_OK);
399 }
400 
401 /*
402  * svcctl_s_QueryServiceStatus
403  *
404  * Returns:
405  *	ERROR_SUCCESS
406  *	ERROR_INVALID_HANDLE
407  */
408 static int
409 svcctl_s_QueryServiceStatus(void *arg, struct mlrpc_xaction *mxa)
410 {
411 	struct svcctl_QueryServiceStatus *param = arg;
412 	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
413 	ndr_handle_t *hd;
414 	svcctl_manager_context_t *mgr_ctx;
415 	svcctl_service_context_t *svc_ctx;
416 	svcctl_svc_node_t *svc;
417 
418 	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
419 	if (hd == NULL) {
420 		bzero(param, sizeof (struct svcctl_QueryServiceStatus));
421 		param->status = ERROR_INVALID_HANDLE;
422 		return (MLRPC_DRC_OK);
423 	}
424 
425 	svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
426 	mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
427 	if (mgr_ctx == NULL) {
428 		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
429 		param->status = ERROR_INVALID_HANDLE;
430 		return (MLRPC_DRC_OK);
431 	}
432 
433 	svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
434 	if (svc == NULL || svc->sn_state == NULL) {
435 		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
436 		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
437 		return (MLRPC_DRC_OK);
438 	}
439 
440 	param->service_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
441 	param->service_status.cur_state = svcctl_scm_map_status(svc->sn_state);
442 	param->service_status.ctrl_accepted = 0;
443 	param->service_status.w32_exitcode = 0;
444 	param->service_status.svc_specified_exitcode = 0;
445 	param->service_status.check_point = 0;
446 	param->service_status.wait_hint = 0;
447 
448 	param->status = ERROR_SUCCESS;
449 	return (MLRPC_DRC_OK);
450 }
451 
452 /*
453  * svcctl_s_EnumServicesStatus
454  *
455  * Enumerate the list of services we support. Currently, this list
456  * is built in a fixed-size 1024 byte buffer - be careful not to
457  * over-run the buffer.
458  *
459  * Returns:
460  *	ERROR_SUCCESS
461  *	ERROR_INVALID_HANDLE
462  *	ERROR_NOT_ENOUGH_MEMORY
463  */
464 static int
465 svcctl_s_EnumServicesStatus(void *arg, struct mlrpc_xaction *mxa)
466 {
467 	struct svcctl_EnumServicesStatus *param = arg;
468 	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
469 	ndr_handle_t *hd;
470 	int input_bufsize = 0;
471 	svcctl_manager_context_t *mgr_ctx;
472 
473 	hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
474 	if (hd == NULL) {
475 		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
476 		param->services = MLRPC_HEAP_STRSAVE(mxa, "");
477 		param->status = ERROR_INVALID_HANDLE;
478 		return (MLRPC_DRC_OK);
479 	}
480 
481 	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
482 	if (svcctl_scm_refresh(mgr_ctx) != 0) {
483 		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
484 		param->status = ERROR_INVALID_DATA;
485 		return (MLRPC_DRC_OK);
486 	}
487 
488 	input_bufsize = param->buf_size;
489 	param->services = MLRPC_HEAP_MALLOC(mxa, input_bufsize);
490 	if (param->services == NULL) {
491 		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
492 		param->status = ERROR_NOT_ENOUGH_MEMORY;
493 		return (MLRPC_DRC_OK);
494 	}
495 	bzero(param->services, input_bufsize);
496 
497 	if (input_bufsize <= mgr_ctx->mc_bytes_needed) {
498 		param->bytes_needed = mgr_ctx->mc_bytes_needed;
499 		param->svc_num = 0;
500 		param->resume_handle = 0;
501 		param->status = ERROR_MORE_DATA;
502 		return (MLRPC_DRC_OK);
503 	}
504 
505 	svcctl_scm_enum_services(mgr_ctx, param->services);
506 
507 	param->buf_size = input_bufsize;
508 	param->bytes_needed = 0;
509 	param->svc_num = mgr_ctx->mc_scf_numsvcs;
510 	param->resume_handle = 0;
511 	param->status = ERROR_SUCCESS;
512 	return (MLRPC_DRC_OK);
513 }
514 
515 /*
516  * svcctl_s_QueryServiceConfig
517  *
518  * Returns:
519  *	ERROR_SUCCESS
520  *	ERROR_INVALID_HANDLE
521  */
522 static int
523 svcctl_s_QueryServiceConfig(void *arg, struct mlrpc_xaction *mxa)
524 {
525 	struct svcctl_QueryServiceConfig *param = arg;
526 	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
527 	ndr_handle_t *hd;
528 	svcctl_manager_context_t *mgr_ctx;
529 	svcctl_service_context_t *svc_ctx;
530 	svcctl_svc_node_t *svc;
531 	int bytes_needed = 0;
532 	svc_config_t *cfg;
533 
534 	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
535 	if (hd == NULL) {
536 		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
537 		param->status = ERROR_INVALID_HANDLE;
538 		return (MLRPC_DRC_OK);
539 	}
540 
541 	svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
542 	mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
543 	if (mgr_ctx == NULL) {
544 		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
545 		param->status = ERROR_INVALID_HANDLE;
546 		return (MLRPC_DRC_OK);
547 	}
548 
549 	svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
550 	if (svc == NULL || svc->sn_fmri == NULL) {
551 		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
552 		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
553 		return (MLRPC_DRC_OK);
554 	}
555 
556 	cfg = &param->service_cfg;
557 	cfg->service_type = SERVICE_WIN32_SHARE_PROCESS;
558 	cfg->start_type = SERVICE_AUTO_START;
559 	cfg->error_control = SERVICE_AUTO_START;
560 	cfg->binary_pathname = MLRPC_HEAP_STRSAVE(mxa, "");
561 	cfg->loadorder_group = MLRPC_HEAP_STRSAVE(mxa, "");
562 	cfg->tag_id = 0;
563 	cfg->dependencies = MLRPC_HEAP_STRSAVE(mxa, "");
564 	cfg->service_startname = MLRPC_HEAP_STRSAVE(mxa, "");
565 	cfg->display_name = MLRPC_HEAP_STRSAVE(mxa, svc->sn_fmri);
566 
567 	bytes_needed = sizeof (svc_config_t);
568 	bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->binary_pathname);
569 	bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->loadorder_group);
570 	bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->dependencies);
571 	bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->service_startname);
572 	bytes_needed += SVCCTL_WNSTRLEN(svc->sn_fmri);
573 
574 	if (param->buf_size < bytes_needed) {
575 		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
576 		param->cfg_bytes = bytes_needed;
577 		param->status = ERROR_MORE_DATA;
578 		return (MLRPC_DRC_OK);
579 	}
580 
581 	param->cfg_bytes = bytes_needed;
582 	param->status = ERROR_SUCCESS;
583 	return (MLRPC_DRC_OK);
584 }
585 
586 /*
587  * svcctl_s_GetServiceDisplayNameW
588  *
589  * Returns:
590  *	ERROR_SUCCESS
591  *	ERROR_INVALID_HANDLE
592  *	ERROR_SERVICE_DOES_NOT_EXIST
593  */
594 static int
595 svcctl_s_GetServiceDisplayNameW(void *arg, struct mlrpc_xaction *mxa)
596 {
597 	struct svcctl_GetServiceDisplayNameW *param = arg;
598 	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
599 	ndr_handle_t *hd;
600 	svcctl_svc_node_t *svc;
601 	svcctl_manager_context_t *mgr_ctx;
602 
603 	hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
604 	if (hd == NULL) {
605 		bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
606 		param->display_name = MLRPC_HEAP_STRSAVE(mxa, "");
607 		param->status = ERROR_INVALID_HANDLE;
608 		return (MLRPC_DRC_OK);
609 	}
610 
611 	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
612 	svc = svcctl_scm_find_service(mgr_ctx, (char *)param->service_name);
613 	if (svc == NULL || svc->sn_fmri == NULL) {
614 		bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
615 		param->display_name = MLRPC_HEAP_STRSAVE(mxa, "");
616 		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
617 		return (MLRPC_DRC_OK);
618 	}
619 
620 	param->display_name = MLRPC_HEAP_STRSAVE(mxa, svc->sn_fmri);
621 	if (param->display_name == NULL) {
622 		bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
623 		param->display_name = MLRPC_HEAP_STRSAVE(mxa, "");
624 		param->status = ERROR_NOT_ENOUGH_MEMORY;
625 		return (MLRPC_DRC_OK);
626 	}
627 
628 	param->buf_size = strlen(svc->sn_fmri);
629 	param->status = ERROR_SUCCESS;
630 	return (MLRPC_DRC_OK);
631 }
632 
633 /*
634  * svcctl_s_GetServiceKeyNameW
635  *
636  * Returns:
637  *	ERROR_SUCCESS
638  *	ERROR_INVALID_HANDLE
639  *	ERROR_SERVICE_DOES_NOT_EXIST
640  */
641 static int
642 svcctl_s_GetServiceKeyNameW(void *arg, struct mlrpc_xaction *mxa)
643 {
644 	struct svcctl_GetServiceKeyNameW *param = arg;
645 	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
646 	ndr_handle_t *hd;
647 	svcctl_svc_node_t *svc;
648 	svcctl_manager_context_t *mgr_ctx;
649 
650 	hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
651 	if (hd == NULL) {
652 		bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
653 		param->key_name = MLRPC_HEAP_STRSAVE(mxa, "");
654 		param->status = ERROR_INVALID_HANDLE;
655 		return (MLRPC_DRC_OK);
656 	}
657 
658 	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
659 	svc = svcctl_scm_find_service(mgr_ctx, (char *)param->service_name);
660 	if (svc == NULL || svc->sn_name == NULL) {
661 		bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
662 		param->key_name = MLRPC_HEAP_STRSAVE(mxa, "");
663 		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
664 		return (MLRPC_DRC_OK);
665 	}
666 
667 	param->key_name = MLRPC_HEAP_STRSAVE(mxa, svc->sn_name);
668 	if (param->key_name == NULL) {
669 		bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
670 		param->key_name = MLRPC_HEAP_STRSAVE(mxa, "");
671 		param->status = ERROR_NOT_ENOUGH_MEMORY;
672 		return (MLRPC_DRC_OK);
673 	}
674 
675 	param->buf_size = strlen(svc->sn_name);
676 	param->status = ERROR_SUCCESS;
677 	return (MLRPC_DRC_OK);
678 }
679 
680 /*
681  * svcctl_s_QueryServiceConfig2W
682  *
683  * Returns:
684  *	ERROR_SUCCESS
685  *	ERROR_INVALID_HANDLE
686  *	ERROR_INVALID_LEVEL
687  *	ERROR_NOT_ENOUGH_MEMORY
688  */
689 static int
690 svcctl_s_QueryServiceConfig2W(void *arg, struct mlrpc_xaction *mxa)
691 {
692 	struct svcctl_QueryServiceConfig2W *param = arg;
693 	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
694 	ndr_handle_t *hd;
695 	svcctl_manager_context_t *mgr_ctx;
696 	svcctl_service_context_t *svc_ctx;
697 	svcctl_svc_node_t *svc;
698 	svc_description_t *svc_desc;
699 	svc_failure_actions_t *fac;
700 	int offset, input_bufsize, bytes_needed = 0;
701 	mts_wchar_t *wide_desc;
702 	char *desc;
703 	DWORD status;
704 
705 	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
706 	if (hd == NULL) {
707 		bzero(param, sizeof (struct svcctl_QueryServiceConfig2W));
708 		param->buffer = MLRPC_HEAP_STRSAVE(mxa, "");
709 		param->status = ERROR_INVALID_HANDLE;
710 		return (MLRPC_DRC_OK);
711 	}
712 
713 	input_bufsize = param->buf_size;
714 	param->buffer = MLRPC_HEAP_MALLOC(mxa, input_bufsize);
715 	if (param->buffer == NULL) {
716 		bzero(param, sizeof (struct svcctl_QueryServiceConfig2W));
717 		param->status = ERROR_NOT_ENOUGH_MEMORY;
718 		return (MLRPC_DRC_OK);
719 	}
720 	bzero(param->buffer, input_bufsize);
721 
722 	status = ERROR_SUCCESS;
723 	switch (param->info_level) {
724 	case SERVICE_CONFIG_DESCRIPTION:
725 		svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
726 		mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
727 		if (mgr_ctx == NULL) {
728 			param->status = ERROR_INVALID_HANDLE;
729 			break;
730 		}
731 
732 		svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
733 		if (svc == NULL || svc->sn_desc == NULL) {
734 			status = ERROR_SERVICE_DOES_NOT_EXIST;
735 			break;
736 		}
737 
738 		desc = svc->sn_desc;
739 		bytes_needed = SVCCTL_WNSTRLEN(desc);
740 
741 		if (input_bufsize <= bytes_needed) {
742 			param->bytes_needed = bytes_needed;
743 			param->status = ERROR_MORE_DATA;
744 			return (MLRPC_DRC_OK);
745 		}
746 
747 		offset = sizeof (svc_description_t);
748 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
749 		svc_desc = (svc_description_t *)param->buffer;
750 		svc_desc->desc = offset;
751 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
752 		wide_desc = (mts_wchar_t *)&param->buffer[offset];
753 		(void) mts_mbstowcs(wide_desc, desc, (strlen(desc) + 1));
754 		offset = SVCCTL_WNSTRLEN(desc);
755 
756 		param->bytes_needed = offset;
757 		break;
758 
759 	case SERVICE_CONFIG_FAILURE_ACTIONS:
760 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
761 		fac = (svc_failure_actions_t *)param->buffer;
762 		bzero(fac, sizeof (svc_failure_actions_t));
763 
764 		param->bytes_needed = input_bufsize;
765 		break;
766 
767 	default:
768 		status = ERROR_INVALID_LEVEL;
769 		break;
770 	}
771 
772 	if (status != ERROR_SUCCESS) {
773 		bzero(param, sizeof (struct svcctl_QueryServiceConfig2W));
774 		param->buffer = MLRPC_HEAP_STRSAVE(mxa, "");
775 		param->status = status;
776 		return (MLRPC_DRC_OK);
777 	}
778 
779 	param->status = ERROR_SUCCESS;
780 	return (MLRPC_DRC_OK);
781 }
782