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