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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Config routines common to idmap(1M) and idmapd(1M) 30 */ 31 32 #include <stdlib.h> 33 #include <strings.h> 34 #include <libintl.h> 35 #include <ctype.h> 36 #include <errno.h> 37 #include "idmapd.h" 38 #include <stdio.h> 39 #include <stdarg.h> 40 #include <uuid/uuid.h> 41 #include <pthread.h> 42 #include <port.h> 43 #include <net/route.h> 44 #include "addisc.h" 45 46 #define MACHINE_SID_LEN (9 + UUID_LEN/4 * 11) 47 #define FMRI_BASE "svc:/system/idmap" 48 #define CONFIG_PG "config" 49 #define GENERAL_PG "general" 50 #define RECONFIGURE 1 51 #define POKE_AUTO_DISCOVERY 2 52 53 /*LINTLIBRARY*/ 54 55 56 static pthread_t update_thread_handle = 0; 57 58 static int idmapd_ev_port = -1; 59 static int rt_sock = -1; 60 61 static int 62 generate_machine_sid(char **machine_sid) 63 { 64 char *p; 65 uuid_t uu; 66 int i, j, len, rlen; 67 uint32_t rid; 68 69 /* 70 * Generate and split 128-bit UUID into four 32-bit RIDs 71 * The machine_sid will be of the form S-1-5-N1-N2-N3-N4 72 * We depart from Windows here, which instead of 128 73 * bits worth of random numbers uses 96 bits. 74 */ 75 76 *machine_sid = calloc(1, MACHINE_SID_LEN); 77 if (*machine_sid == NULL) { 78 idmapdlog(LOG_ERR, "Out of memory"); 79 return (-1); 80 } 81 (void) strcpy(*machine_sid, "S-1-5-21"); 82 p = *machine_sid + strlen("S-1-5-21"); 83 len = MACHINE_SID_LEN - strlen("S-1-5-21"); 84 85 uuid_clear(uu); 86 uuid_generate_random(uu); 87 88 for (i = 0; i < UUID_LEN/4; i++) { 89 j = i * 4; 90 rid = (uu[j] << 24) | (uu[j + 1] << 16) | 91 (uu[j + 2] << 8) | (uu[j + 3]); 92 rlen = snprintf(p, len, "-%u", rid); 93 p += rlen; 94 len -= rlen; 95 } 96 97 return (0); 98 } 99 100 static bool_t 101 prop_exists(idmap_cfg_handles_t *handles, char *name) 102 { 103 bool_t exists = FALSE; 104 105 scf_property_t *scf_prop = scf_property_create(handles->main); 106 scf_value_t *value = scf_value_create(handles->main); 107 108 if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0) 109 exists = TRUE; 110 111 scf_value_destroy(value); 112 scf_property_destroy(scf_prop); 113 114 return (exists); 115 } 116 117 /* Check if in the case of failure the original value of *val is preserved */ 118 static int 119 get_val_int(idmap_cfg_handles_t *handles, char *name, 120 void *val, scf_type_t type) 121 { 122 int rc = 0; 123 124 scf_property_t *scf_prop = scf_property_create(handles->main); 125 scf_value_t *value = scf_value_create(handles->main); 126 127 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 128 /* this is OK: the property is just undefined */ 129 goto destruction; 130 131 132 if (scf_property_get_value(scf_prop, value) < 0) 133 /* It is still OK when a property doesn't have any value */ 134 goto destruction; 135 136 switch (type) { 137 case SCF_TYPE_BOOLEAN: 138 rc = scf_value_get_boolean(value, val); 139 break; 140 case SCF_TYPE_COUNT: 141 rc = scf_value_get_count(value, val); 142 break; 143 case SCF_TYPE_INTEGER: 144 rc = scf_value_get_integer(value, val); 145 break; 146 default: 147 idmapdlog(LOG_ERR, "Invalid scf integer type (%d)", 148 type); 149 rc = -1; 150 break; 151 } 152 153 154 destruction: 155 scf_value_destroy(value); 156 scf_property_destroy(scf_prop); 157 158 return (rc); 159 } 160 161 static char * 162 scf_value2string(scf_value_t *value) 163 { 164 int rc = -1; 165 char buf_size = 127; 166 int length; 167 char *buf = NULL; 168 buf = (char *) malloc(sizeof (char) * buf_size); 169 170 for (;;) { 171 length = scf_value_get_astring(value, buf, buf_size); 172 if (length < 0) { 173 rc = -1; 174 goto destruction; 175 } 176 177 if (length == buf_size - 1) { 178 buf_size *= 2; 179 buf = (char *)realloc(buf, buf_size * sizeof (char)); 180 if (!buf) { 181 idmapdlog(LOG_ERR, "Out of memory"); 182 rc = -1; 183 goto destruction; 184 } 185 } else { 186 rc = 0; 187 break; 188 } 189 } 190 191 destruction: 192 if (rc < 0) { 193 if (buf) 194 free(buf); 195 buf = NULL; 196 } 197 198 return (buf); 199 } 200 201 static int 202 get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport, 203 ad_disc_ds_t **val) 204 { 205 ad_disc_ds_t *servers = NULL; 206 scf_property_t *scf_prop; 207 scf_value_t *value; 208 scf_iter_t *iter; 209 char *host, *portstr; 210 int len, i; 211 int count = 0; 212 int rc = -1; 213 214 *val = NULL; 215 216 restart: 217 scf_prop = scf_property_create(handles->main); 218 value = scf_value_create(handles->main); 219 iter = scf_iter_create(handles->main); 220 221 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) { 222 /* this is OK: the property is just undefined */ 223 rc = 0; 224 goto destruction; 225 } 226 227 if (scf_iter_property_values(iter, scf_prop) < 0) { 228 idmapdlog(LOG_ERR, 229 "scf_iter_property_values(%s) failed: %s", 230 name, scf_strerror(scf_error())); 231 goto destruction; 232 } 233 234 /* Workaround scf bugs -- can't reset an iteration */ 235 if (count == 0) { 236 while (scf_iter_next_value(iter, value) > 0) 237 count++; 238 239 if (count == 0) { 240 /* no values */ 241 rc = 0; 242 goto destruction; 243 } 244 245 scf_value_destroy(value); 246 scf_iter_destroy(iter); 247 scf_property_destroy(scf_prop); 248 goto restart; 249 } 250 251 if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) { 252 idmapdlog(LOG_ERR, "Out of memory"); 253 goto destruction; 254 } 255 256 i = 0; 257 while (i < count && scf_iter_next_value(iter, value) > 0) { 258 servers[i].priority = 0; 259 servers[i].weight = 100; 260 servers[i].port = defport; 261 if ((host = scf_value2string(value)) == NULL) { 262 goto destruction; 263 } 264 if ((portstr = strchr(host, ':')) != NULL) { 265 *portstr++ = '\0'; 266 servers[i].port = strtol(portstr, 267 (char **)NULL, 10); 268 if (servers[i].port == 0) 269 servers[i].port = defport; 270 } 271 len = strlcpy(servers[i].host, host, 272 sizeof (servers->host)); 273 274 free(host); 275 276 /* Ignore this server if the hostname is too long */ 277 if (len < sizeof (servers->host)) 278 i++; 279 } 280 281 *val = servers; 282 283 rc = 0; 284 285 destruction: 286 scf_value_destroy(value); 287 scf_iter_destroy(iter); 288 scf_property_destroy(scf_prop); 289 290 if (rc < 0) { 291 if (servers) 292 free(servers); 293 *val = NULL; 294 } 295 296 return (rc); 297 } 298 299 300 static int 301 get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val) 302 { 303 int rc = 0; 304 305 scf_property_t *scf_prop = scf_property_create(handles->main); 306 scf_value_t *value = scf_value_create(handles->main); 307 308 *val = NULL; 309 310 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 311 /* this is OK: the property is just undefined */ 312 goto destruction; 313 314 if (scf_property_get_value(scf_prop, value) < 0) { 315 idmapdlog(LOG_ERR, 316 "scf_property_get_value(%s) failed: %s", 317 name, scf_strerror(scf_error())); 318 rc = -1; 319 goto destruction; 320 } 321 322 if (!(*val = scf_value2string(value))) 323 rc = -1; 324 325 destruction: 326 scf_value_destroy(value); 327 scf_property_destroy(scf_prop); 328 329 if (rc < 0) { 330 if (*val) 331 free(*val); 332 *val = NULL; 333 } 334 335 return (rc); 336 } 337 338 339 static int 340 set_val_astring(idmap_cfg_handles_t *handles, char *name, const char *val) 341 { 342 int rc = -1; 343 int ret = -2; 344 int i; 345 scf_property_t *scf_prop = NULL; 346 scf_value_t *value = NULL; 347 scf_transaction_t *tx = NULL; 348 scf_transaction_entry_t *ent = NULL; 349 350 if ((scf_prop = scf_property_create(handles->main)) == NULL || 351 (value = scf_value_create(handles->main)) == NULL || 352 (tx = scf_transaction_create(handles->main)) == NULL || 353 (ent = scf_entry_create(handles->main)) == NULL) { 354 idmapdlog(LOG_ERR, "Unable to set property %s", 355 name, scf_strerror(scf_error())); 356 goto destruction; 357 } 358 359 for (i = 0; i < MAX_TRIES && (ret == -2 || ret == 0); i++) { 360 if (scf_transaction_start(tx, handles->config_pg) == -1) { 361 idmapdlog(LOG_ERR, 362 "scf_transaction_start(%s) failed: %s", 363 name, scf_strerror(scf_error())); 364 goto destruction; 365 } 366 367 if (scf_transaction_property_new(tx, ent, name, 368 SCF_TYPE_ASTRING) < 0) { 369 idmapdlog(LOG_ERR, 370 "scf_transaction_property_new() failed: %s", 371 scf_strerror(scf_error())); 372 goto destruction; 373 } 374 375 if (scf_value_set_astring(value, val) == -1) { 376 idmapdlog(LOG_ERR, 377 "scf_value_set_astring() failed: %s", 378 scf_strerror(scf_error())); 379 goto destruction; 380 } 381 382 if (scf_entry_add_value(ent, value) == -1) { 383 idmapdlog(LOG_ERR, 384 "scf_entry_add_value() failed: %s", 385 scf_strerror(scf_error())); 386 goto destruction; 387 } 388 389 if ((ret = scf_transaction_commit(tx)) == 1) 390 break; 391 392 if (ret == 0 && i < MAX_TRIES - 1) { 393 /* 394 * Property group set in scf_transaction_start() 395 * is not the most recent. Update pg, reset tx and 396 * retry tx. 397 */ 398 idmapdlog(LOG_WARNING, 399 "scf_transaction_commit(%s) failed - Retry: %s", 400 name, scf_strerror(scf_error())); 401 if (scf_pg_update(handles->config_pg) == -1) { 402 idmapdlog(LOG_ERR, 403 "scf_pg_update() failed: %s", 404 scf_strerror(scf_error())); 405 goto destruction; 406 } 407 scf_transaction_reset(tx); 408 } 409 } 410 411 412 if (ret == 1) 413 rc = 0; 414 else if (ret != -2) 415 idmapdlog(LOG_ERR, 416 "scf_transaction_commit(%s) failed: %s", 417 name, scf_strerror(scf_error())); 418 419 destruction: 420 scf_value_destroy(value); 421 scf_entry_destroy(ent); 422 scf_transaction_destroy(tx); 423 scf_property_destroy(scf_prop); 424 return (rc); 425 } 426 427 static int 428 update_value(char **value, char **new, char *name) 429 { 430 if (*new == NULL) 431 return (FALSE); 432 433 if (*value != NULL && strcmp(*new, *value) == 0) { 434 free(*new); 435 *new = NULL; 436 return (FALSE); 437 } 438 439 idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new)); 440 if (*value != NULL) 441 free(*value); 442 *value = *new; 443 *new = NULL; 444 return (TRUE); 445 } 446 447 static int 448 update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new, char *name) 449 { 450 int i; 451 452 if (*value == *new) 453 /* Nothing to do */ 454 return (FALSE); 455 456 if (*value != NULL && *new != NULL && 457 ad_disc_compare_ds(*value, *new) == 0) { 458 free(*new); 459 *new = NULL; 460 return (FALSE); 461 } 462 463 if (*value) 464 free(*value); 465 466 *value = *new; 467 *new = NULL; 468 469 if (*value == NULL) { 470 /* We're unsetting this DS property */ 471 idmapdlog(LOG_INFO, "change %s=<none>", name); 472 return (TRUE); 473 } 474 475 /* List all the new DSs */ 476 for (i = 0; (*value)[i].host[0] != '\0'; i++) 477 idmapdlog(LOG_INFO, "change %s=%s port=%d", name, 478 (*value)[i].host, (*value)[i].port); 479 return (TRUE); 480 } 481 482 483 #define MAX_CHECK_TIME (20 * 60) 484 485 /* 486 * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the 487 * interfaces. 488 * 489 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON. 490 */ 491 static 492 int 493 pfroute_event_is_interesting(int rt_sock) 494 { 495 int nbytes; 496 int64_t msg[2048 / 8]; 497 struct rt_msghdr *rtm; 498 int is_interesting = FALSE; 499 500 for (;;) { 501 if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0) 502 break; 503 rtm = (struct rt_msghdr *)msg; 504 if (rtm->rtm_version != RTM_VERSION) 505 continue; 506 if (nbytes < rtm->rtm_msglen) 507 continue; 508 switch (rtm->rtm_type) { 509 case RTM_NEWADDR: 510 case RTM_DELADDR: 511 case RTM_IFINFO: 512 is_interesting = TRUE; 513 break; 514 default: 515 break; 516 } 517 } 518 return (is_interesting); 519 } 520 521 /* 522 * Returns 1 if SIGHUP has been received (see hup_handler() elsewhere) or if an 523 * interface address was added or removed; otherwise it returns 0. 524 * 525 * Note that port_get() does not update its timeout argument when EINTR, unlike 526 * nanosleep(). We probably don't care very much here, but if we did care then 527 * we could always use a timer event and associate it with the same event port, 528 * then we could get accurate waiting regardless of EINTRs. 529 */ 530 static 531 int 532 wait_for_event(int poke_is_interesting, struct timespec *timeout) 533 { 534 port_event_t pe; 535 536 retry: 537 memset(&pe, 0, sizeof (pe)); 538 if (port_get(idmapd_ev_port, &pe, timeout) != 0) { 539 switch (errno) { 540 case EINTR: 541 goto retry; 542 case ETIME: 543 /* Timeout */ 544 return (FALSE); 545 default: 546 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */ 547 idmapdlog(LOG_ERR, "Event port failed: %s", 548 strerror(errno)); 549 exit(1); 550 /* NOTREACHED */ 551 break; 552 } 553 } 554 555 if (pe.portev_source == PORT_SOURCE_USER && 556 pe.portev_events == POKE_AUTO_DISCOVERY) 557 return (poke_is_interesting ? TRUE : FALSE); 558 559 if (pe.portev_source == PORT_SOURCE_FD && pe.portev_object == rt_sock) { 560 /* PF_ROUTE socket read event, re-associate fd, handle event */ 561 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock, 562 POLLIN, NULL) != 0) { 563 idmapdlog(LOG_ERR, "Failed to re-associate the " 564 "routing socket with the event port: %s", 565 strerror(errno)); 566 exit(1); 567 } 568 /* 569 * The network configuration may still be in flux. No matter, 570 * the resolver will re-transmit and timout if need be. 571 */ 572 return (pfroute_event_is_interesting(rt_sock)); 573 } 574 575 if (pe.portev_source == PORT_SOURCE_USER && 576 pe.portev_events == RECONFIGURE) { 577 int rc; 578 579 /* 580 * Blow away the ccache, we might have re-joined the 581 * domain or joined a new one 582 */ 583 (void) unlink(IDMAP_CACHEDIR "/ccache"); 584 /* HUP is the refresh method, so re-read SMF config */ 585 (void) idmapdlog(LOG_INFO, "SMF refresh"); 586 WRLOCK_CONFIG(); 587 (void) idmap_cfg_unload(&_idmapdstate.cfg->pgcfg); 588 rc = idmap_cfg_load(&_idmapdstate.cfg->handles, 589 &_idmapdstate.cfg->pgcfg, 1); 590 if (rc < -1) 591 (void) idmapdlog(LOG_ERR, 592 "Various errors re-loading configuration " 593 "will cause AD lookups to fail"); 594 else if (rc == -1) 595 (void) idmapdlog(LOG_WARNING, 596 "Various errors re-loading configuration " 597 "may cause AD lookups to fail"); 598 UNLOCK_CONFIG(); 599 return (TRUE); 600 } 601 602 return (FALSE); 603 } 604 605 void * 606 idmap_cfg_update_thread(void *arg) 607 { 608 609 idmap_pg_config_t new_cfg; 610 int ttl, changed, poke_is_interesting; 611 idmap_cfg_handles_t *handles = &_idmapdstate.cfg->handles; 612 idmap_pg_config_t *live_cfg = &_idmapdstate.cfg->pgcfg; 613 ad_disc_t ad_ctx = handles->ad_ctx; 614 struct timespec timeout; 615 616 (void) memset(&new_cfg, 0, sizeof (new_cfg)); 617 618 poke_is_interesting = 1; 619 for (ttl = 0, changed = TRUE; ; ttl = ad_disc_get_TTL(ad_ctx)) { 620 if (ttl < 0 || ttl > MAX_CHECK_TIME) { 621 ttl = MAX_CHECK_TIME; 622 } 623 timeout.tv_sec = ttl; 624 timeout.tv_nsec = 0; 625 changed = wait_for_event(poke_is_interesting, &timeout); 626 627 /* 628 * If there are no interesting events, and this is not the first 629 * time through the loop, and we haven't waited the most that 630 * we're willing to wait, so do nothing but wait some more. 631 */ 632 if (changed == FALSE && ttl > 0 && ttl < MAX_CHECK_TIME) 633 continue; 634 635 (void) ad_disc_SubnetChanged(ad_ctx); 636 637 /* 638 * Load configuration data into a private copy. 639 * 640 * The fixed values (i.e., from SMF) have already been set in AD 641 * auto discovery, so if all values have been set in SMF and 642 * they haven't been changed or the service been refreshed then 643 * the rest of this loop's body is one big no-op. 644 */ 645 ad_disc_refresh(ad_ctx); 646 new_cfg.default_domain = ad_disc_get_DomainName(ad_ctx); 647 if (new_cfg.default_domain == NULL) 648 idmapdlog(LOG_INFO, 649 "unable to discover Default Domain"); 650 651 new_cfg.domain_name = ad_disc_get_DomainName(ad_ctx); 652 if (new_cfg.domain_name == NULL) 653 idmapdlog(LOG_INFO, 654 "unable to discover Domain Name"); 655 656 new_cfg.domain_controller = 657 ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE); 658 if (new_cfg.domain_controller == NULL) 659 idmapdlog(LOG_INFO, 660 "unable to discover Domain Controller"); 661 662 new_cfg.forest_name = ad_disc_get_ForestName(ad_ctx); 663 if (new_cfg.forest_name == NULL) 664 idmapdlog(LOG_INFO, 665 "unable to discover Forest Name"); 666 667 new_cfg.site_name = ad_disc_get_SiteName(ad_ctx); 668 if (new_cfg.site_name == NULL) 669 idmapdlog(LOG_INFO, 670 "unable to discover Site Name"); 671 672 new_cfg.global_catalog = 673 ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE); 674 if (new_cfg.global_catalog == NULL) { 675 idmapdlog(LOG_INFO, 676 "unable to discover Global Catalog"); 677 poke_is_interesting = 1; 678 } else { 679 poke_is_interesting = 0; 680 } 681 682 if (new_cfg.default_domain == NULL && 683 new_cfg.domain_name == NULL && 684 new_cfg.domain_controller == NULL && 685 new_cfg.forest_name == NULL && 686 new_cfg.global_catalog == NULL) { 687 idmapdlog(LOG_NOTICE, "Could not auto-discover AD " 688 "domain and forest names nor domain controllers " 689 "and global catalog servers"); 690 } 691 692 /* 693 * Update the live configuration 694 */ 695 WRLOCK_CONFIG(); 696 697 if (live_cfg->list_size_limit != new_cfg.list_size_limit) { 698 idmapdlog(LOG_INFO, "change list_size=%d", 699 new_cfg.list_size_limit); 700 live_cfg->list_size_limit = new_cfg.list_size_limit; 701 } 702 703 /* 704 * Update running config and decide whether we want to call 705 * reload_ad() (i.e., if the default_domain changed or the GC 706 * list changed). 707 * 708 * If default_domain came from SMF then we must not 709 * auto-discover it. 710 */ 711 changed = FALSE; 712 if (live_cfg->dflt_dom_set_in_smf == FALSE && 713 update_value(&live_cfg->default_domain, 714 &new_cfg.default_domain, "default_domain") == TRUE) 715 changed = TRUE; 716 717 (void) update_value(&live_cfg->domain_name, 718 &new_cfg.domain_name, "domain_name"); 719 720 (void) update_dirs(&live_cfg->domain_controller, 721 &new_cfg.domain_controller, "domain_controller"); 722 723 (void) update_value(&live_cfg->forest_name, 724 &new_cfg.forest_name, "forest_name"); 725 726 (void) update_value(&live_cfg->site_name, 727 &new_cfg.site_name, "site_name"); 728 729 if (update_dirs(&live_cfg->global_catalog, 730 &new_cfg.global_catalog, "global_catalog") == TRUE) 731 changed = TRUE; 732 UNLOCK_CONFIG(); 733 734 idmap_cfg_unload(&new_cfg); 735 736 737 /* 738 * Re-create the ad_t/ad_host_t objects if 739 * either the default domain or the global 740 * catalog server list changed. 741 */ 742 743 if (changed) { 744 RDLOCK_CONFIG(); 745 (void) reload_ad(); 746 UNLOCK_CONFIG(); 747 print_idmapdstate(); 748 } 749 } 750 /*NOTREACHED*/ 751 return (NULL); 752 } 753 754 int 755 idmap_cfg_start_updates(void) 756 { 757 if ((idmapd_ev_port = port_create()) < 0) { 758 idmapdlog(LOG_ERR, "Failed to create event port: %s", 759 strerror(errno)); 760 return (-1); 761 } 762 763 if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 764 idmapdlog(LOG_ERR, "Failed to open routing socket: %s", 765 strerror(errno)); 766 (void) close(idmapd_ev_port); 767 return (-1); 768 } 769 770 if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) { 771 idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s", 772 strerror(errno)); 773 (void) close(rt_sock); 774 (void) close(idmapd_ev_port); 775 return (-1); 776 } 777 778 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, 779 rt_sock, POLLIN, NULL) != 0) { 780 idmapdlog(LOG_ERR, "Failed to associate the routing " 781 "socket with the event port: %s", strerror(errno)); 782 (void) close(rt_sock); 783 (void) close(idmapd_ev_port); 784 return (-1); 785 } 786 787 if ((errno = pthread_create(&update_thread_handle, NULL, 788 idmap_cfg_update_thread, NULL)) != 0) { 789 idmapdlog(LOG_ERR, "Failed to start update thread: %s", 790 strerror(errno)); 791 (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock); 792 (void) close(rt_sock); 793 (void) close(idmapd_ev_port); 794 return (-1); 795 } 796 797 return (0); 798 } 799 800 801 int 802 idmap_cfg_load(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, 803 int discover) 804 { 805 int rc; 806 int errors = 0; 807 uint8_t bool_val; 808 char *str = NULL; 809 bool_t new_debug_mode; 810 ad_disc_t ad_ctx = handles->ad_ctx; 811 812 pgcfg->list_size_limit = 0; 813 pgcfg->default_domain = NULL; 814 pgcfg->domain_name = NULL; 815 pgcfg->machine_sid = NULL; 816 pgcfg->domain_controller = NULL; 817 pgcfg->forest_name = NULL; 818 pgcfg->site_name = NULL; 819 pgcfg->global_catalog = NULL; 820 pgcfg->ad_unixuser_attr = NULL; 821 pgcfg->ad_unixgroup_attr = NULL; 822 pgcfg->nldap_winname_attr = NULL; 823 pgcfg->ds_name_mapping_enabled = FALSE; 824 825 pthread_mutex_lock(&handles->mutex); 826 827 ad_disc_refresh(handles->ad_ctx); 828 829 if (scf_pg_update(handles->config_pg) < 0) { 830 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 831 scf_strerror(scf_error())); 832 rc = -2; 833 goto exit; 834 } 835 836 if (scf_pg_update(handles->general_pg) < 0) { 837 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 838 scf_strerror(scf_error())); 839 rc = -2; 840 goto exit; 841 } 842 843 new_debug_mode = prop_exists(handles, "debug"); 844 if (_idmapdstate.debug_mode != new_debug_mode) { 845 if (_idmapdstate.debug_mode == FALSE) { 846 _idmapdstate.debug_mode = new_debug_mode; 847 idmapdlog(LOG_DEBUG, "debug mode enabled"); 848 } else { 849 idmapdlog(LOG_DEBUG, "debug mode disabled"); 850 _idmapdstate.debug_mode = new_debug_mode; 851 } 852 } 853 854 rc = get_val_int(handles, "list_size_limit", 855 &pgcfg->list_size_limit, SCF_TYPE_COUNT); 856 if (rc != 0) { 857 pgcfg->list_size_limit = 0; 858 errors++; 859 } 860 861 rc = get_val_astring(handles, "domain_name", 862 &pgcfg->domain_name); 863 if (rc != 0) 864 errors++; 865 else 866 (void) ad_disc_set_DomainName(ad_ctx, pgcfg->domain_name); 867 868 rc = get_val_astring(handles, "default_domain", 869 &pgcfg->default_domain); 870 if (rc != 0) { 871 /* 872 * SCF failures fetching config/default_domain we treat 873 * as fatal as they may leave ID mapping rules that 874 * match unqualified winnames flapping in the wind. 875 */ 876 rc = -2; 877 goto exit; 878 } 879 880 rc = get_val_astring(handles, "mapping_domain", &str); 881 if (rc != 0) 882 errors++; 883 884 /* 885 * We treat default_domain as having been specified in SMF IFF 886 * either (the config/default_domain property was set) or (the 887 * old, obsolete, never documented config/mapping_domain 888 * property was set and the new config/domain_name property was 889 * not set). 890 */ 891 pgcfg->dflt_dom_set_in_smf = TRUE; 892 if (pgcfg->default_domain == NULL) { 893 894 pgcfg->dflt_dom_set_in_smf = FALSE; 895 896 if (pgcfg->domain_name != NULL) { 897 pgcfg->default_domain = strdup(pgcfg->domain_name); 898 if (str != NULL) { 899 idmapdlog(LOG_WARNING, 900 "Ignoring obsolete, undocumented " 901 "config/mapping_domain property"); 902 } 903 } else if (str != NULL) { 904 pgcfg->default_domain = strdup(str); 905 pgcfg->dflt_dom_set_in_smf = TRUE; 906 idmapdlog(LOG_WARNING, 907 "The config/mapping_domain property is " 908 "obsolete; support for it will be removed, " 909 "please use config/default_domain instead"); 910 } 911 } 912 913 if (str != NULL) 914 free(str); 915 916 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid); 917 if (rc != 0) 918 errors++; 919 if (pgcfg->machine_sid == NULL) { 920 /* If machine_sid not configured, generate one */ 921 if (generate_machine_sid(&pgcfg->machine_sid) < 0) { 922 rc = -2; 923 goto exit; 924 } 925 rc = set_val_astring(handles, "machine_sid", 926 pgcfg->machine_sid); 927 if (rc != 0) 928 errors++; 929 } 930 931 str = NULL; 932 rc = get_val_ds(handles, "domain_controller", 389, 933 &pgcfg->domain_controller); 934 if (rc != 0) 935 errors++; 936 else 937 (void) ad_disc_set_DomainController(ad_ctx, 938 pgcfg->domain_controller); 939 940 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name); 941 if (rc != 0) 942 errors++; 943 else 944 (void) ad_disc_set_ForestName(ad_ctx, pgcfg->forest_name); 945 946 rc = get_val_astring(handles, "site_name", &pgcfg->site_name); 947 if (rc != 0) 948 errors++; 949 else 950 (void) ad_disc_set_SiteName(ad_ctx, pgcfg->site_name); 951 952 str = NULL; 953 rc = get_val_ds(handles, "global_catalog", 3268, 954 &pgcfg->global_catalog); 955 if (rc != 0) 956 errors++; 957 else 958 (void) ad_disc_set_GlobalCatalog(ad_ctx, pgcfg->global_catalog); 959 960 /* 961 * Read directory-based name mappings related SMF properties 962 */ 963 bool_val = 0; 964 rc = get_val_int(handles, "ds_name_mapping_enabled", 965 &bool_val, SCF_TYPE_BOOLEAN); 966 if (rc != 0) { 967 rc = -2; 968 goto exit; 969 } else if (bool_val) { 970 pgcfg->ds_name_mapping_enabled = TRUE; 971 rc = get_val_astring(handles, "ad_unixuser_attr", 972 &pgcfg->ad_unixuser_attr); 973 if (rc != 0) { 974 rc = -2; 975 goto exit; 976 } 977 978 rc = get_val_astring(handles, "ad_unixgroup_attr", 979 &pgcfg->ad_unixgroup_attr); 980 if (rc != 0) { 981 rc = -2; 982 goto exit; 983 } 984 985 rc = get_val_astring(handles, "nldap_winname_attr", 986 &pgcfg->nldap_winname_attr); 987 if (rc != 0) { 988 rc = -2; 989 goto exit; 990 } 991 992 if (pgcfg->nldap_winname_attr != NULL) { 993 idmapdlog(LOG_ERR, 994 "native LDAP based name mapping not supported " 995 "at this time. Please unset " 996 "config/nldap_winname_attr and restart idmapd."); 997 rc = -3; 998 goto exit; 999 } 1000 1001 if (pgcfg->ad_unixuser_attr == NULL && 1002 pgcfg->ad_unixgroup_attr == NULL) { 1003 idmapdlog(LOG_ERR, 1004 "If config/ds_name_mapping_enabled property " 1005 "is set to true then atleast one of the following " 1006 "name mapping attributes must be specified. " 1007 "(config/ad_unixuser_attr OR " 1008 "config/ad_unixgroup_attr)"); 1009 rc = -3; 1010 goto exit; 1011 } 1012 } 1013 1014 1015 if (!discover) 1016 goto exit; 1017 1018 /* 1019 * Auto Discover the rest 1020 */ 1021 if (pgcfg->default_domain == NULL) { 1022 pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx); 1023 if (pgcfg->default_domain == NULL) { 1024 idmapdlog(LOG_INFO, 1025 "unable to discover Default Domain"); 1026 } 1027 } 1028 1029 if (pgcfg->domain_name == NULL) { 1030 pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx); 1031 if (pgcfg->domain_name == NULL) { 1032 idmapdlog(LOG_INFO, 1033 "unable to discover Domain Name"); 1034 } 1035 } 1036 1037 if (pgcfg->domain_controller == NULL) { 1038 pgcfg->domain_controller = 1039 ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE); 1040 if (pgcfg->domain_controller == NULL) { 1041 idmapdlog(LOG_INFO, 1042 "unable to discover Domain Controller"); 1043 } 1044 } 1045 1046 if (pgcfg->forest_name == NULL) { 1047 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx); 1048 if (pgcfg->forest_name == NULL) { 1049 idmapdlog(LOG_INFO, 1050 "unable to discover Forest Name"); 1051 } 1052 } 1053 1054 if (pgcfg->site_name == NULL) { 1055 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx); 1056 if (pgcfg->site_name == NULL) { 1057 idmapdlog(LOG_INFO, 1058 "unable to discover Site Name"); 1059 } 1060 } 1061 1062 if (pgcfg->global_catalog == NULL) { 1063 pgcfg->global_catalog = 1064 ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE); 1065 if (pgcfg->global_catalog == NULL) { 1066 idmapdlog(LOG_INFO, 1067 "unable to discover Global Catalog"); 1068 } 1069 } 1070 1071 exit: 1072 pthread_mutex_unlock(&handles->mutex); 1073 1074 if (rc < -1) 1075 return (rc); 1076 1077 return ((errors == 0) ? 0 : -1); 1078 } 1079 1080 /* 1081 * Initialize 'cfg'. 1082 */ 1083 idmap_cfg_t * 1084 idmap_cfg_init() 1085 { 1086 idmap_cfg_handles_t *handles; 1087 1088 /* First the smf repository handles: */ 1089 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t)); 1090 if (!cfg) { 1091 idmapdlog(LOG_ERR, "Out of memory"); 1092 return (NULL); 1093 } 1094 handles = &cfg->handles; 1095 1096 (void) pthread_mutex_init(&handles->mutex, NULL); 1097 1098 if (!(handles->main = scf_handle_create(SCF_VERSION))) { 1099 idmapdlog(LOG_ERR, "scf_handle_create() failed: %s", 1100 scf_strerror(scf_error())); 1101 goto error; 1102 } 1103 1104 if (scf_handle_bind(handles->main) < 0) { 1105 idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s", 1106 scf_strerror(scf_error())); 1107 goto error; 1108 } 1109 1110 if (!(handles->service = scf_service_create(handles->main)) || 1111 !(handles->instance = scf_instance_create(handles->main)) || 1112 !(handles->config_pg = scf_pg_create(handles->main)) || 1113 !(handles->general_pg = scf_pg_create(handles->main))) { 1114 idmapdlog(LOG_ERR, "scf handle creation failed: %s", 1115 scf_strerror(scf_error())); 1116 goto error; 1117 } 1118 1119 if (scf_handle_decode_fmri(handles->main, 1120 FMRI_BASE "/:properties/" CONFIG_PG, 1121 NULL, /* scope */ 1122 handles->service, /* service */ 1123 handles->instance, /* instance */ 1124 handles->config_pg, /* pg */ 1125 NULL, /* prop */ 1126 SCF_DECODE_FMRI_EXACT) < 0) { 1127 idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s", 1128 scf_strerror(scf_error())); 1129 goto error; 1130 } 1131 1132 if (scf_service_get_pg(handles->service, 1133 GENERAL_PG, handles->general_pg) < 0) { 1134 idmapdlog(LOG_ERR, "scf_service_get_pg() failed: %s", 1135 scf_strerror(scf_error())); 1136 goto error; 1137 } 1138 1139 /* Initialize AD Auto Discovery context */ 1140 handles->ad_ctx = ad_disc_init(); 1141 if (handles->ad_ctx == NULL) 1142 goto error; 1143 1144 return (cfg); 1145 1146 error: 1147 (void) idmap_cfg_fini(cfg); 1148 return (NULL); 1149 } 1150 1151 void 1152 idmap_cfg_unload(idmap_pg_config_t *pgcfg) 1153 { 1154 1155 if (pgcfg->default_domain) { 1156 free(pgcfg->default_domain); 1157 pgcfg->default_domain = NULL; 1158 } 1159 if (pgcfg->domain_name) { 1160 free(pgcfg->domain_name); 1161 pgcfg->domain_name = NULL; 1162 } 1163 if (pgcfg->machine_sid) { 1164 free(pgcfg->machine_sid); 1165 pgcfg->machine_sid = NULL; 1166 } 1167 if (pgcfg->domain_controller) { 1168 free(pgcfg->domain_controller); 1169 pgcfg->domain_controller = NULL; 1170 } 1171 if (pgcfg->forest_name) { 1172 free(pgcfg->forest_name); 1173 pgcfg->forest_name = NULL; 1174 } 1175 if (pgcfg->site_name) { 1176 free(pgcfg->site_name); 1177 pgcfg->site_name = NULL; 1178 } 1179 if (pgcfg->global_catalog) { 1180 free(pgcfg->global_catalog); 1181 pgcfg->global_catalog = NULL; 1182 } 1183 if (pgcfg->ad_unixuser_attr) { 1184 free(pgcfg->ad_unixuser_attr); 1185 pgcfg->ad_unixuser_attr = NULL; 1186 } 1187 if (pgcfg->ad_unixgroup_attr) { 1188 free(pgcfg->ad_unixgroup_attr); 1189 pgcfg->ad_unixgroup_attr = NULL; 1190 } 1191 if (pgcfg->nldap_winname_attr) { 1192 free(pgcfg->nldap_winname_attr); 1193 pgcfg->nldap_winname_attr = NULL; 1194 } 1195 } 1196 1197 int 1198 idmap_cfg_fini(idmap_cfg_t *cfg) 1199 { 1200 idmap_cfg_handles_t *handles = &cfg->handles; 1201 idmap_cfg_unload(&cfg->pgcfg); 1202 1203 (void) pthread_mutex_destroy(&handles->mutex); 1204 scf_pg_destroy(handles->config_pg); 1205 scf_pg_destroy(handles->general_pg); 1206 scf_instance_destroy(handles->instance); 1207 scf_service_destroy(handles->service); 1208 scf_handle_destroy(handles->main); 1209 if (handles->ad_ctx != NULL) 1210 ad_disc_fini(handles->ad_ctx); 1211 free(cfg); 1212 1213 return (0); 1214 } 1215 1216 void 1217 idmap_cfg_poke_updates(void) 1218 { 1219 (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL); 1220 } 1221 1222 /*ARGSUSED*/ 1223 void 1224 idmap_cfg_hup_handler(int sig) { 1225 if (idmapd_ev_port >= 0) 1226 (void) port_send(idmapd_ev_port, RECONFIGURE, NULL); 1227 } 1228