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 Manager (SCM) for SVCCTL service. 28 * 29 * This routine maintains a list of SMF service and their states. A list 30 * of Solaris SMF service are displayed on the Server/Connection Manager 31 * Windows client. 32 */ 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <stdarg.h> 36 #include <strings.h> 37 #include <assert.h> 38 #include <errno.h> 39 #include <libscf.h> 40 #include <libscf_priv.h> 41 #include <time.h> 42 #include <dlfcn.h> 43 #include <sys/types.h> 44 45 #include <smbsrv/libsmb.h> 46 #include <smbsrv/libmlsvc.h> 47 #include <smbsrv/winsvc.h> 48 #include <smbsrv/ndl/svcctl.ndl> 49 50 #define LEGACY_UNKNOWN "unknown" 51 #define SVC_NAME_PROP "name" 52 53 /* Flags for svcctl_scm_pg_get_val() */ 54 #define EMPTY_OK 0x01 55 #define MULTI_OK 0x02 56 57 static void *svcctl_scm_interposer_hdl = NULL; 58 static struct { 59 int (*svcctl_op_scm_init)(svcctl_manager_context_t *); 60 int (*svcctl_op_scf_init)(svcctl_manager_context_t *); 61 } svcctl_scm_ops; 62 63 /* 64 * svcctl_scm_avl_nodecmp 65 * 66 * Comparision function for nodes in an AVL tree of services. 67 */ 68 /* ARGSUSED */ 69 static int 70 svcctl_scm_avl_nodecmp(const void *l_arg, const void *r_arg, void *m_name_len) 71 { 72 const svcctl_svc_node_t *l = l_arg; 73 const svcctl_svc_node_t *r = r_arg; 74 int *max_name_len = m_name_len; 75 int ret = 0; 76 77 ret = strncasecmp(l->sn_name, r->sn_name, *max_name_len); 78 79 if (ret > 0) 80 return (1); 81 if (ret < 0) 82 return (-1); 83 return (0); 84 } 85 86 /* 87 * svcctl_scm_pg_get_val 88 * 89 * Get the single value of the named property in the given property group, 90 * which must have type ty, and put it in *vp. If ty is SCF_TYPE_ASTRING, vp 91 * is taken to be a char **, and sz is the size of the buffer. sz is unused 92 * otherwise. Return 0 on success, -1 if the property doesn't exist, has the 93 * wrong type, or doesn't have a single value. If flags has EMPTY_OK, don't 94 * complain if the property has no values (but return nonzero). If flags has 95 * MULTI_OK and the property has multiple values, succeed with E2BIG. 96 */ 97 static int 98 svcctl_scm_pg_get_val(svcctl_manager_context_t *mgr_ctx, 99 scf_propertygroup_t *pg, const char *propname, scf_type_t ty, void *vp, 100 size_t sz, uint_t flags) 101 { 102 int ret = -1, r; 103 boolean_t multi = B_FALSE; 104 105 assert((flags & ~(EMPTY_OK | MULTI_OK)) == 0); 106 107 if (scf_pg_get_property(pg, propname, mgr_ctx->mc_scf_gprop) == -1) 108 return (ret); 109 110 if (scf_property_is_type(mgr_ctx->mc_scf_gprop, ty) != SCF_SUCCESS) 111 return (ret); 112 113 if (scf_property_get_value(mgr_ctx->mc_scf_gprop, 114 mgr_ctx->mc_scf_gval) != SCF_SUCCESS) { 115 switch (scf_error()) { 116 case SCF_ERROR_NOT_FOUND: 117 return (ret); 118 119 case SCF_ERROR_CONSTRAINT_VIOLATED: 120 if (flags & MULTI_OK) { 121 multi = B_TRUE; 122 break; 123 } 124 return (ret); 125 126 case SCF_ERROR_PERMISSION_DENIED: 127 default: 128 return (ret); 129 } 130 } 131 132 switch (ty) { 133 case SCF_TYPE_ASTRING: 134 r = scf_value_get_astring 135 (mgr_ctx->mc_scf_gval, vp, sz) > 0 ? SCF_SUCCESS : -1; 136 break; 137 138 case SCF_TYPE_BOOLEAN: 139 r = scf_value_get_boolean(mgr_ctx->mc_scf_gval, (uint8_t *)vp); 140 break; 141 142 case SCF_TYPE_COUNT: 143 r = scf_value_get_count(mgr_ctx->mc_scf_gval, (uint64_t *)vp); 144 break; 145 146 case SCF_TYPE_INTEGER: 147 r = scf_value_get_integer(mgr_ctx->mc_scf_gval, (int64_t *)vp); 148 break; 149 150 case SCF_TYPE_TIME: { 151 int64_t sec; 152 int32_t ns; 153 r = scf_value_get_time(mgr_ctx->mc_scf_gval, &sec, &ns); 154 ((struct timeval *)vp)->tv_sec = sec; 155 ((struct timeval *)vp)->tv_usec = ns / 1000; 156 break; 157 } 158 159 case SCF_TYPE_USTRING: 160 r = scf_value_get_ustring(mgr_ctx->mc_scf_gval, vp, sz) > 0 ? 161 SCF_SUCCESS : -1; 162 break; 163 164 default: 165 return (ret); 166 } 167 168 if (r != SCF_SUCCESS) 169 return (ret); 170 171 ret = multi ? E2BIG : 0; 172 173 return (ret); 174 } 175 176 /* 177 * svcctl_scm_get_running_snapshot 178 * 179 * Get running snapshot of a service instance. 180 */ 181 static scf_snapshot_t * 182 svcctl_scm_get_running_snapshot(svcctl_manager_context_t *mgr_ctx, 183 scf_instance_t *inst) 184 { 185 scf_snapshot_t *snap; 186 187 snap = scf_snapshot_create(mgr_ctx->mc_scf_hdl); 188 if (snap == NULL) 189 return (NULL); 190 191 if (scf_instance_get_snapshot(inst, "running", snap) == 0) 192 return (snap); 193 194 if (scf_error() != SCF_ERROR_NOT_FOUND) 195 return (NULL); 196 197 scf_snapshot_destroy(snap); 198 return (NULL); 199 } 200 201 /* 202 * svcctl_scm_inst_get_val 203 * 204 * As svcctl_scm_pg_get_val(), except look the property group up in an 205 * instance. If "use_running" is set, and the running snapshot exists, 206 * do a composed lookup there. Otherwise, do an (optionally composed) 207 * lookup on the current values. Note that lookups using snapshots are 208 * always composed. 209 */ 210 static int 211 svcctl_scm_inst_get_val(svcctl_manager_context_t *mgr_ctx, scf_instance_t *inst, 212 const char *pgname, const char *propname, scf_type_t ty, void *vp, 213 size_t sz, uint_t flags, int use_running, int composed) 214 { 215 scf_snapshot_t *snap = NULL; 216 int r; 217 218 if (use_running) 219 snap = svcctl_scm_get_running_snapshot(mgr_ctx, inst); 220 if (composed || use_running) 221 r = scf_instance_get_pg_composed(inst, snap, pgname, 222 mgr_ctx->mc_scf_gpg); 223 else 224 r = scf_instance_get_pg(inst, pgname, mgr_ctx->mc_scf_gpg); 225 if (snap) 226 scf_snapshot_destroy(snap); 227 if (r == -1) 228 return (-1); 229 230 r = svcctl_scm_pg_get_val(mgr_ctx, mgr_ctx->mc_scf_gpg, propname, ty, 231 vp, sz, flags); 232 233 return (r); 234 } 235 236 /* 237 * svcctl_scm_get_restarter_string_prop 238 * 239 * Get a string property from the restarter property group of the given 240 * instance. Return an empty string on normal problems. 241 */ 242 static void 243 svcctl_scm_get_restarter_string_prop(svcctl_manager_context_t *mgr_ctx, 244 scf_instance_t *inst, const char *pname, char *buf, size_t buf_sz) 245 { 246 if (svcctl_scm_inst_get_val(mgr_ctx, inst, SCF_PG_RESTARTER, pname, 247 SCF_TYPE_ASTRING, buf, buf_sz, 0, 0, 1) != 0) 248 *buf = '\0'; 249 } 250 251 /* 252 * svcctl_scm_svc_transitioning 253 * 254 * Return true if a service instance is transitioning. 255 */ 256 static int 257 svcctl_scm_svc_transitioning(svcctl_manager_context_t *mgr_ctx, 258 scf_instance_t *inst) 259 { 260 char nstate_name[MAX_SCF_STATE_STRING_SZ]; 261 262 bzero(nstate_name, MAX_SCF_STATE_STRING_SZ); 263 svcctl_scm_get_restarter_string_prop(mgr_ctx, inst, 264 SCF_PROPERTY_NEXT_STATE, nstate_name, sizeof (nstate_name)); 265 266 return ((*nstate_name == '\0')); 267 } 268 269 /* 270 * svcctl_scm_get_svcstate 271 * 272 * Gets the state of an SMF service. 273 */ 274 static int 275 svcctl_scm_get_svcstate(svcctl_manager_context_t *mgr_ctx, 276 char **buf, scf_walkinfo_t *wip) 277 { 278 char *state_name; 279 size_t max_state_size; 280 281 max_state_size = MAX_SCF_STATE_STRING_SZ + 1; 282 283 if ((state_name = malloc(max_state_size)) == NULL) 284 return (-1); 285 286 if (wip->pg == NULL) { 287 svcctl_scm_get_restarter_string_prop(mgr_ctx, wip->inst, 288 SCF_PROPERTY_STATE, state_name, max_state_size); 289 290 /* Don't print blank fields, to ease parsing. */ 291 if (state_name[0] == '\0') { 292 state_name[0] = '-'; 293 state_name[1] = '\0'; 294 } 295 296 if (svcctl_scm_svc_transitioning(mgr_ctx, wip->inst)) 297 /* Append an asterisk if new state is valid. */ 298 (void) strlcat(state_name, "*", max_state_size); 299 300 } else 301 (void) strlcpy(state_name, SCF_STATE_STRING_LEGACY, 302 max_state_size); 303 304 *buf = state_name; 305 return (0); 306 } 307 308 /* 309 * svcctl_scm_get_svcdesc 310 * 311 * Gets the description of an SMF service. 312 */ 313 static int 314 svcctl_scm_get_svcdesc(svcctl_manager_context_t *mgr_ctx, 315 char **buf, scf_walkinfo_t *wip) 316 { 317 char *x; 318 size_t newsize; 319 char *newbuf; 320 char *desc_buf = NULL; 321 322 if ((desc_buf = malloc(mgr_ctx->mc_scf_max_value_len + 1)) == NULL) 323 return (-1); 324 325 bzero(desc_buf, mgr_ctx->mc_scf_max_value_len + 1); 326 if (wip->pg != NULL) 327 desc_buf[0] = '-'; 328 else if (svcctl_scm_inst_get_val(mgr_ctx, wip->inst, 329 SCF_PG_TM_COMMON_NAME, "C", SCF_TYPE_USTRING, desc_buf, 330 mgr_ctx->mc_scf_max_value_len, 0, 1, 1) == -1) 331 desc_buf[0] = '-'; 332 333 /* 334 * Collapse multi-line tm_common_name values into a single line. 335 */ 336 for (x = desc_buf; *x != '\0'; x++) 337 if (*x == '\n') 338 *x = ' '; 339 340 newsize = strlen(desc_buf) + 1; 341 if ((newbuf = malloc(newsize)) == NULL) { 342 free(desc_buf); 343 return (-1); 344 } 345 346 (void) snprintf(newbuf, newsize, "%s", desc_buf); 347 free(desc_buf); 348 349 *buf = newbuf; 350 return (0); 351 } 352 353 /* 354 * svcctl_scm_get_svcfmri 355 * 356 * Gets the FMRI of an SMF service. 357 */ 358 static int 359 svcctl_scm_get_svcfmri(svcctl_manager_context_t *mgr_ctx, 360 char **buf, scf_walkinfo_t *wip) 361 { 362 size_t newsize; 363 char *newbuf; 364 char *fmri_buf = NULL; 365 void *fmri_p = NULL; 366 size_t fmri_size; 367 368 if ((fmri_buf = malloc(mgr_ctx->mc_scf_max_fmri_len + 1)) == NULL) 369 return (-1); 370 371 if (wip->pg == NULL) { 372 if (scf_instance_to_fmri(wip->inst, fmri_buf, 373 mgr_ctx->mc_scf_max_fmri_len + 1) == -1) { 374 free(fmri_buf); 375 return (-1); 376 } 377 } else { 378 (void) strlcpy(fmri_buf, SCF_FMRI_LEGACY_PREFIX, 379 mgr_ctx->mc_scf_max_fmri_len + 1); 380 381 fmri_p = fmri_buf + sizeof (SCF_FMRI_LEGACY_PREFIX) - 1; 382 fmri_size = mgr_ctx->mc_scf_max_fmri_len + 1 - \ 383 (sizeof (SCF_FMRI_LEGACY_PREFIX) - 1); 384 385 if (svcctl_scm_pg_get_val(mgr_ctx, wip->pg, 386 SCF_LEGACY_PROPERTY_NAME, SCF_TYPE_ASTRING, 387 fmri_p, fmri_size, 0) != 0) 388 (void) strlcat(fmri_buf, LEGACY_UNKNOWN, 389 mgr_ctx->mc_scf_max_fmri_len + 1); 390 } 391 392 newsize = strlen(fmri_buf) + 1; 393 if ((newbuf = malloc(newsize)) == NULL) { 394 free(fmri_buf); 395 return (-1); 396 } 397 398 (void) snprintf(newbuf, newsize, "%s", fmri_buf); 399 free(fmri_buf); 400 401 *buf = newbuf; 402 return (0); 403 } 404 405 /* 406 * svcctl_scm_get_svcname 407 * 408 * Gets the FMRI of an SMF service. 409 */ 410 static int 411 svcctl_scm_get_svcname(char **buf, char *fmri) 412 { 413 char *nm_buf = NULL; 414 char *newbuf; 415 size_t newsize; 416 417 if (fmri == NULL) 418 return (-1); 419 420 newsize = strlen(fmri); 421 if ((newbuf = malloc(newsize)) == NULL) 422 return (-1); 423 424 if ((nm_buf = strchr(fmri, '/')) == NULL) 425 return (-1); 426 427 (void) snprintf(newbuf, newsize, "%s", ++nm_buf); 428 *buf = newbuf; 429 return (0); 430 } 431 432 /* 433 * svcctl_scm_cb_list_svcinst 434 * 435 * Callback function to walk all the services in an SCF repository. 436 */ 437 static int 438 svcctl_scm_cb_list_svcinst(void *context, scf_walkinfo_t *wip) 439 { 440 svcctl_svc_node_t *node = NULL; 441 uu_avl_index_t idx; 442 svcctl_manager_context_t *mgr_ctx = (svcctl_manager_context_t *)context; 443 444 node = malloc(sizeof (*node)); 445 if (node == NULL) 446 return (-1); 447 448 node->sn_fmri = NULL; 449 if (svcctl_scm_get_svcfmri(mgr_ctx, &node->sn_fmri, wip) != 0) 450 return (-1); 451 452 node->sn_name = NULL; 453 if (svcctl_scm_get_svcname(&node->sn_name, node->sn_fmri) != 0) 454 return (-1); 455 456 node->sn_desc = NULL; 457 if (svcctl_scm_get_svcdesc(mgr_ctx, &node->sn_desc, wip) != 0) 458 return (-1); 459 460 node->sn_state = NULL; 461 if (svcctl_scm_get_svcstate(mgr_ctx, &node->sn_state, wip) != 0) 462 return (-1); 463 464 /* Insert into AVL tree. */ 465 uu_avl_node_init(node, &node->sn_node, mgr_ctx->mc_svcs_pool); 466 (void) uu_avl_find(mgr_ctx->mc_svcs, node, 467 &mgr_ctx->mc_scf_max_fmri_len, &idx); 468 uu_avl_insert(mgr_ctx->mc_svcs, node, idx); 469 470 return (0); 471 } 472 473 /* 474 * svcctl_scm_map_status 475 * 476 * Report the service status. 477 * 478 * The mapping between the Microsoft service states and SMF service states 479 * are as follows. 480 * 481 * SMF service states 482 * ================== 483 * SCF_STATE_UNINIT 0x00000001 484 * SCF_STATE_MAINT 0x00000002 485 * SCF_STATE_OFFLINE 0x00000004 486 * SCF_STATE_DISABLED 0x00000008 487 * SCF_STATE_ONLINE 0x00000010 488 * SCF_STATE_DEGRADED 0x00000020 489 * SCF_STATE_ALL 0x0000003F 490 * 491 * Microsoft service states 492 * ======================== 493 * SERVICE_CONTINUE_PENDING 0x00000005 494 * SERVICE_PAUSE_PENDING 0x00000006 495 * SERVICE_PAUSED 0x00000007 496 * SERVICE_RUNNING 0x00000004 497 * SERVICE_START_PENDING 0x00000002 498 * SERVICE_STOP_PENDING 0x00000003 499 * SERVICE_STOPPED 0x00000001 500 * 501 * Mapping 502 * ======= 503 * 504 * SCF_STATE_ONLINE <-> SERVICE_RUNNING 505 * SCF_STATE_OFFLINE <-> SERVICE_PAUSED 506 * SCF_STATE_DISABLED <-> SERVICE_STOPPED 507 * SCF_STATE_UNINIT <-> SERVICE_START_PENDING 508 * SCF_STATE_DEGRADED <-> SERVICE_STOP_PENDING 509 * SCF_STATE_MAINT <-> SERVICE_PAUSE_PENDING 510 * SCF_STATE_STRING_LEGACY <-> SERVICE_RUNNING 511 * Service Transitioning <-> SERVICE_STOP_PENDING 512 */ 513 uint32_t 514 svcctl_scm_map_status(const char *state) 515 { 516 int i; 517 518 struct { 519 const char *scf_state; 520 uint32_t scm_state; 521 } state_map[] = { 522 { SCF_STATE_STRING_ONLINE, SERVICE_RUNNING }, 523 { SCF_STATE_STRING_OFFLINE, SERVICE_PAUSED }, 524 { SCF_STATE_STRING_DISABLED, SERVICE_STOPPED }, 525 { SCF_STATE_STRING_UNINIT, SERVICE_START_PENDING }, 526 { SCF_STATE_STRING_DEGRADED, SERVICE_STOP_PENDING }, 527 { SCF_STATE_STRING_MAINT, SERVICE_PAUSE_PENDING }, 528 { SCF_STATE_STRING_LEGACY, SERVICE_RUNNING } 529 }; 530 531 for (i = 0; i < (sizeof (state_map)/sizeof (state_map[0])); ++i) { 532 if (strcmp(state, state_map[i].scf_state) == 0) 533 return (state_map[i].scm_state); 534 } 535 536 if (strrchr(state, '*') != 0) /* State Transitioning */ 537 return (SERVICE_STOP_PENDING); 538 539 return (SERVICE_RUNNING); 540 } 541 542 /* 543 * svcctl_scm_enum_services 544 * 545 * Enumerates SMF services: handles wide-char or ascii requests. 546 * 547 * Returns the number of services written to buf. 548 */ 549 uint32_t 550 svcctl_scm_enum_services(svcctl_manager_context_t *mgr_ctx, uint8_t *buf, 551 size_t buflen, uint32_t *resume_handle, boolean_t use_wchar) 552 { 553 svcctl_svc_node_t *node; 554 int base_offset, offset; 555 smb_wchar_t *w_name; 556 char *a_name; 557 char *node_name; 558 size_t namelen; 559 uint32_t numsvcs = mgr_ctx->mc_scf_numsvcs; 560 uint32_t ns; 561 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 562 svc_enum_status_t *svc = (svc_enum_status_t *)buf; 563 564 if (buf == NULL || buflen == 0 || *resume_handle >= numsvcs) { 565 *resume_handle = 0; 566 return (0); 567 } 568 569 base_offset = numsvcs * sizeof (svc_enum_status_t); 570 if (buflen < mgr_ctx->mc_bytes_needed) { 571 while (base_offset > (buflen / 4)) { 572 --numsvcs; 573 base_offset = numsvcs * sizeof (svc_enum_status_t); 574 } 575 } 576 577 offset = buflen; 578 node = uu_avl_first(mgr_ctx->mc_svcs); 579 580 for (ns = 0; ((ns < *resume_handle) && (node != NULL)); ++ns) 581 node = uu_avl_next(mgr_ctx->mc_svcs, node); 582 583 if (node == NULL) { 584 *resume_handle = 0; 585 return (0); 586 } 587 588 for (ns = 0; ((ns < numsvcs) && (node != NULL)); ++ns) { 589 node_name = node->sn_name; 590 namelen = strlen(node_name) + 1; 591 if (use_wchar) { 592 offset -= SVCCTL_WNSTRLEN(node_name); 593 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 594 w_name = (smb_wchar_t *)&buf[offset]; 595 (void) smb_mbstowcs(w_name, node_name, namelen); 596 } else { 597 offset -= namelen; 598 a_name = (char *)&buf[offset]; 599 (void) strlcpy(a_name, node_name, namelen); 600 } 601 svc[ns].svc_name = offset; 602 603 if (offset <= base_offset) 604 break; 605 606 node_name = node->sn_fmri; 607 namelen = strlen(node_name) + 1; 608 if (use_wchar) { 609 offset -= SVCCTL_WNSTRLEN(node_name); 610 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 611 w_name = (smb_wchar_t *)&buf[offset]; 612 (void) smb_mbstowcs(w_name, node_name, namelen); 613 } else { 614 offset -= namelen; 615 a_name = (char *)&buf[offset]; 616 (void) strlcpy(a_name, node_name, namelen); 617 } 618 svc[ns].display_name = offset; 619 620 if (offset <= base_offset) 621 break; 622 623 svc[ns].svc_status.cur_state = 624 svcctl_scm_map_status(node->sn_state); 625 svc[ns].svc_status.service_type = SERVICE_WIN32_SHARE_PROCESS; 626 svc[ns].svc_status.ctrl_accepted = 0; 627 svc[ns].svc_status.w32_exitcode = 0; 628 svc[ns].svc_status.svc_specified_exitcode = 0; 629 svc[ns].svc_status.check_point = 0; 630 svc[ns].svc_status.wait_hint = 0; 631 632 node = uu_avl_next(mgr_ctx->mc_svcs, node); 633 } 634 635 if (node == NULL) { 636 *resume_handle = 0; 637 } else { 638 *resume_handle += ns; 639 640 if (*resume_handle >= mgr_ctx->mc_scf_numsvcs) 641 *resume_handle = 0; 642 } 643 644 return (ns); 645 } 646 647 /* 648 * svcctl_scm_cb_bytes_needed 649 * 650 * Callback function to calculate bytes needed to enumerate SMF services. 651 */ 652 static int 653 svcctl_scm_cb_bytes_needed(void *svc_node, void *byte_cnt) 654 { 655 svcctl_svc_node_t *node = svc_node; 656 int *cnt = byte_cnt; 657 658 *cnt += (strlen(node->sn_fmri) + 1) * sizeof (smb_wchar_t); 659 *cnt += (strlen(node->sn_name) + 1) * sizeof (smb_wchar_t); 660 661 return (UU_WALK_NEXT); 662 } 663 664 /* 665 * svcctl_scm_bytes_needed 666 * 667 * Calculates bytes needed to enumerate SMF services. 668 */ 669 static void 670 svcctl_scm_bytes_needed(svcctl_manager_context_t *mgr_ctx) 671 { 672 int bytes_needed = 0, svc_enum_status_size = 0; 673 674 (void) uu_avl_walk(mgr_ctx->mc_svcs, svcctl_scm_cb_bytes_needed, 675 &bytes_needed, 0); 676 677 svc_enum_status_size = 678 mgr_ctx->mc_scf_numsvcs * sizeof (svc_enum_status_t); 679 bytes_needed += svc_enum_status_size; 680 681 mgr_ctx->mc_bytes_needed = bytes_needed; 682 } 683 684 /* 685 * svcctl_scm_validate_service 686 * 687 * Check to see whether or not a service is supported. 688 * 689 * Returns: 690 * ERROR_SUCCESS 691 * ERROR_SERVICE_DOES_NOT_EXIST 692 */ 693 uint32_t 694 svcctl_scm_validate_service(svcctl_manager_context_t *mgr_ctx, char *svc_name) 695 { 696 if (svcctl_scm_find_service(mgr_ctx, svc_name) != NULL) 697 return (ERROR_SUCCESS); 698 699 return (ERROR_SERVICE_DOES_NOT_EXIST); 700 } 701 702 /* 703 * svcctl_scm_map_windows_svc 704 * 705 * Windows client send windows service name. This method maps windows 706 * service names to Solaris service names. 707 */ 708 static char * 709 svcctl_scm_map_windows_svc(char *svc_name) 710 { 711 int i, size = 0; 712 struct { 713 char *win_svc_name; 714 char *solaris_svc_name; 715 } win2solaris_svc_map[] = { 716 { "eventlog", "system/system-log:default" }, 717 { "RemoteRegistry", "system/svc/restarter:default" }, 718 { "spooler", "application/print/ppd-cache-update:default" } 719 }; 720 721 size = sizeof (win2solaris_svc_map)/sizeof (win2solaris_svc_map[0]); 722 for (i = 0; i < size; ++i) { 723 if (strcasecmp(svc_name, 724 win2solaris_svc_map[i].win_svc_name) == 0) 725 return (win2solaris_svc_map[i].solaris_svc_name); 726 } 727 728 return (NULL); 729 } 730 731 /* 732 * svcctl_scm_find_service 733 * 734 * Lookup a service. 735 */ 736 svcctl_svc_node_t * 737 svcctl_scm_find_service(svcctl_manager_context_t *mgr_ctx, char *svc_name) 738 { 739 svcctl_svc_node_t node; 740 uu_avl_index_t idx; 741 svcctl_svc_node_t *f_node = NULL; 742 743 if (svc_name == NULL) 744 return (NULL); 745 746 bzero(&node, sizeof (svcctl_svc_node_t)); 747 node.sn_name = svc_name; 748 f_node = uu_avl_find(mgr_ctx->mc_svcs, &node, 749 &mgr_ctx->mc_scf_max_fmri_len, &idx); 750 if (f_node != NULL) 751 return (f_node); 752 753 bzero(&node, sizeof (svcctl_svc_node_t)); 754 node.sn_name = svcctl_scm_map_windows_svc(svc_name); 755 if (node.sn_name != NULL) 756 f_node = uu_avl_find(mgr_ctx->mc_svcs, &node, 757 &mgr_ctx->mc_scf_max_fmri_len, &idx); 758 759 return (f_node); 760 } 761 762 /* 763 * svcctl_scm_refresh 764 * 765 * Refresh SCM services per context. 766 */ 767 int 768 svcctl_scm_refresh(svcctl_manager_context_t *mgr_ctx) 769 { 770 svcctl_scm_fini(mgr_ctx); 771 772 if (svcctl_scm_ops.svcctl_op_scm_init != NULL) 773 return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx)); 774 775 return (svcctl_scm_init(mgr_ctx)); 776 } 777 778 /* 779 * svcctl_scm_scf_handle_init 780 * 781 * Initialize SCF handle per context. 782 */ 783 int 784 svcctl_scm_scf_handle_init(svcctl_manager_context_t *mgr_ctx) 785 { 786 if (svcctl_scm_ops.svcctl_op_scf_init != NULL) 787 return (svcctl_scm_ops. 788 svcctl_op_scf_init(mgr_ctx)); 789 790 mgr_ctx->mc_scf_hdl = scf_handle_create(SCF_VERSION); 791 if (mgr_ctx->mc_scf_hdl == NULL) 792 return (-1); 793 794 if (scf_handle_bind(mgr_ctx->mc_scf_hdl) == -1) { 795 scf_handle_destroy(mgr_ctx->mc_scf_hdl); 796 return (-1); 797 } 798 799 mgr_ctx->mc_scf_gpg = scf_pg_create(mgr_ctx->mc_scf_hdl); 800 mgr_ctx->mc_scf_gprop = scf_property_create(mgr_ctx->mc_scf_hdl); 801 mgr_ctx->mc_scf_gval = scf_value_create(mgr_ctx->mc_scf_hdl); 802 803 if ((mgr_ctx->mc_scf_gpg == NULL) || 804 (mgr_ctx->mc_scf_gprop == NULL) || 805 (mgr_ctx->mc_scf_gval == NULL)) { 806 (void) scf_handle_unbind(mgr_ctx->mc_scf_hdl); 807 scf_handle_destroy(mgr_ctx->mc_scf_hdl); 808 return (-1); 809 } 810 811 mgr_ctx->mc_scf_max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 812 mgr_ctx->mc_scf_max_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 813 814 return (0); 815 } 816 817 /* 818 * svcctl_scm_scf_handle_init 819 * 820 * Destroy SCF handle per context. 821 */ 822 void 823 svcctl_scm_scf_handle_fini(svcctl_manager_context_t *mgr_ctx) 824 { 825 scf_value_destroy(mgr_ctx->mc_scf_gval); 826 scf_property_destroy(mgr_ctx->mc_scf_gprop); 827 scf_pg_destroy(mgr_ctx->mc_scf_gpg); 828 829 if (mgr_ctx->mc_scf_hdl != NULL) { 830 (void) scf_handle_unbind(mgr_ctx->mc_scf_hdl); 831 scf_handle_destroy(mgr_ctx->mc_scf_hdl); 832 } 833 } 834 835 /* 836 * svcctl_scm_init 837 * 838 * Initialize SCM repository per context. 839 * SCM repository holds a list of SMF services. 840 * Each SMF service node contains state, description and FMRI. 841 */ 842 int 843 svcctl_scm_init(svcctl_manager_context_t *mgr_ctx) 844 { 845 int exit_status = 0; 846 847 assert(mgr_ctx->mc_svcs_pool == NULL); 848 assert(mgr_ctx->mc_svcs == NULL); 849 850 if (svcctl_scm_ops.svcctl_op_scm_init != NULL) 851 return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx)); 852 853 mgr_ctx->mc_svcs_pool = uu_avl_pool_create("smf_svcs_pool", 854 sizeof (svcctl_svc_node_t), offsetof(svcctl_svc_node_t, sn_node), 855 svcctl_scm_avl_nodecmp, UU_AVL_DEBUG); 856 857 if (mgr_ctx->mc_svcs_pool == NULL) 858 return (-1); 859 860 mgr_ctx->mc_svcs = uu_avl_create(mgr_ctx->mc_svcs_pool, NULL, 0); 861 if (mgr_ctx->mc_svcs == NULL) { 862 uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool); 863 return (-1); 864 } 865 866 if (scf_walk_fmri(mgr_ctx->mc_scf_hdl, 0, NULL, 867 SCF_WALK_MULTIPLE | SCF_WALK_LEGACY, 868 svcctl_scm_cb_list_svcinst, mgr_ctx, &exit_status, NULL) != 0) { 869 uu_avl_destroy(mgr_ctx->mc_svcs); 870 uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool); 871 return (-1); 872 } 873 874 mgr_ctx->mc_scf_numsvcs = uu_avl_numnodes(mgr_ctx->mc_svcs); 875 if (mgr_ctx->mc_scf_numsvcs > 0) 876 svcctl_scm_bytes_needed(mgr_ctx); 877 878 return (0); 879 } 880 881 /* 882 * svcctl_scm_fini 883 * 884 * Destroy SCM repository per context. 885 */ 886 void 887 svcctl_scm_fini(svcctl_manager_context_t *mgr_ctx) 888 { 889 uu_avl_walk_t *walk; 890 svcctl_svc_node_t *node; 891 892 if ((mgr_ctx == NULL) || (mgr_ctx->mc_svcs_pool == NULL) || 893 (mgr_ctx->mc_svcs == NULL)) 894 return; 895 896 if ((walk = 897 uu_avl_walk_start(mgr_ctx->mc_svcs, UU_WALK_ROBUST)) == NULL) 898 return; 899 900 while ((node = uu_avl_walk_next(walk)) != NULL) { 901 uu_avl_remove(mgr_ctx->mc_svcs, node); 902 free(node->sn_name); 903 free(node->sn_fmri); 904 free(node->sn_desc); 905 free(node->sn_state); 906 free(node); 907 } 908 uu_avl_walk_end(walk); 909 uu_avl_destroy(mgr_ctx->mc_svcs); 910 uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool); 911 mgr_ctx->mc_svcs_pool = NULL; 912 mgr_ctx->mc_svcs = NULL; 913 } 914 915 /* 916 * svcctl_init 917 * 918 * Initializes the SVCCTL service. 919 * Initializes handle and ops structure to interposed library. 920 */ 921 void 922 svcctl_init(void) 923 { 924 svcctl_scm_interposer_hdl = smb_dlopen(); 925 if (svcctl_scm_interposer_hdl == NULL) 926 return; 927 928 bzero((void *)&svcctl_scm_ops, 929 sizeof (svcctl_scm_ops)); 930 931 svcctl_scm_ops.svcctl_op_scm_init = 932 (int (*)())dlsym(svcctl_scm_interposer_hdl, "svcctl_scm_init"); 933 934 svcctl_scm_ops.svcctl_op_scf_init = 935 (int (*)())dlsym(svcctl_scm_interposer_hdl, 936 "svcctl_scm_scf_handle_init"); 937 938 if (svcctl_scm_ops.svcctl_op_scm_init == NULL || 939 svcctl_scm_ops.svcctl_op_scf_init == NULL) 940 svcctl_fini(); 941 942 } 943 944 /* 945 * svcctl_fini 946 * 947 * Finalizes the SVCCTL service. 948 * Closes handle to interposed library. 949 */ 950 void 951 svcctl_fini(void) 952 { 953 smb_dlclose(svcctl_scm_interposer_hdl); 954 svcctl_scm_interposer_hdl = NULL; 955 bzero((void *)&svcctl_scm_ops, 956 sizeof (svcctl_scm_ops)); 957 } 958