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 *)¶m->handle; 335 336 svcctl_hdfree(mxa, id); 337 338 bzero(¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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(¶m->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, ¶m->handle, sizeof (svcctl_handle_t)); 537 param->status = ERROR_SUCCESS; 538 } else { 539 bzero(¶m->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 *)¶m->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(¶m->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(¶m->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(¶m->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, ¶m->service_handle, sizeof (svcctl_handle_t)); 597 param->status = ERROR_SUCCESS; 598 } else { 599 bzero(¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 = ¶m->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 *)¶m->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 *)¶m->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 *)¶m->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(¶m->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, ¶m->handle, sizeof (svcctl_handle_t)); 1043 param->status = ERROR_SUCCESS; 1044 } else { 1045 bzero(¶m->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 *)¶m->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(¶m->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(¶m->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(¶m->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, ¶m->service_handle, sizeof (svcctl_handle_t)); 1103 param->status = ERROR_SUCCESS; 1104 } else { 1105 bzero(¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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