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