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