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 (0); 432 433 if (*value != NULL && strcmp(*new, *value) == 0) { 434 free(*new); 435 *new = NULL; 436 return (0); 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 (1); 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 (0); 455 456 if (*value != NULL && *new != NULL && 457 ad_disc_compare_ds(*value, *new) == 0) { 458 free(*new); 459 *new = NULL; 460 return (0); 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 (1); 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 (1); 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 *timeoutp) 533 { 534 port_event_t pe; 535 536 retry: 537 memset(&pe, 0, sizeof (pe)); 538 if (port_get(idmapd_ev_port, &pe, timeoutp) != 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 rc = idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER|CFG_LOG); 587 if (rc < -1) { 588 (void) idmapdlog(LOG_ERR, "Fatal errors while reading " 589 "SMF properties"); 590 exit(1); 591 } else if (rc == -1) { 592 (void) idmapdlog(LOG_WARNING, "Various errors " 593 "re-loading configuration may cause AD lookups " 594 "to fail"); 595 } 596 return (FALSE); 597 } 598 599 return (FALSE); 600 } 601 602 void * 603 idmap_cfg_update_thread(void *arg) 604 { 605 606 int ttl, changed, poke_is_interesting; 607 idmap_cfg_handles_t *handles = &_idmapdstate.cfg->handles; 608 ad_disc_t ad_ctx = handles->ad_ctx; 609 struct timespec timeout, *timeoutp; 610 611 poke_is_interesting = 1; 612 for (ttl = 0, changed = TRUE; ; ttl = ad_disc_get_TTL(ad_ctx)) { 613 /* 614 * If ttl < 0 then we can wait for an event without timing out. 615 * If idmapd needs to notice that the system has been joined to 616 * a Windows domain then idmapd needs to be refreshed. 617 */ 618 timeoutp = (ttl < 0) ? NULL : &timeout; 619 if (ttl > MAX_CHECK_TIME) 620 ttl = MAX_CHECK_TIME; 621 timeout.tv_sec = ttl; 622 timeout.tv_nsec = 0; 623 changed = wait_for_event(poke_is_interesting, timeoutp); 624 625 /* 626 * If there are no interesting events, and this is not the first 627 * time through the loop, and we haven't waited the most that 628 * we're willing to wait, so do nothing but wait some more. 629 */ 630 if (changed == FALSE && ttl > 0 && ttl < MAX_CHECK_TIME) 631 continue; 632 633 (void) ad_disc_SubnetChanged(ad_ctx); 634 635 if (idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER) < -1) { 636 (void) idmapdlog(LOG_ERR, "Fatal errors while reading " 637 "SMF properties"); 638 exit(1); 639 } 640 641 if (_idmapdstate.cfg->pgcfg.global_catalog == NULL || 642 _idmapdstate.cfg->pgcfg.global_catalog[0].host[0] == '\0') 643 poke_is_interesting = 1; 644 else 645 poke_is_interesting = 0; 646 } 647 /*NOTREACHED*/ 648 return (NULL); 649 } 650 651 int 652 idmap_cfg_start_updates(void) 653 { 654 if ((idmapd_ev_port = port_create()) < 0) { 655 idmapdlog(LOG_ERR, "Failed to create event port: %s", 656 strerror(errno)); 657 return (-1); 658 } 659 660 if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 661 idmapdlog(LOG_ERR, "Failed to open routing socket: %s", 662 strerror(errno)); 663 (void) close(idmapd_ev_port); 664 return (-1); 665 } 666 667 if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) { 668 idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s", 669 strerror(errno)); 670 (void) close(rt_sock); 671 (void) close(idmapd_ev_port); 672 return (-1); 673 } 674 675 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, 676 rt_sock, POLLIN, NULL) != 0) { 677 idmapdlog(LOG_ERR, "Failed to associate the routing " 678 "socket with the event port: %s", strerror(errno)); 679 (void) close(rt_sock); 680 (void) close(idmapd_ev_port); 681 return (-1); 682 } 683 684 if ((errno = pthread_create(&update_thread_handle, NULL, 685 idmap_cfg_update_thread, NULL)) != 0) { 686 idmapdlog(LOG_ERR, "Failed to start update thread: %s", 687 strerror(errno)); 688 (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock); 689 (void) close(rt_sock); 690 (void) close(idmapd_ev_port); 691 return (-1); 692 } 693 694 return (0); 695 } 696 697 /* 698 * This is the half of idmap_cfg_load() that loads property values from 699 * SMF (using the config/ property group of the idmap FMRI). 700 * 701 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 702 * reading from SMF. 703 */ 704 static 705 int 706 idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, 707 int *errors) 708 { 709 int rc; 710 uint8_t bool_val; 711 char *str = NULL; 712 bool_t new_debug_mode; 713 714 if (scf_pg_update(handles->config_pg) < 0) { 715 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 716 scf_strerror(scf_error())); 717 return (-2); 718 } 719 720 if (scf_pg_update(handles->general_pg) < 0) { 721 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 722 scf_strerror(scf_error())); 723 return (-2); 724 } 725 726 new_debug_mode = prop_exists(handles, "debug"); 727 if (_idmapdstate.debug_mode != new_debug_mode) { 728 if (_idmapdstate.debug_mode == FALSE) { 729 _idmapdstate.debug_mode = new_debug_mode; 730 idmapdlog(LOG_DEBUG, "debug mode enabled"); 731 } else { 732 idmapdlog(LOG_DEBUG, "debug mode disabled"); 733 _idmapdstate.debug_mode = new_debug_mode; 734 } 735 } 736 737 rc = get_val_int(handles, "list_size_limit", 738 &pgcfg->list_size_limit, SCF_TYPE_COUNT); 739 if (rc != 0) { 740 pgcfg->list_size_limit = 0; 741 errors++; 742 } 743 744 rc = get_val_astring(handles, "domain_name", 745 &pgcfg->domain_name); 746 if (rc != 0) 747 errors++; 748 else 749 (void) ad_disc_set_DomainName(handles->ad_ctx, 750 pgcfg->domain_name); 751 752 rc = get_val_astring(handles, "default_domain", 753 &pgcfg->default_domain); 754 if (rc != 0) { 755 /* 756 * SCF failures fetching config/default_domain we treat 757 * as fatal as they may leave ID mapping rules that 758 * match unqualified winnames flapping in the wind. 759 */ 760 return (-2); 761 } 762 763 rc = get_val_astring(handles, "mapping_domain", &str); 764 if (rc != 0) 765 errors++; 766 767 /* 768 * We treat default_domain as having been specified in SMF IFF 769 * either (the config/default_domain property was set) or (the 770 * old, obsolete, never documented config/mapping_domain 771 * property was set and the new config/domain_name property was 772 * not set). 773 */ 774 pgcfg->dflt_dom_set_in_smf = TRUE; 775 if (pgcfg->default_domain == NULL) { 776 777 pgcfg->dflt_dom_set_in_smf = FALSE; 778 779 if (pgcfg->domain_name != NULL) { 780 pgcfg->default_domain = strdup(pgcfg->domain_name); 781 if (str != NULL) { 782 idmapdlog(LOG_WARNING, 783 "Ignoring obsolete, undocumented " 784 "config/mapping_domain property"); 785 } 786 } else if (str != NULL) { 787 pgcfg->default_domain = strdup(str); 788 pgcfg->dflt_dom_set_in_smf = TRUE; 789 idmapdlog(LOG_WARNING, 790 "The config/mapping_domain property is " 791 "obsolete; support for it will be removed, " 792 "please use config/default_domain instead"); 793 } 794 } 795 796 if (str != NULL) 797 free(str); 798 799 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid); 800 if (rc != 0) 801 errors++; 802 if (pgcfg->machine_sid == NULL) { 803 /* If machine_sid not configured, generate one */ 804 if (generate_machine_sid(&pgcfg->machine_sid) < 0) 805 return (-2); 806 rc = set_val_astring(handles, "machine_sid", 807 pgcfg->machine_sid); 808 if (rc != 0) 809 errors++; 810 } 811 812 str = NULL; 813 rc = get_val_ds(handles, "domain_controller", 389, 814 &pgcfg->domain_controller); 815 if (rc != 0) 816 errors++; 817 else 818 (void) ad_disc_set_DomainController(handles->ad_ctx, 819 pgcfg->domain_controller); 820 821 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name); 822 if (rc != 0) 823 errors++; 824 else 825 (void) ad_disc_set_ForestName(handles->ad_ctx, 826 pgcfg->forest_name); 827 828 rc = get_val_astring(handles, "site_name", &pgcfg->site_name); 829 if (rc != 0) 830 errors++; 831 else 832 (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name); 833 834 str = NULL; 835 rc = get_val_ds(handles, "global_catalog", 3268, 836 &pgcfg->global_catalog); 837 if (rc != 0) 838 errors++; 839 else 840 (void) ad_disc_set_GlobalCatalog(handles->ad_ctx, 841 pgcfg->global_catalog); 842 843 /* 844 * Read directory-based name mappings related SMF properties 845 */ 846 bool_val = 0; 847 rc = get_val_int(handles, "ds_name_mapping_enabled", 848 &bool_val, SCF_TYPE_BOOLEAN); 849 if (rc != 0) 850 return (-2); 851 852 if (!bool_val) 853 return (rc); 854 855 pgcfg->ds_name_mapping_enabled = TRUE; 856 rc = get_val_astring(handles, "ad_unixuser_attr", 857 &pgcfg->ad_unixuser_attr); 858 if (rc != 0) 859 return (-2); 860 861 rc = get_val_astring(handles, "ad_unixgroup_attr", 862 &pgcfg->ad_unixgroup_attr); 863 if (rc != 0) 864 return (-2); 865 866 rc = get_val_astring(handles, "nldap_winname_attr", 867 &pgcfg->nldap_winname_attr); 868 if (rc != 0) 869 return (-2); 870 871 if (pgcfg->nldap_winname_attr != NULL) { 872 idmapdlog(LOG_ERR, 873 "Native LDAP based name mapping not supported at this " 874 "time. Please unset config/nldap_winname_attr and restart " 875 "idmapd."); 876 return (-3); 877 } 878 879 if (pgcfg->ad_unixuser_attr == NULL && 880 pgcfg->ad_unixgroup_attr == NULL) { 881 idmapdlog(LOG_ERR, 882 "If config/ds_name_mapping_enabled property is set to " 883 "true then atleast one of the following name mapping " 884 "attributes must be specified. (config/ad_unixuser_attr OR " 885 "config/ad_unixgroup_attr)"); 886 return (-3); 887 } 888 889 return (rc); 890 891 } 892 893 /* 894 * This is the half of idmap_cfg_load() that auto-discovers values of 895 * discoverable properties that weren't already set via SMF properties. 896 * 897 * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it 898 * needs to be careful not to overwrite any properties set in SMF. 899 */ 900 static 901 void 902 idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) 903 { 904 ad_disc_t ad_ctx = handles->ad_ctx; 905 906 ad_disc_refresh(ad_ctx); 907 908 if (pgcfg->default_domain == NULL) 909 pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx); 910 911 if (pgcfg->domain_name == NULL) 912 pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx); 913 914 if (pgcfg->domain_controller == NULL) 915 pgcfg->domain_controller = 916 ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE); 917 918 if (pgcfg->forest_name == NULL) 919 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx); 920 921 if (pgcfg->site_name == NULL) 922 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx); 923 924 if (pgcfg->global_catalog == NULL) 925 pgcfg->global_catalog = 926 ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE); 927 928 if (pgcfg->domain_name == NULL) 929 idmapdlog(LOG_DEBUG, "unable to discover Domain Name"); 930 if (pgcfg->domain_controller == NULL) 931 idmapdlog(LOG_DEBUG, "unable to discover Domain Controller"); 932 if (pgcfg->forest_name == NULL) 933 idmapdlog(LOG_DEBUG, "unable to discover Forest Name"); 934 if (pgcfg->site_name == NULL) 935 idmapdlog(LOG_DEBUG, "unable to discover Site Name"); 936 if (pgcfg->global_catalog == NULL) 937 idmapdlog(LOG_DEBUG, "unable to discover Global Catalog"); 938 } 939 940 /* 941 * idmap_cfg_load() is called at startup, and periodically via the 942 * update thread when the auto-discovery TTLs expire, as well as part of 943 * the refresh method, to update the current configuration. It always 944 * reads from SMF, but you still have to refresh the service after 945 * changing the config pg in order for the changes to take effect. 946 * 947 * There are two flags: 948 * 949 * - CFG_DISCOVER 950 * - CFG_LOG 951 * 952 * If CFG_DISCOVER is set then idmap_cfg_load() calls 953 * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property 954 * values that weren't set in SMF. 955 * 956 * If CFG_LOG is set then idmap_cfg_load() will log (to LOG_NOTICE) 957 * whether the configuration changed. This should be used only from the 958 * refresh method. 959 * 960 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 961 * reading from SMF. 962 */ 963 int 964 idmap_cfg_load(idmap_cfg_t *cfg, int flags) 965 { 966 int rc = 0; 967 int errors = 0; 968 int changed = 0; 969 idmap_pg_config_t new_pgcfg, *live_pgcfg; 970 971 live_pgcfg = &cfg->pgcfg; 972 (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg)); 973 974 pthread_mutex_lock(&cfg->handles.mutex); 975 976 if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1) 977 goto err; 978 979 if (flags & CFG_DISCOVER) 980 idmap_cfg_discover(&cfg->handles, &new_pgcfg); 981 982 WRLOCK_CONFIG(); 983 if (live_pgcfg->list_size_limit != new_pgcfg.list_size_limit) { 984 idmapdlog(LOG_INFO, "change list_size=%d", 985 new_pgcfg.list_size_limit); 986 live_pgcfg->list_size_limit = new_pgcfg.list_size_limit; 987 } 988 989 /* Non-discoverable props updated here */ 990 changed += update_value(&live_pgcfg->machine_sid, 991 &new_pgcfg.machine_sid, "machine_sid"); 992 993 changed += live_pgcfg->ds_name_mapping_enabled != 994 new_pgcfg.ds_name_mapping_enabled; 995 live_pgcfg->ds_name_mapping_enabled = 996 new_pgcfg.ds_name_mapping_enabled; 997 998 changed += update_value(&live_pgcfg->ad_unixuser_attr, 999 &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr"); 1000 1001 changed += update_value(&live_pgcfg->ad_unixgroup_attr, 1002 &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr"); 1003 1004 changed += update_value(&live_pgcfg->nldap_winname_attr, 1005 &new_pgcfg.nldap_winname_attr, "nldap_winname_attr"); 1006 1007 /* Props that can be discovered and set in SMF updated here */ 1008 if (live_pgcfg->dflt_dom_set_in_smf == FALSE) 1009 changed += update_value(&live_pgcfg->default_domain, 1010 &new_pgcfg.default_domain, "default_domain"); 1011 1012 changed += update_value(&live_pgcfg->domain_name, 1013 &new_pgcfg.domain_name, "domain_name"); 1014 1015 changed += update_dirs(&live_pgcfg->domain_controller, 1016 &new_pgcfg.domain_controller, "domain_controller"); 1017 1018 changed += update_value(&live_pgcfg->forest_name, 1019 &new_pgcfg.forest_name, "forest_name"); 1020 1021 changed += update_value(&live_pgcfg->site_name, 1022 &new_pgcfg.site_name, "site_name"); 1023 1024 if (update_dirs(&live_pgcfg->global_catalog, 1025 &new_pgcfg.global_catalog, "global_catalog")) { 1026 changed++; 1027 /* 1028 * Right now we only update the ad_t used for AD lookups 1029 * when the GC list is updated. When we add mixed 1030 * ds-based mapping we'll also need to update the ad_t 1031 * used to talk to the domain, not just the one used to 1032 * talk to the GC. 1033 */ 1034 if (live_pgcfg->global_catalog != NULL && 1035 live_pgcfg->global_catalog[0].host[0] != '\0') 1036 reload_ad(); 1037 } 1038 1039 idmap_cfg_unload(&new_pgcfg); 1040 1041 if (flags & CFG_LOG) { 1042 /* 1043 * If the config changes as a result of a refresh of the 1044 * service, then logging about it can provide useful 1045 * feedback to the sysadmin. 1046 */ 1047 idmapdlog(LOG_NOTICE, "Configuration %schanged", 1048 changed ? "" : "un"); 1049 } 1050 1051 UNLOCK_CONFIG(); 1052 1053 err: 1054 pthread_mutex_unlock(&cfg->handles.mutex); 1055 1056 if (rc < -1) 1057 return (rc); 1058 1059 return ((errors == 0) ? 0 : -1); 1060 } 1061 1062 /* 1063 * Initialize 'cfg'. 1064 */ 1065 idmap_cfg_t * 1066 idmap_cfg_init() 1067 { 1068 idmap_cfg_handles_t *handles; 1069 1070 /* First the smf repository handles: */ 1071 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t)); 1072 if (!cfg) { 1073 idmapdlog(LOG_ERR, "Out of memory"); 1074 return (NULL); 1075 } 1076 handles = &cfg->handles; 1077 1078 (void) pthread_mutex_init(&handles->mutex, NULL); 1079 1080 if (!(handles->main = scf_handle_create(SCF_VERSION))) { 1081 idmapdlog(LOG_ERR, "scf_handle_create() failed: %s", 1082 scf_strerror(scf_error())); 1083 goto error; 1084 } 1085 1086 if (scf_handle_bind(handles->main) < 0) { 1087 idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s", 1088 scf_strerror(scf_error())); 1089 goto error; 1090 } 1091 1092 if (!(handles->service = scf_service_create(handles->main)) || 1093 !(handles->instance = scf_instance_create(handles->main)) || 1094 !(handles->config_pg = scf_pg_create(handles->main)) || 1095 !(handles->general_pg = scf_pg_create(handles->main))) { 1096 idmapdlog(LOG_ERR, "scf handle creation failed: %s", 1097 scf_strerror(scf_error())); 1098 goto error; 1099 } 1100 1101 if (scf_handle_decode_fmri(handles->main, 1102 FMRI_BASE "/:properties/" CONFIG_PG, 1103 NULL, /* scope */ 1104 handles->service, /* service */ 1105 handles->instance, /* instance */ 1106 handles->config_pg, /* pg */ 1107 NULL, /* prop */ 1108 SCF_DECODE_FMRI_EXACT) < 0) { 1109 idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s", 1110 scf_strerror(scf_error())); 1111 goto error; 1112 } 1113 1114 if (scf_service_get_pg(handles->service, 1115 GENERAL_PG, handles->general_pg) < 0) { 1116 idmapdlog(LOG_ERR, "scf_service_get_pg() failed: %s", 1117 scf_strerror(scf_error())); 1118 goto error; 1119 } 1120 1121 /* Initialize AD Auto Discovery context */ 1122 handles->ad_ctx = ad_disc_init(); 1123 if (handles->ad_ctx == NULL) 1124 goto error; 1125 1126 return (cfg); 1127 1128 error: 1129 (void) idmap_cfg_fini(cfg); 1130 return (NULL); 1131 } 1132 1133 void 1134 idmap_cfg_unload(idmap_pg_config_t *pgcfg) 1135 { 1136 1137 if (pgcfg->default_domain) { 1138 free(pgcfg->default_domain); 1139 pgcfg->default_domain = NULL; 1140 } 1141 if (pgcfg->domain_name) { 1142 free(pgcfg->domain_name); 1143 pgcfg->domain_name = NULL; 1144 } 1145 if (pgcfg->machine_sid) { 1146 free(pgcfg->machine_sid); 1147 pgcfg->machine_sid = NULL; 1148 } 1149 if (pgcfg->domain_controller) { 1150 free(pgcfg->domain_controller); 1151 pgcfg->domain_controller = NULL; 1152 } 1153 if (pgcfg->forest_name) { 1154 free(pgcfg->forest_name); 1155 pgcfg->forest_name = NULL; 1156 } 1157 if (pgcfg->site_name) { 1158 free(pgcfg->site_name); 1159 pgcfg->site_name = NULL; 1160 } 1161 if (pgcfg->global_catalog) { 1162 free(pgcfg->global_catalog); 1163 pgcfg->global_catalog = NULL; 1164 } 1165 if (pgcfg->ad_unixuser_attr) { 1166 free(pgcfg->ad_unixuser_attr); 1167 pgcfg->ad_unixuser_attr = NULL; 1168 } 1169 if (pgcfg->ad_unixgroup_attr) { 1170 free(pgcfg->ad_unixgroup_attr); 1171 pgcfg->ad_unixgroup_attr = NULL; 1172 } 1173 if (pgcfg->nldap_winname_attr) { 1174 free(pgcfg->nldap_winname_attr); 1175 pgcfg->nldap_winname_attr = NULL; 1176 } 1177 } 1178 1179 int 1180 idmap_cfg_fini(idmap_cfg_t *cfg) 1181 { 1182 idmap_cfg_handles_t *handles = &cfg->handles; 1183 idmap_cfg_unload(&cfg->pgcfg); 1184 1185 (void) pthread_mutex_destroy(&handles->mutex); 1186 scf_pg_destroy(handles->config_pg); 1187 scf_pg_destroy(handles->general_pg); 1188 scf_instance_destroy(handles->instance); 1189 scf_service_destroy(handles->service); 1190 scf_handle_destroy(handles->main); 1191 if (handles->ad_ctx != NULL) 1192 ad_disc_fini(handles->ad_ctx); 1193 free(cfg); 1194 1195 return (0); 1196 } 1197 1198 void 1199 idmap_cfg_poke_updates(void) 1200 { 1201 if (idmapd_ev_port != -1) 1202 (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL); 1203 } 1204 1205 /*ARGSUSED*/ 1206 void 1207 idmap_cfg_hup_handler(int sig) 1208 { 1209 if (idmapd_ev_port >= 0) 1210 (void) port_send(idmapd_ev_port, RECONFIGURE, NULL); 1211 } 1212