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