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