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