1c5c4113dSnw /* 2c5c4113dSnw * CDDL HEADER START 3c5c4113dSnw * 4c5c4113dSnw * The contents of this file are subject to the terms of the 5c5c4113dSnw * Common Development and Distribution License (the "License"). 6c5c4113dSnw * You may not use this file except in compliance with the License. 7c5c4113dSnw * 8c5c4113dSnw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9c5c4113dSnw * or http://www.opensolaris.org/os/licensing. 10c5c4113dSnw * See the License for the specific language governing permissions 11c5c4113dSnw * and limitations under the License. 12c5c4113dSnw * 13c5c4113dSnw * When distributing Covered Code, include this CDDL HEADER in each 14c5c4113dSnw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15c5c4113dSnw * If applicable, add the following below this CDDL HEADER, with the 16c5c4113dSnw * fields enclosed by brackets "[]" replaced with your own identifying 17c5c4113dSnw * information: Portions Copyright [yyyy] [name of copyright owner] 18c5c4113dSnw * 19c5c4113dSnw * CDDL HEADER END 20c5c4113dSnw */ 21c5c4113dSnw /* 224edd44c5Sjp * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23c5c4113dSnw * Use is subject to license terms. 24c5c4113dSnw */ 25c5c4113dSnw 26c5c4113dSnw #pragma ident "%Z%%M% %I% %E% SMI" 27c5c4113dSnw 28c5c4113dSnw /* 29c5c4113dSnw * Config routines common to idmap(1M) and idmapd(1M) 30c5c4113dSnw */ 31c5c4113dSnw 32c5c4113dSnw #include <stdlib.h> 33c5c4113dSnw #include <strings.h> 34c5c4113dSnw #include <libintl.h> 35c5c4113dSnw #include <ctype.h> 36c5c4113dSnw #include <errno.h> 37651c0131Sbaban #include "idmapd.h" 38c5c4113dSnw #include <stdio.h> 39c5c4113dSnw #include <stdarg.h> 408edda628Sbaban #include <uuid/uuid.h> 41c8e26105Sjp #include <pthread.h> 42c8e26105Sjp #include <port.h> 430dcc7149Snw #include <net/route.h> 44c8e26105Sjp #include "addisc.h" 45c5c4113dSnw 460dcc7149Snw #define MACHINE_SID_LEN (9 + UUID_LEN/4 * 11) 470dcc7149Snw #define FMRI_BASE "svc:/system/idmap" 480dcc7149Snw #define CONFIG_PG "config" 490dcc7149Snw #define GENERAL_PG "general" 500dcc7149Snw #define RECONFIGURE 1 510dcc7149Snw #define POKE_AUTO_DISCOVERY 2 52c5c4113dSnw 53c8e26105Sjp /*LINTLIBRARY*/ 54c8e26105Sjp 55c8e26105Sjp 56c8e26105Sjp static pthread_t update_thread_handle = 0; 57c8e26105Sjp 580dcc7149Snw static int idmapd_ev_port = -1; 590dcc7149Snw static int rt_sock = -1; 60c8e26105Sjp 618edda628Sbaban static int 624edd44c5Sjp generate_machine_sid(char **machine_sid) 634edd44c5Sjp { 648edda628Sbaban char *p; 658edda628Sbaban uuid_t uu; 668edda628Sbaban int i, j, len, rlen; 678edda628Sbaban uint32_t rid; 688edda628Sbaban 698edda628Sbaban /* 708edda628Sbaban * Generate and split 128-bit UUID into four 32-bit RIDs 718edda628Sbaban * The machine_sid will be of the form S-1-5-N1-N2-N3-N4 728edda628Sbaban * We depart from Windows here, which instead of 128 738edda628Sbaban * bits worth of random numbers uses 96 bits. 748edda628Sbaban */ 758edda628Sbaban 768edda628Sbaban *machine_sid = calloc(1, MACHINE_SID_LEN); 778edda628Sbaban if (*machine_sid == NULL) { 7871590c90Snw idmapdlog(LOG_ERR, "Out of memory"); 798edda628Sbaban return (-1); 808edda628Sbaban } 818edda628Sbaban (void) strcpy(*machine_sid, "S-1-5-21"); 828edda628Sbaban p = *machine_sid + strlen("S-1-5-21"); 838edda628Sbaban len = MACHINE_SID_LEN - strlen("S-1-5-21"); 848edda628Sbaban 858edda628Sbaban uuid_clear(uu); 868edda628Sbaban uuid_generate_random(uu); 878edda628Sbaban 888edda628Sbaban for (i = 0; i < UUID_LEN/4; i++) { 898edda628Sbaban j = i * 4; 908edda628Sbaban rid = (uu[j] << 24) | (uu[j + 1] << 16) | 914edd44c5Sjp (uu[j + 2] << 8) | (uu[j + 3]); 928edda628Sbaban rlen = snprintf(p, len, "-%u", rid); 938edda628Sbaban p += rlen; 948edda628Sbaban len -= rlen; 958edda628Sbaban } 968edda628Sbaban 978edda628Sbaban return (0); 988edda628Sbaban } 998edda628Sbaban 100*479ac375Sdm 101*479ac375Sdm /* In the case of error, exists is set to FALSE anyway */ 102*479ac375Sdm static int 103*479ac375Sdm prop_exists(idmap_cfg_handles_t *handles, char *name, bool_t *exists) 10471590c90Snw { 10571590c90Snw 106*479ac375Sdm scf_property_t *scf_prop; 107*479ac375Sdm scf_value_t *value; 108*479ac375Sdm 109*479ac375Sdm *exists = FALSE; 110*479ac375Sdm 111*479ac375Sdm scf_prop = scf_property_create(handles->main); 112*479ac375Sdm if (scf_prop == NULL) { 113*479ac375Sdm idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 114*479ac375Sdm scf_strerror(scf_error())); 115*479ac375Sdm return (-1); 116*479ac375Sdm } 117*479ac375Sdm value = scf_value_create(handles->main); 118*479ac375Sdm if (value == NULL) { 119*479ac375Sdm idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 120*479ac375Sdm scf_strerror(scf_error())); 121*479ac375Sdm scf_property_destroy(scf_prop); 122*479ac375Sdm return (-1); 123*479ac375Sdm } 12471590c90Snw 12571590c90Snw if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0) 126*479ac375Sdm *exists = TRUE; 12771590c90Snw 12871590c90Snw scf_value_destroy(value); 12971590c90Snw scf_property_destroy(scf_prop); 13071590c90Snw 131*479ac375Sdm return (0); 13271590c90Snw } 13371590c90Snw 134c5c4113dSnw /* Check if in the case of failure the original value of *val is preserved */ 135c5c4113dSnw static int 136c8e26105Sjp get_val_int(idmap_cfg_handles_t *handles, char *name, 137c8e26105Sjp void *val, scf_type_t type) 138c5c4113dSnw { 139c5c4113dSnw int rc = 0; 140c5c4113dSnw 141*479ac375Sdm scf_property_t *scf_prop; 142*479ac375Sdm scf_value_t *value; 143*479ac375Sdm 144*479ac375Sdm scf_prop = scf_property_create(handles->main); 145*479ac375Sdm if (scf_prop == NULL) { 146*479ac375Sdm idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 147*479ac375Sdm scf_strerror(scf_error())); 148*479ac375Sdm return (-1); 149*479ac375Sdm } 150*479ac375Sdm value = scf_value_create(handles->main); 151*479ac375Sdm if (value == NULL) { 152*479ac375Sdm idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 153*479ac375Sdm scf_strerror(scf_error())); 154*479ac375Sdm scf_property_destroy(scf_prop); 155*479ac375Sdm return (-1); 156*479ac375Sdm } 157c5c4113dSnw 158c8e26105Sjp if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 159c5c4113dSnw /* this is OK: the property is just undefined */ 160c5c4113dSnw goto destruction; 161c5c4113dSnw 162c5c4113dSnw 163c8e26105Sjp if (scf_property_get_value(scf_prop, value) < 0) 164c5c4113dSnw /* It is still OK when a property doesn't have any value */ 165c5c4113dSnw goto destruction; 166c5c4113dSnw 167c5c4113dSnw switch (type) { 168c5c4113dSnw case SCF_TYPE_BOOLEAN: 169c5c4113dSnw rc = scf_value_get_boolean(value, val); 170c5c4113dSnw break; 171c5c4113dSnw case SCF_TYPE_COUNT: 172c5c4113dSnw rc = scf_value_get_count(value, val); 173c5c4113dSnw break; 174c5c4113dSnw case SCF_TYPE_INTEGER: 175c5c4113dSnw rc = scf_value_get_integer(value, val); 176c5c4113dSnw break; 177c5c4113dSnw default: 17871590c90Snw idmapdlog(LOG_ERR, "Invalid scf integer type (%d)", 17971590c90Snw type); 180c5c4113dSnw rc = -1; 181c5c4113dSnw break; 182c5c4113dSnw } 183c5c4113dSnw 184c5c4113dSnw 185c5c4113dSnw destruction: 186c5c4113dSnw scf_value_destroy(value); 187c5c4113dSnw scf_property_destroy(scf_prop); 188c5c4113dSnw 189c5c4113dSnw return (rc); 190c5c4113dSnw } 191c5c4113dSnw 192c5c4113dSnw static char * 1934edd44c5Sjp scf_value2string(scf_value_t *value) 1944edd44c5Sjp { 195c5c4113dSnw int rc = -1; 196c5c4113dSnw char buf_size = 127; 197c5c4113dSnw int length; 198c5c4113dSnw char *buf = NULL; 199c5c4113dSnw buf = (char *) malloc(sizeof (char) * buf_size); 200c5c4113dSnw 201c5c4113dSnw for (;;) { 202c5c4113dSnw length = scf_value_get_astring(value, buf, buf_size); 203c5c4113dSnw if (length < 0) { 204c5c4113dSnw rc = -1; 205c5c4113dSnw goto destruction; 206c5c4113dSnw } 207c5c4113dSnw 208c5c4113dSnw if (length == buf_size - 1) { 209c5c4113dSnw buf_size *= 2; 210c5c4113dSnw buf = (char *)realloc(buf, buf_size * sizeof (char)); 211c5c4113dSnw if (!buf) { 21271590c90Snw idmapdlog(LOG_ERR, "Out of memory"); 213c5c4113dSnw rc = -1; 214c5c4113dSnw goto destruction; 215c5c4113dSnw } 216c5c4113dSnw } else { 217c5c4113dSnw rc = 0; 2184edd44c5Sjp break; 2194edd44c5Sjp } 220c5c4113dSnw } 221c5c4113dSnw 222c5c4113dSnw destruction: 223c5c4113dSnw if (rc < 0) { 224c5c4113dSnw if (buf) 225c5c4113dSnw free(buf); 226c5c4113dSnw buf = NULL; 227c5c4113dSnw } 228c5c4113dSnw 229c5c4113dSnw return (buf); 230c5c4113dSnw } 231c5c4113dSnw 232c8e26105Sjp static int 233c8e26105Sjp get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport, 234*479ac375Sdm idmap_ad_disc_ds_t **val) 235c8e26105Sjp { 236*479ac375Sdm idmap_ad_disc_ds_t *servers = NULL; 237c8e26105Sjp scf_property_t *scf_prop; 238c8e26105Sjp scf_value_t *value; 239c8e26105Sjp scf_iter_t *iter; 240c8e26105Sjp char *host, *portstr; 241e3c2d6aaSnw int len, i; 242c8e26105Sjp int count = 0; 243e3c2d6aaSnw int rc = -1; 244c8e26105Sjp 245c8e26105Sjp *val = NULL; 246c8e26105Sjp 247c8e26105Sjp restart: 248c8e26105Sjp scf_prop = scf_property_create(handles->main); 249*479ac375Sdm if (scf_prop == NULL) { 250*479ac375Sdm idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 251*479ac375Sdm scf_strerror(scf_error())); 252*479ac375Sdm return (-1); 253*479ac375Sdm } 254*479ac375Sdm 255c8e26105Sjp value = scf_value_create(handles->main); 256*479ac375Sdm if (value == NULL) { 257*479ac375Sdm idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 258*479ac375Sdm scf_strerror(scf_error())); 259*479ac375Sdm scf_property_destroy(scf_prop); 260*479ac375Sdm return (-1); 261*479ac375Sdm } 262*479ac375Sdm 263c8e26105Sjp iter = scf_iter_create(handles->main); 264*479ac375Sdm if (iter == NULL) { 265*479ac375Sdm idmapdlog(LOG_ERR, "scf_iter_create() failed: %s", 266*479ac375Sdm scf_strerror(scf_error())); 267*479ac375Sdm scf_value_destroy(value); 268*479ac375Sdm scf_property_destroy(scf_prop); 269*479ac375Sdm return (-1); 270*479ac375Sdm } 271c8e26105Sjp 272e3c2d6aaSnw if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) { 273c8e26105Sjp /* this is OK: the property is just undefined */ 274e3c2d6aaSnw rc = 0; 275c8e26105Sjp goto destruction; 276e3c2d6aaSnw } 277c8e26105Sjp 278c8e26105Sjp if (scf_iter_property_values(iter, scf_prop) < 0) { 279c8e26105Sjp idmapdlog(LOG_ERR, 28071590c90Snw "scf_iter_property_values(%s) failed: %s", 28171590c90Snw name, scf_strerror(scf_error())); 282c8e26105Sjp goto destruction; 283c8e26105Sjp } 284c8e26105Sjp 285c8e26105Sjp /* Workaround scf bugs -- can't reset an iteration */ 286c8e26105Sjp if (count == 0) { 287c8e26105Sjp while (scf_iter_next_value(iter, value) > 0) 288c8e26105Sjp count++; 289c8e26105Sjp 290e3c2d6aaSnw if (count == 0) { 291c8e26105Sjp /* no values */ 292e3c2d6aaSnw rc = 0; 293c8e26105Sjp goto destruction; 294e3c2d6aaSnw } 295c8e26105Sjp 296c8e26105Sjp scf_value_destroy(value); 297c8e26105Sjp scf_iter_destroy(iter); 298c8e26105Sjp scf_property_destroy(scf_prop); 299c8e26105Sjp goto restart; 300c8e26105Sjp } 301c8e26105Sjp 302c8e26105Sjp if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) { 30371590c90Snw idmapdlog(LOG_ERR, "Out of memory"); 304c8e26105Sjp goto destruction; 305c8e26105Sjp } 306c8e26105Sjp 307e3c2d6aaSnw i = 0; 308e3c2d6aaSnw while (i < count && scf_iter_next_value(iter, value) > 0) { 309e3c2d6aaSnw servers[i].priority = 0; 310e3c2d6aaSnw servers[i].weight = 100; 311e3c2d6aaSnw servers[i].port = defport; 312c8e26105Sjp if ((host = scf_value2string(value)) == NULL) { 313c8e26105Sjp goto destruction; 314c8e26105Sjp } 315c8e26105Sjp if ((portstr = strchr(host, ':')) != NULL) { 316c8e26105Sjp *portstr++ = '\0'; 317e3c2d6aaSnw servers[i].port = strtol(portstr, 318c8e26105Sjp (char **)NULL, 10); 319e3c2d6aaSnw if (servers[i].port == 0) 320e3c2d6aaSnw servers[i].port = defport; 321c8e26105Sjp } 322e3c2d6aaSnw len = strlcpy(servers[i].host, host, 323c8e26105Sjp sizeof (servers->host)); 324c8e26105Sjp 325c8e26105Sjp free(host); 326c8e26105Sjp 327c8e26105Sjp /* Ignore this server if the hostname is too long */ 328c8e26105Sjp if (len < sizeof (servers->host)) 329e3c2d6aaSnw i++; 330c8e26105Sjp } 331c8e26105Sjp 332c8e26105Sjp *val = servers; 333c8e26105Sjp 334e3c2d6aaSnw rc = 0; 335e3c2d6aaSnw 336c8e26105Sjp destruction: 337c8e26105Sjp scf_value_destroy(value); 338c8e26105Sjp scf_iter_destroy(iter); 339c8e26105Sjp scf_property_destroy(scf_prop); 340c8e26105Sjp 341c8e26105Sjp if (rc < 0) { 342c8e26105Sjp if (servers) 343c8e26105Sjp free(servers); 344c8e26105Sjp *val = NULL; 345c8e26105Sjp } 346c8e26105Sjp 347c8e26105Sjp return (rc); 348c8e26105Sjp } 349c8e26105Sjp 350c5c4113dSnw 351c5c4113dSnw static int 352c8e26105Sjp get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val) 353c5c4113dSnw { 354c5c4113dSnw int rc = 0; 355c5c4113dSnw 356*479ac375Sdm scf_property_t *scf_prop; 357*479ac375Sdm scf_value_t *value; 358*479ac375Sdm 359*479ac375Sdm scf_prop = scf_property_create(handles->main); 360*479ac375Sdm if (scf_prop == NULL) { 361*479ac375Sdm idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 362*479ac375Sdm scf_strerror(scf_error())); 363*479ac375Sdm return (-1); 364*479ac375Sdm } 365*479ac375Sdm value = scf_value_create(handles->main); 366*479ac375Sdm if (value == NULL) { 367*479ac375Sdm idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 368*479ac375Sdm scf_strerror(scf_error())); 369*479ac375Sdm scf_property_destroy(scf_prop); 370*479ac375Sdm return (-1); 371*479ac375Sdm } 372c5c4113dSnw 373c8e26105Sjp *val = NULL; 374c5c4113dSnw 375c8e26105Sjp if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 376c5c4113dSnw /* this is OK: the property is just undefined */ 377c5c4113dSnw goto destruction; 378c5c4113dSnw 379c8e26105Sjp if (scf_property_get_value(scf_prop, value) < 0) { 380651c0131Sbaban idmapdlog(LOG_ERR, 38171590c90Snw "scf_property_get_value(%s) failed: %s", 38271590c90Snw name, scf_strerror(scf_error())); 383c5c4113dSnw rc = -1; 384c5c4113dSnw goto destruction; 385c5c4113dSnw } 386c5c4113dSnw 387c8e26105Sjp if (!(*val = scf_value2string(value))) 388c5c4113dSnw rc = -1; 389c5c4113dSnw 390c5c4113dSnw destruction: 391c5c4113dSnw scf_value_destroy(value); 392c5c4113dSnw scf_property_destroy(scf_prop); 393c5c4113dSnw 394c5c4113dSnw if (rc < 0) { 395c5c4113dSnw if (*val) 396c5c4113dSnw free(*val); 397c5c4113dSnw *val = NULL; 398c5c4113dSnw } 399c5c4113dSnw 400c5c4113dSnw return (rc); 401c5c4113dSnw } 402c5c4113dSnw 403c8e26105Sjp 4048edda628Sbaban static int 405c8e26105Sjp set_val_astring(idmap_cfg_handles_t *handles, char *name, const char *val) 4068edda628Sbaban { 407e3c2d6aaSnw int rc = -1; 408e3c2d6aaSnw int ret = -2; 409e3c2d6aaSnw int i; 4108edda628Sbaban scf_property_t *scf_prop = NULL; 4118edda628Sbaban scf_value_t *value = NULL; 4128edda628Sbaban scf_transaction_t *tx = NULL; 4138edda628Sbaban scf_transaction_entry_t *ent = NULL; 4148edda628Sbaban 415c8e26105Sjp if ((scf_prop = scf_property_create(handles->main)) == NULL || 416c8e26105Sjp (value = scf_value_create(handles->main)) == NULL || 417c8e26105Sjp (tx = scf_transaction_create(handles->main)) == NULL || 418c8e26105Sjp (ent = scf_entry_create(handles->main)) == NULL) { 41971590c90Snw idmapdlog(LOG_ERR, "Unable to set property %s", 42071590c90Snw name, scf_strerror(scf_error())); 4218edda628Sbaban goto destruction; 4228edda628Sbaban } 4238edda628Sbaban 424e3c2d6aaSnw for (i = 0; i < MAX_TRIES && (ret == -2 || ret == 0); i++) { 425c8e26105Sjp if (scf_transaction_start(tx, handles->config_pg) == -1) { 4268edda628Sbaban idmapdlog(LOG_ERR, 42771590c90Snw "scf_transaction_start(%s) failed: %s", 42871590c90Snw name, scf_strerror(scf_error())); 4298edda628Sbaban goto destruction; 4308edda628Sbaban } 4318edda628Sbaban 432e3c2d6aaSnw if (scf_transaction_property_new(tx, ent, name, 433e3c2d6aaSnw SCF_TYPE_ASTRING) < 0) { 4348edda628Sbaban idmapdlog(LOG_ERR, 43571590c90Snw "scf_transaction_property_new() failed: %s", 43671590c90Snw scf_strerror(scf_error())); 4378edda628Sbaban goto destruction; 4388edda628Sbaban } 4398edda628Sbaban 4408edda628Sbaban if (scf_value_set_astring(value, val) == -1) { 4418edda628Sbaban idmapdlog(LOG_ERR, 44271590c90Snw "scf_value_set_astring() failed: %s", 44371590c90Snw scf_strerror(scf_error())); 4448edda628Sbaban goto destruction; 4458edda628Sbaban } 4468edda628Sbaban 4478edda628Sbaban if (scf_entry_add_value(ent, value) == -1) { 4488edda628Sbaban idmapdlog(LOG_ERR, 44971590c90Snw "scf_entry_add_value() failed: %s", 45071590c90Snw scf_strerror(scf_error())); 4518edda628Sbaban goto destruction; 4528edda628Sbaban } 4538edda628Sbaban 454e3c2d6aaSnw if ((ret = scf_transaction_commit(tx)) == 1) 455e3c2d6aaSnw break; 456e3c2d6aaSnw 457e3c2d6aaSnw if (ret == 0 && i < MAX_TRIES - 1) { 4588edda628Sbaban /* 4598edda628Sbaban * Property group set in scf_transaction_start() 4608edda628Sbaban * is not the most recent. Update pg, reset tx and 4618edda628Sbaban * retry tx. 4628edda628Sbaban */ 4638edda628Sbaban idmapdlog(LOG_WARNING, 46471590c90Snw "scf_transaction_commit(%s) failed - Retry: %s", 46571590c90Snw name, scf_strerror(scf_error())); 466c8e26105Sjp if (scf_pg_update(handles->config_pg) == -1) { 4678edda628Sbaban idmapdlog(LOG_ERR, 46871590c90Snw "scf_pg_update() failed: %s", 46971590c90Snw scf_strerror(scf_error())); 4708edda628Sbaban goto destruction; 4718edda628Sbaban } 4728edda628Sbaban scf_transaction_reset(tx); 4738edda628Sbaban } 4748edda628Sbaban } 4758edda628Sbaban 476e3c2d6aaSnw 477e3c2d6aaSnw if (ret == 1) 478e3c2d6aaSnw rc = 0; 479e3c2d6aaSnw else if (ret != -2) 4808edda628Sbaban idmapdlog(LOG_ERR, 48171590c90Snw "scf_transaction_commit(%s) failed: %s", 48271590c90Snw name, scf_strerror(scf_error())); 4838edda628Sbaban 4848edda628Sbaban destruction: 4858edda628Sbaban scf_value_destroy(value); 4868edda628Sbaban scf_entry_destroy(ent); 4878edda628Sbaban scf_transaction_destroy(tx); 4888edda628Sbaban scf_property_destroy(scf_prop); 4898edda628Sbaban return (rc); 4908edda628Sbaban } 4918edda628Sbaban 492c8e26105Sjp static int 493c8e26105Sjp update_value(char **value, char **new, char *name) 494c8e26105Sjp { 495c8e26105Sjp if (*new == NULL) 496349d5d8fSnw return (0); 497c8e26105Sjp 498c8e26105Sjp if (*value != NULL && strcmp(*new, *value) == 0) { 499c8e26105Sjp free(*new); 500c8e26105Sjp *new = NULL; 501349d5d8fSnw return (0); 502c8e26105Sjp } 503c8e26105Sjp 50471590c90Snw idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new)); 505c8e26105Sjp if (*value != NULL) 506c8e26105Sjp free(*value); 507c8e26105Sjp *value = *new; 508c8e26105Sjp *new = NULL; 509349d5d8fSnw return (1); 510c8e26105Sjp } 511c8e26105Sjp 512c8e26105Sjp static int 513*479ac375Sdm update_dirs(idmap_ad_disc_ds_t **value, idmap_ad_disc_ds_t **new, char *name) 514c8e26105Sjp { 515c8e26105Sjp int i; 516c8e26105Sjp 5170dcc7149Snw if (*value == *new) 5180dcc7149Snw /* Nothing to do */ 519349d5d8fSnw return (0); 520c8e26105Sjp 5210dcc7149Snw if (*value != NULL && *new != NULL && 5220dcc7149Snw ad_disc_compare_ds(*value, *new) == 0) { 523c8e26105Sjp free(*new); 524c8e26105Sjp *new = NULL; 525349d5d8fSnw return (0); 526c8e26105Sjp } 527c8e26105Sjp 528c8e26105Sjp if (*value) 529c8e26105Sjp free(*value); 530c8e26105Sjp 531c8e26105Sjp *value = *new; 532c8e26105Sjp *new = NULL; 5330dcc7149Snw 5340dcc7149Snw if (*value == NULL) { 5350dcc7149Snw /* We're unsetting this DS property */ 53671590c90Snw idmapdlog(LOG_INFO, "change %s=<none>", name); 537349d5d8fSnw return (1); 5380dcc7149Snw } 5390dcc7149Snw 5400dcc7149Snw /* List all the new DSs */ 5410dcc7149Snw for (i = 0; (*value)[i].host[0] != '\0'; i++) 54271590c90Snw idmapdlog(LOG_INFO, "change %s=%s port=%d", name, 5430dcc7149Snw (*value)[i].host, (*value)[i].port); 544349d5d8fSnw return (1); 545c8e26105Sjp } 546c8e26105Sjp 547c8e26105Sjp 5480dcc7149Snw #define MAX_CHECK_TIME (20 * 60) 549c8e26105Sjp 550c8e26105Sjp /* 5510dcc7149Snw * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the 5520dcc7149Snw * interfaces. 553c8e26105Sjp * 5540dcc7149Snw * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON. 555c8e26105Sjp */ 556c8e26105Sjp static 557c8e26105Sjp int 5580dcc7149Snw pfroute_event_is_interesting(int rt_sock) 559c8e26105Sjp { 5600dcc7149Snw int nbytes; 5610dcc7149Snw int64_t msg[2048 / 8]; 5620dcc7149Snw struct rt_msghdr *rtm; 5630dcc7149Snw int is_interesting = FALSE; 564c8e26105Sjp 5650dcc7149Snw for (;;) { 5660dcc7149Snw if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0) 5670dcc7149Snw break; 5680dcc7149Snw rtm = (struct rt_msghdr *)msg; 5690dcc7149Snw if (rtm->rtm_version != RTM_VERSION) 5700dcc7149Snw continue; 5710dcc7149Snw if (nbytes < rtm->rtm_msglen) 5720dcc7149Snw continue; 5730dcc7149Snw switch (rtm->rtm_type) { 5740dcc7149Snw case RTM_NEWADDR: 5750dcc7149Snw case RTM_DELADDR: 5760dcc7149Snw case RTM_IFINFO: 5770dcc7149Snw is_interesting = TRUE; 5780dcc7149Snw break; 5790dcc7149Snw default: 5800dcc7149Snw break; 5810dcc7149Snw } 582c8e26105Sjp } 5830dcc7149Snw return (is_interesting); 5840dcc7149Snw } 5850dcc7149Snw 5860dcc7149Snw /* 5870dcc7149Snw * Returns 1 if SIGHUP has been received (see hup_handler() elsewhere) or if an 5880dcc7149Snw * interface address was added or removed; otherwise it returns 0. 5890dcc7149Snw * 5900dcc7149Snw * Note that port_get() does not update its timeout argument when EINTR, unlike 5910dcc7149Snw * nanosleep(). We probably don't care very much here, but if we did care then 5920dcc7149Snw * we could always use a timer event and associate it with the same event port, 5930dcc7149Snw * then we could get accurate waiting regardless of EINTRs. 5940dcc7149Snw */ 5950dcc7149Snw static 5960dcc7149Snw int 597349d5d8fSnw wait_for_event(int poke_is_interesting, struct timespec *timeoutp) 5980dcc7149Snw { 5990dcc7149Snw port_event_t pe; 600c8e26105Sjp 601c8e26105Sjp retry: 6020dcc7149Snw memset(&pe, 0, sizeof (pe)); 603349d5d8fSnw if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) { 604c8e26105Sjp switch (errno) { 605c8e26105Sjp case EINTR: 6060dcc7149Snw goto retry; 607c8e26105Sjp case ETIME: 608c8e26105Sjp /* Timeout */ 6090dcc7149Snw return (FALSE); 610c8e26105Sjp default: 6110dcc7149Snw /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */ 6120dcc7149Snw idmapdlog(LOG_ERR, "Event port failed: %s", 6130dcc7149Snw strerror(errno)); 6140dcc7149Snw exit(1); 6150dcc7149Snw /* NOTREACHED */ 616c8e26105Sjp break; 617c8e26105Sjp } 618c8e26105Sjp } 619c8e26105Sjp 6200dcc7149Snw if (pe.portev_source == PORT_SOURCE_USER && 6210dcc7149Snw pe.portev_events == POKE_AUTO_DISCOVERY) 6220dcc7149Snw return (poke_is_interesting ? TRUE : FALSE); 6230dcc7149Snw 6240dcc7149Snw if (pe.portev_source == PORT_SOURCE_FD && pe.portev_object == rt_sock) { 6250dcc7149Snw /* PF_ROUTE socket read event, re-associate fd, handle event */ 6260dcc7149Snw if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock, 6270dcc7149Snw POLLIN, NULL) != 0) { 6280dcc7149Snw idmapdlog(LOG_ERR, "Failed to re-associate the " 6290dcc7149Snw "routing socket with the event port: %s", 6300dcc7149Snw strerror(errno)); 6310dcc7149Snw exit(1); 6320dcc7149Snw } 6330dcc7149Snw /* 6340dcc7149Snw * The network configuration may still be in flux. No matter, 6350dcc7149Snw * the resolver will re-transmit and timout if need be. 6360dcc7149Snw */ 6370dcc7149Snw return (pfroute_event_is_interesting(rt_sock)); 6380dcc7149Snw } 639c8e26105Sjp 6400dcc7149Snw if (pe.portev_source == PORT_SOURCE_USER && 6410dcc7149Snw pe.portev_events == RECONFIGURE) { 642e3c2d6aaSnw int rc; 643e3c2d6aaSnw 644e3c2d6aaSnw /* 645e3c2d6aaSnw * Blow away the ccache, we might have re-joined the 646e3c2d6aaSnw * domain or joined a new one 647e3c2d6aaSnw */ 648e3c2d6aaSnw (void) unlink(IDMAP_CACHEDIR "/ccache"); 649e3c2d6aaSnw /* HUP is the refresh method, so re-read SMF config */ 65071590c90Snw (void) idmapdlog(LOG_INFO, "SMF refresh"); 651349d5d8fSnw rc = idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER|CFG_LOG); 652349d5d8fSnw if (rc < -1) { 653349d5d8fSnw (void) idmapdlog(LOG_ERR, "Fatal errors while reading " 654349d5d8fSnw "SMF properties"); 655349d5d8fSnw exit(1); 656349d5d8fSnw } else if (rc == -1) { 657349d5d8fSnw (void) idmapdlog(LOG_WARNING, "Various errors " 658349d5d8fSnw "re-loading configuration may cause AD lookups " 659349d5d8fSnw "to fail"); 660349d5d8fSnw } 661349d5d8fSnw return (FALSE); 662c8e26105Sjp } 663c8e26105Sjp 6640dcc7149Snw return (FALSE); 665c8e26105Sjp } 666c8e26105Sjp 667c8e26105Sjp void * 668c8e26105Sjp idmap_cfg_update_thread(void *arg) 669c8e26105Sjp { 670c8e26105Sjp 6710dcc7149Snw int ttl, changed, poke_is_interesting; 672c8e26105Sjp idmap_cfg_handles_t *handles = &_idmapdstate.cfg->handles; 673c8e26105Sjp ad_disc_t ad_ctx = handles->ad_ctx; 674349d5d8fSnw struct timespec timeout, *timeoutp; 675c8e26105Sjp 6760dcc7149Snw poke_is_interesting = 1; 6770dcc7149Snw for (ttl = 0, changed = TRUE; ; ttl = ad_disc_get_TTL(ad_ctx)) { 678349d5d8fSnw /* 679349d5d8fSnw * If ttl < 0 then we can wait for an event without timing out. 680349d5d8fSnw * If idmapd needs to notice that the system has been joined to 681349d5d8fSnw * a Windows domain then idmapd needs to be refreshed. 682349d5d8fSnw */ 683349d5d8fSnw timeoutp = (ttl < 0) ? NULL : &timeout; 684349d5d8fSnw if (ttl > MAX_CHECK_TIME) 685c8e26105Sjp ttl = MAX_CHECK_TIME; 6860dcc7149Snw timeout.tv_sec = ttl; 6870dcc7149Snw timeout.tv_nsec = 0; 688349d5d8fSnw changed = wait_for_event(poke_is_interesting, timeoutp); 6890dcc7149Snw 6900dcc7149Snw /* 6910dcc7149Snw * If there are no interesting events, and this is not the first 6920dcc7149Snw * time through the loop, and we haven't waited the most that 6930dcc7149Snw * we're willing to wait, so do nothing but wait some more. 6940dcc7149Snw */ 6950dcc7149Snw if (changed == FALSE && ttl > 0 && ttl < MAX_CHECK_TIME) 6960dcc7149Snw continue; 6970dcc7149Snw 6980dcc7149Snw (void) ad_disc_SubnetChanged(ad_ctx); 699c8e26105Sjp 700349d5d8fSnw if (idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER) < -1) { 701349d5d8fSnw (void) idmapdlog(LOG_ERR, "Fatal errors while reading " 702349d5d8fSnw "SMF properties"); 703349d5d8fSnw exit(1); 704349d5d8fSnw } 705c8e26105Sjp 706349d5d8fSnw if (_idmapdstate.cfg->pgcfg.global_catalog == NULL || 707349d5d8fSnw _idmapdstate.cfg->pgcfg.global_catalog[0].host[0] == '\0') 7080dcc7149Snw poke_is_interesting = 1; 709349d5d8fSnw else 7100dcc7149Snw poke_is_interesting = 0; 711c8e26105Sjp } 712c8e26105Sjp /*NOTREACHED*/ 713c8e26105Sjp return (NULL); 714c8e26105Sjp } 715c8e26105Sjp 716c8e26105Sjp int 7170dcc7149Snw idmap_cfg_start_updates(void) 718c8e26105Sjp { 7190dcc7149Snw if ((idmapd_ev_port = port_create()) < 0) { 72071590c90Snw idmapdlog(LOG_ERR, "Failed to create event port: %s", 72171590c90Snw strerror(errno)); 722c8e26105Sjp return (-1); 7230dcc7149Snw } 7240dcc7149Snw 7250dcc7149Snw if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 72671590c90Snw idmapdlog(LOG_ERR, "Failed to open routing socket: %s", 72771590c90Snw strerror(errno)); 7280dcc7149Snw (void) close(idmapd_ev_port); 7290dcc7149Snw return (-1); 7300dcc7149Snw } 7310dcc7149Snw 7320dcc7149Snw if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) { 73371590c90Snw idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s", 73471590c90Snw strerror(errno)); 7350dcc7149Snw (void) close(rt_sock); 7360dcc7149Snw (void) close(idmapd_ev_port); 7370dcc7149Snw return (-1); 7380dcc7149Snw } 7390dcc7149Snw 7400dcc7149Snw if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, 7410dcc7149Snw rt_sock, POLLIN, NULL) != 0) { 74271590c90Snw idmapdlog(LOG_ERR, "Failed to associate the routing " 74371590c90Snw "socket with the event port: %s", strerror(errno)); 7440dcc7149Snw (void) close(rt_sock); 7450dcc7149Snw (void) close(idmapd_ev_port); 7460dcc7149Snw return (-1); 7470dcc7149Snw } 7480dcc7149Snw 7490dcc7149Snw if ((errno = pthread_create(&update_thread_handle, NULL, 7500dcc7149Snw idmap_cfg_update_thread, NULL)) != 0) { 75171590c90Snw idmapdlog(LOG_ERR, "Failed to start update thread: %s", 75271590c90Snw strerror(errno)); 7530dcc7149Snw (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock); 7540dcc7149Snw (void) close(rt_sock); 7550dcc7149Snw (void) close(idmapd_ev_port); 7560dcc7149Snw return (-1); 7570dcc7149Snw } 7580dcc7149Snw 7590dcc7149Snw return (0); 760c8e26105Sjp } 761c8e26105Sjp 762*479ac375Sdm /* 763*479ac375Sdm * Reject attribute names with invalid characters. 764*479ac375Sdm */ 765*479ac375Sdm static 766*479ac375Sdm int 767*479ac375Sdm valid_ldap_attr(const char *attr) { 768*479ac375Sdm for (; *attr; attr++) { 769*479ac375Sdm if (!isalnum(*attr) && *attr != '-' && 770*479ac375Sdm *attr != '_' && *attr != '.' && *attr != ';') 771*479ac375Sdm return (0); 772*479ac375Sdm } 773*479ac375Sdm return (1); 774*479ac375Sdm } 775*479ac375Sdm 776349d5d8fSnw /* 777349d5d8fSnw * This is the half of idmap_cfg_load() that loads property values from 778349d5d8fSnw * SMF (using the config/ property group of the idmap FMRI). 779349d5d8fSnw * 780349d5d8fSnw * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 781*479ac375Sdm * -3 -> hard smf config failures 782349d5d8fSnw * reading from SMF. 783349d5d8fSnw */ 784349d5d8fSnw static 785c5c4113dSnw int 786349d5d8fSnw idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, 787349d5d8fSnw int *errors) 788c5c4113dSnw { 789e3c2d6aaSnw int rc; 790e8c27ec8Sbaban uint8_t bool_val; 791c8e26105Sjp char *str = NULL; 79271590c90Snw bool_t new_debug_mode; 793c8e26105Sjp 794c8e26105Sjp if (scf_pg_update(handles->config_pg) < 0) { 79571590c90Snw idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 79671590c90Snw scf_strerror(scf_error())); 797349d5d8fSnw return (-2); 798c5c4113dSnw } 799c5c4113dSnw 800c8e26105Sjp if (scf_pg_update(handles->general_pg) < 0) { 80171590c90Snw idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 80271590c90Snw scf_strerror(scf_error())); 803349d5d8fSnw return (-2); 804c5c4113dSnw } 805c5c4113dSnw 806*479ac375Sdm 807*479ac375Sdm rc = prop_exists(handles, "debug", &new_debug_mode); 808*479ac375Sdm if (rc != 0) 809*479ac375Sdm errors++; 810*479ac375Sdm 81171590c90Snw if (_idmapdstate.debug_mode != new_debug_mode) { 81271590c90Snw if (_idmapdstate.debug_mode == FALSE) { 81371590c90Snw _idmapdstate.debug_mode = new_debug_mode; 81471590c90Snw idmapdlog(LOG_DEBUG, "debug mode enabled"); 81571590c90Snw } else { 81671590c90Snw idmapdlog(LOG_DEBUG, "debug mode disabled"); 81771590c90Snw _idmapdstate.debug_mode = new_debug_mode; 81871590c90Snw } 81971590c90Snw } 82071590c90Snw 821c8e26105Sjp rc = get_val_int(handles, "list_size_limit", 822c8e26105Sjp &pgcfg->list_size_limit, SCF_TYPE_COUNT); 823c8e26105Sjp if (rc != 0) { 824e3c2d6aaSnw pgcfg->list_size_limit = 0; 825e3c2d6aaSnw errors++; 826c8e26105Sjp } 827c5c4113dSnw 828c8e26105Sjp rc = get_val_astring(handles, "domain_name", 829c8e26105Sjp &pgcfg->domain_name); 830e3c2d6aaSnw if (rc != 0) 831e3c2d6aaSnw errors++; 832e3c2d6aaSnw else 833349d5d8fSnw (void) ad_disc_set_DomainName(handles->ad_ctx, 834349d5d8fSnw pgcfg->domain_name); 835c8e26105Sjp 836c8e26105Sjp rc = get_val_astring(handles, "default_domain", 837c8e26105Sjp &pgcfg->default_domain); 838c8e26105Sjp if (rc != 0) { 839e3c2d6aaSnw /* 840e3c2d6aaSnw * SCF failures fetching config/default_domain we treat 841e3c2d6aaSnw * as fatal as they may leave ID mapping rules that 842e3c2d6aaSnw * match unqualified winnames flapping in the wind. 843e3c2d6aaSnw */ 844349d5d8fSnw return (-2); 845c8e26105Sjp } 846c8e26105Sjp 847c8e26105Sjp rc = get_val_astring(handles, "mapping_domain", &str); 848e3c2d6aaSnw if (rc != 0) 849e3c2d6aaSnw errors++; 850c5c4113dSnw 851c5c4113dSnw /* 852c8e26105Sjp * We treat default_domain as having been specified in SMF IFF 853c8e26105Sjp * either (the config/default_domain property was set) or (the 854c8e26105Sjp * old, obsolete, never documented config/mapping_domain 855c8e26105Sjp * property was set and the new config/domain_name property was 856c8e26105Sjp * not set). 857c5c4113dSnw */ 858c8e26105Sjp pgcfg->dflt_dom_set_in_smf = TRUE; 859c8e26105Sjp if (pgcfg->default_domain == NULL) { 860c8e26105Sjp 861c8e26105Sjp pgcfg->dflt_dom_set_in_smf = FALSE; 862c8e26105Sjp 863c8e26105Sjp if (pgcfg->domain_name != NULL) { 864c8e26105Sjp pgcfg->default_domain = strdup(pgcfg->domain_name); 865c8e26105Sjp if (str != NULL) { 866c8e26105Sjp idmapdlog(LOG_WARNING, 86771590c90Snw "Ignoring obsolete, undocumented " 86871590c90Snw "config/mapping_domain property"); 869c8e26105Sjp } 870c8e26105Sjp } else if (str != NULL) { 871c8e26105Sjp pgcfg->default_domain = strdup(str); 872c8e26105Sjp pgcfg->dflt_dom_set_in_smf = TRUE; 873c8e26105Sjp idmapdlog(LOG_WARNING, 87471590c90Snw "The config/mapping_domain property is " 875c8e26105Sjp "obsolete; support for it will be removed, " 87671590c90Snw "please use config/default_domain instead"); 877c5c4113dSnw } 878c5c4113dSnw } 879c5c4113dSnw 880c8e26105Sjp if (str != NULL) 881c8e26105Sjp free(str); 882c8e26105Sjp 883c8e26105Sjp rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid); 884e3c2d6aaSnw if (rc != 0) 885e3c2d6aaSnw errors++; 886c8e26105Sjp if (pgcfg->machine_sid == NULL) { 8878edda628Sbaban /* If machine_sid not configured, generate one */ 888349d5d8fSnw if (generate_machine_sid(&pgcfg->machine_sid) < 0) 889349d5d8fSnw return (-2); 890c8e26105Sjp rc = set_val_astring(handles, "machine_sid", 891c8e26105Sjp pgcfg->machine_sid); 892e3c2d6aaSnw if (rc != 0) 893e3c2d6aaSnw errors++; 8948edda628Sbaban } 895c5c4113dSnw 896c8e26105Sjp str = NULL; 897c8e26105Sjp rc = get_val_ds(handles, "domain_controller", 389, 898c8e26105Sjp &pgcfg->domain_controller); 899e3c2d6aaSnw if (rc != 0) 900e3c2d6aaSnw errors++; 901e3c2d6aaSnw else 902349d5d8fSnw (void) ad_disc_set_DomainController(handles->ad_ctx, 903e3c2d6aaSnw pgcfg->domain_controller); 904c5c4113dSnw 905c8e26105Sjp rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name); 906e3c2d6aaSnw if (rc != 0) 907e3c2d6aaSnw errors++; 908e3c2d6aaSnw else 909349d5d8fSnw (void) ad_disc_set_ForestName(handles->ad_ctx, 910349d5d8fSnw pgcfg->forest_name); 911c8e26105Sjp 912c8e26105Sjp rc = get_val_astring(handles, "site_name", &pgcfg->site_name); 913e3c2d6aaSnw if (rc != 0) 914e3c2d6aaSnw errors++; 915e3c2d6aaSnw else 916349d5d8fSnw (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name); 917c8e26105Sjp 918c8e26105Sjp str = NULL; 919c8e26105Sjp rc = get_val_ds(handles, "global_catalog", 3268, 920c8e26105Sjp &pgcfg->global_catalog); 921e3c2d6aaSnw if (rc != 0) 922e3c2d6aaSnw errors++; 923e3c2d6aaSnw else 924349d5d8fSnw (void) ad_disc_set_GlobalCatalog(handles->ad_ctx, 925349d5d8fSnw pgcfg->global_catalog); 926c8e26105Sjp 927e8c27ec8Sbaban /* 928e8c27ec8Sbaban * Read directory-based name mappings related SMF properties 929e8c27ec8Sbaban */ 930e8c27ec8Sbaban bool_val = 0; 931e8c27ec8Sbaban rc = get_val_int(handles, "ds_name_mapping_enabled", 932e8c27ec8Sbaban &bool_val, SCF_TYPE_BOOLEAN); 933349d5d8fSnw if (rc != 0) 934349d5d8fSnw return (-2); 935e8c27ec8Sbaban 936349d5d8fSnw if (!bool_val) 937349d5d8fSnw return (rc); 938e8c27ec8Sbaban 939349d5d8fSnw pgcfg->ds_name_mapping_enabled = TRUE; 940349d5d8fSnw rc = get_val_astring(handles, "ad_unixuser_attr", 941349d5d8fSnw &pgcfg->ad_unixuser_attr); 942349d5d8fSnw if (rc != 0) 943349d5d8fSnw return (-2); 944*479ac375Sdm if (pgcfg->ad_unixuser_attr != NULL && 945*479ac375Sdm !valid_ldap_attr(pgcfg->ad_unixuser_attr)) { 946*479ac375Sdm idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a " 947*479ac375Sdm "valid LDAP attribute name", pgcfg->ad_unixuser_attr); 948*479ac375Sdm return (-3); 949*479ac375Sdm } 950e8c27ec8Sbaban 951349d5d8fSnw rc = get_val_astring(handles, "ad_unixgroup_attr", 952349d5d8fSnw &pgcfg->ad_unixgroup_attr); 953349d5d8fSnw if (rc != 0) 954349d5d8fSnw return (-2); 955*479ac375Sdm if (pgcfg->ad_unixgroup_attr != NULL && 956*479ac375Sdm !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) { 957*479ac375Sdm idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a " 958*479ac375Sdm "valid LDAP attribute name", pgcfg->ad_unixgroup_attr); 959*479ac375Sdm return (-3); 960*479ac375Sdm } 961e8c27ec8Sbaban 962349d5d8fSnw rc = get_val_astring(handles, "nldap_winname_attr", 963349d5d8fSnw &pgcfg->nldap_winname_attr); 964349d5d8fSnw if (rc != 0) 965349d5d8fSnw return (-2); 966*479ac375Sdm if (pgcfg->nldap_winname_attr != NULL && 967*479ac375Sdm !valid_ldap_attr(pgcfg->nldap_winname_attr)) { 968*479ac375Sdm idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a " 969*479ac375Sdm "valid LDAP attribute name", pgcfg->nldap_winname_attr); 970349d5d8fSnw return (-3); 971e8c27ec8Sbaban } 972349d5d8fSnw if (pgcfg->ad_unixuser_attr == NULL && 973*479ac375Sdm pgcfg->ad_unixgroup_attr == NULL && 974*479ac375Sdm pgcfg->nldap_winname_attr == NULL) { 975349d5d8fSnw idmapdlog(LOG_ERR, 976349d5d8fSnw "If config/ds_name_mapping_enabled property is set to " 977349d5d8fSnw "true then atleast one of the following name mapping " 978349d5d8fSnw "attributes must be specified. (config/ad_unixuser_attr OR " 979*479ac375Sdm "config/ad_unixgroup_attr OR config/nldap_winname_attr)"); 980349d5d8fSnw return (-3); 981349d5d8fSnw } 982c8e26105Sjp 983349d5d8fSnw return (rc); 984e3c2d6aaSnw 985349d5d8fSnw } 986349d5d8fSnw 987349d5d8fSnw /* 988349d5d8fSnw * This is the half of idmap_cfg_load() that auto-discovers values of 989349d5d8fSnw * discoverable properties that weren't already set via SMF properties. 990349d5d8fSnw * 991349d5d8fSnw * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it 992349d5d8fSnw * needs to be careful not to overwrite any properties set in SMF. 993349d5d8fSnw */ 994349d5d8fSnw static 995349d5d8fSnw void 996349d5d8fSnw idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) 997349d5d8fSnw { 998349d5d8fSnw ad_disc_t ad_ctx = handles->ad_ctx; 999349d5d8fSnw 1000349d5d8fSnw ad_disc_refresh(ad_ctx); 1001349d5d8fSnw 1002349d5d8fSnw if (pgcfg->default_domain == NULL) 1003c8e26105Sjp pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx); 1004c8e26105Sjp 1005349d5d8fSnw if (pgcfg->domain_name == NULL) 1006c8e26105Sjp pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx); 1007c8e26105Sjp 1008349d5d8fSnw if (pgcfg->domain_controller == NULL) 1009c8e26105Sjp pgcfg->domain_controller = 1010c8e26105Sjp ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE); 1011c8e26105Sjp 1012349d5d8fSnw if (pgcfg->forest_name == NULL) 1013c8e26105Sjp pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx); 1014c8e26105Sjp 1015349d5d8fSnw if (pgcfg->site_name == NULL) 1016c8e26105Sjp pgcfg->site_name = ad_disc_get_SiteName(ad_ctx); 1017c8e26105Sjp 1018349d5d8fSnw if (pgcfg->global_catalog == NULL) 1019c8e26105Sjp pgcfg->global_catalog = 1020c8e26105Sjp ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE); 1021349d5d8fSnw 1022349d5d8fSnw if (pgcfg->domain_name == NULL) 1023349d5d8fSnw idmapdlog(LOG_DEBUG, "unable to discover Domain Name"); 1024349d5d8fSnw if (pgcfg->domain_controller == NULL) 1025349d5d8fSnw idmapdlog(LOG_DEBUG, "unable to discover Domain Controller"); 1026349d5d8fSnw if (pgcfg->forest_name == NULL) 1027349d5d8fSnw idmapdlog(LOG_DEBUG, "unable to discover Forest Name"); 1028349d5d8fSnw if (pgcfg->site_name == NULL) 1029349d5d8fSnw idmapdlog(LOG_DEBUG, "unable to discover Site Name"); 1030349d5d8fSnw if (pgcfg->global_catalog == NULL) 1031349d5d8fSnw idmapdlog(LOG_DEBUG, "unable to discover Global Catalog"); 1032349d5d8fSnw } 1033349d5d8fSnw 1034349d5d8fSnw /* 1035349d5d8fSnw * idmap_cfg_load() is called at startup, and periodically via the 1036349d5d8fSnw * update thread when the auto-discovery TTLs expire, as well as part of 1037349d5d8fSnw * the refresh method, to update the current configuration. It always 1038349d5d8fSnw * reads from SMF, but you still have to refresh the service after 1039349d5d8fSnw * changing the config pg in order for the changes to take effect. 1040349d5d8fSnw * 1041349d5d8fSnw * There are two flags: 1042349d5d8fSnw * 1043349d5d8fSnw * - CFG_DISCOVER 1044349d5d8fSnw * - CFG_LOG 1045349d5d8fSnw * 1046349d5d8fSnw * If CFG_DISCOVER is set then idmap_cfg_load() calls 1047349d5d8fSnw * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property 1048349d5d8fSnw * values that weren't set in SMF. 1049349d5d8fSnw * 1050349d5d8fSnw * If CFG_LOG is set then idmap_cfg_load() will log (to LOG_NOTICE) 1051349d5d8fSnw * whether the configuration changed. This should be used only from the 1052349d5d8fSnw * refresh method. 1053349d5d8fSnw * 1054349d5d8fSnw * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 1055349d5d8fSnw * reading from SMF. 1056349d5d8fSnw */ 1057349d5d8fSnw int 1058349d5d8fSnw idmap_cfg_load(idmap_cfg_t *cfg, int flags) 1059349d5d8fSnw { 1060349d5d8fSnw int rc = 0; 1061349d5d8fSnw int errors = 0; 1062349d5d8fSnw int changed = 0; 1063349d5d8fSnw idmap_pg_config_t new_pgcfg, *live_pgcfg; 1064349d5d8fSnw 1065349d5d8fSnw live_pgcfg = &cfg->pgcfg; 1066349d5d8fSnw (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg)); 1067349d5d8fSnw 1068349d5d8fSnw pthread_mutex_lock(&cfg->handles.mutex); 1069349d5d8fSnw 1070349d5d8fSnw if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1) 1071349d5d8fSnw goto err; 1072349d5d8fSnw 1073349d5d8fSnw if (flags & CFG_DISCOVER) 1074349d5d8fSnw idmap_cfg_discover(&cfg->handles, &new_pgcfg); 1075349d5d8fSnw 1076349d5d8fSnw WRLOCK_CONFIG(); 1077349d5d8fSnw if (live_pgcfg->list_size_limit != new_pgcfg.list_size_limit) { 1078349d5d8fSnw idmapdlog(LOG_INFO, "change list_size=%d", 1079349d5d8fSnw new_pgcfg.list_size_limit); 1080349d5d8fSnw live_pgcfg->list_size_limit = new_pgcfg.list_size_limit; 1081349d5d8fSnw } 1082349d5d8fSnw 1083349d5d8fSnw /* Non-discoverable props updated here */ 1084349d5d8fSnw changed += update_value(&live_pgcfg->machine_sid, 1085349d5d8fSnw &new_pgcfg.machine_sid, "machine_sid"); 1086349d5d8fSnw 1087349d5d8fSnw changed += live_pgcfg->ds_name_mapping_enabled != 1088349d5d8fSnw new_pgcfg.ds_name_mapping_enabled; 1089349d5d8fSnw live_pgcfg->ds_name_mapping_enabled = 1090349d5d8fSnw new_pgcfg.ds_name_mapping_enabled; 1091349d5d8fSnw 1092349d5d8fSnw changed += update_value(&live_pgcfg->ad_unixuser_attr, 1093349d5d8fSnw &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr"); 1094349d5d8fSnw 1095349d5d8fSnw changed += update_value(&live_pgcfg->ad_unixgroup_attr, 1096349d5d8fSnw &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr"); 1097349d5d8fSnw 1098349d5d8fSnw changed += update_value(&live_pgcfg->nldap_winname_attr, 1099349d5d8fSnw &new_pgcfg.nldap_winname_attr, "nldap_winname_attr"); 1100349d5d8fSnw 1101349d5d8fSnw /* Props that can be discovered and set in SMF updated here */ 1102349d5d8fSnw if (live_pgcfg->dflt_dom_set_in_smf == FALSE) 1103349d5d8fSnw changed += update_value(&live_pgcfg->default_domain, 1104349d5d8fSnw &new_pgcfg.default_domain, "default_domain"); 1105349d5d8fSnw 1106349d5d8fSnw changed += update_value(&live_pgcfg->domain_name, 1107349d5d8fSnw &new_pgcfg.domain_name, "domain_name"); 1108349d5d8fSnw 1109349d5d8fSnw changed += update_dirs(&live_pgcfg->domain_controller, 1110349d5d8fSnw &new_pgcfg.domain_controller, "domain_controller"); 1111349d5d8fSnw 1112349d5d8fSnw changed += update_value(&live_pgcfg->forest_name, 1113349d5d8fSnw &new_pgcfg.forest_name, "forest_name"); 1114349d5d8fSnw 1115349d5d8fSnw changed += update_value(&live_pgcfg->site_name, 1116349d5d8fSnw &new_pgcfg.site_name, "site_name"); 1117349d5d8fSnw 1118349d5d8fSnw if (update_dirs(&live_pgcfg->global_catalog, 1119349d5d8fSnw &new_pgcfg.global_catalog, "global_catalog")) { 1120349d5d8fSnw changed++; 1121349d5d8fSnw /* 1122349d5d8fSnw * Right now we only update the ad_t used for AD lookups 1123349d5d8fSnw * when the GC list is updated. When we add mixed 1124349d5d8fSnw * ds-based mapping we'll also need to update the ad_t 1125349d5d8fSnw * used to talk to the domain, not just the one used to 1126349d5d8fSnw * talk to the GC. 1127349d5d8fSnw */ 1128349d5d8fSnw if (live_pgcfg->global_catalog != NULL && 1129349d5d8fSnw live_pgcfg->global_catalog[0].host[0] != '\0') 1130349d5d8fSnw reload_ad(); 1131349d5d8fSnw } 1132349d5d8fSnw 1133349d5d8fSnw idmap_cfg_unload(&new_pgcfg); 1134349d5d8fSnw 1135349d5d8fSnw if (flags & CFG_LOG) { 1136349d5d8fSnw /* 1137349d5d8fSnw * If the config changes as a result of a refresh of the 1138349d5d8fSnw * service, then logging about it can provide useful 1139349d5d8fSnw * feedback to the sysadmin. 1140349d5d8fSnw */ 1141349d5d8fSnw idmapdlog(LOG_NOTICE, "Configuration %schanged", 1142349d5d8fSnw changed ? "" : "un"); 1143c8e26105Sjp } 1144e3c2d6aaSnw 1145349d5d8fSnw UNLOCK_CONFIG(); 1146349d5d8fSnw 1147349d5d8fSnw err: 1148349d5d8fSnw pthread_mutex_unlock(&cfg->handles.mutex); 1149c5c4113dSnw 1150e8c27ec8Sbaban if (rc < -1) 1151e3c2d6aaSnw return (rc); 1152e3c2d6aaSnw 1153e3c2d6aaSnw return ((errors == 0) ? 0 : -1); 1154c5c4113dSnw } 1155c5c4113dSnw 1156651c0131Sbaban /* 1157651c0131Sbaban * Initialize 'cfg'. 1158651c0131Sbaban */ 1159c5c4113dSnw idmap_cfg_t * 11604edd44c5Sjp idmap_cfg_init() 11614edd44c5Sjp { 1162c8e26105Sjp idmap_cfg_handles_t *handles; 1163c5c4113dSnw 1164c5c4113dSnw /* First the smf repository handles: */ 1165c5c4113dSnw idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t)); 1166c5c4113dSnw if (!cfg) { 116771590c90Snw idmapdlog(LOG_ERR, "Out of memory"); 1168c5c4113dSnw return (NULL); 1169c5c4113dSnw } 1170c8e26105Sjp handles = &cfg->handles; 1171c5c4113dSnw 1172c8e26105Sjp (void) pthread_mutex_init(&handles->mutex, NULL); 1173c8e26105Sjp 1174c8e26105Sjp if (!(handles->main = scf_handle_create(SCF_VERSION))) { 117571590c90Snw idmapdlog(LOG_ERR, "scf_handle_create() failed: %s", 117671590c90Snw scf_strerror(scf_error())); 1177c5c4113dSnw goto error; 1178c5c4113dSnw } 1179c5c4113dSnw 1180c8e26105Sjp if (scf_handle_bind(handles->main) < 0) { 118171590c90Snw idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s", 118271590c90Snw scf_strerror(scf_error())); 1183c5c4113dSnw goto error; 1184c5c4113dSnw } 1185c5c4113dSnw 1186c8e26105Sjp if (!(handles->service = scf_service_create(handles->main)) || 1187c8e26105Sjp !(handles->instance = scf_instance_create(handles->main)) || 1188c8e26105Sjp !(handles->config_pg = scf_pg_create(handles->main)) || 1189c8e26105Sjp !(handles->general_pg = scf_pg_create(handles->main))) { 119071590c90Snw idmapdlog(LOG_ERR, "scf handle creation failed: %s", 119171590c90Snw scf_strerror(scf_error())); 1192c5c4113dSnw goto error; 1193c5c4113dSnw } 1194c5c4113dSnw 1195c8e26105Sjp if (scf_handle_decode_fmri(handles->main, 11964edd44c5Sjp FMRI_BASE "/:properties/" CONFIG_PG, 11974edd44c5Sjp NULL, /* scope */ 11984edd44c5Sjp handles->service, /* service */ 11994edd44c5Sjp handles->instance, /* instance */ 12004edd44c5Sjp handles->config_pg, /* pg */ 12014edd44c5Sjp NULL, /* prop */ 12024edd44c5Sjp SCF_DECODE_FMRI_EXACT) < 0) { 120371590c90Snw idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s", 120471590c90Snw scf_strerror(scf_error())); 1205c5c4113dSnw goto error; 1206c5c4113dSnw } 1207c5c4113dSnw 1208c8e26105Sjp if (scf_service_get_pg(handles->service, 12094edd44c5Sjp GENERAL_PG, handles->general_pg) < 0) { 121071590c90Snw idmapdlog(LOG_ERR, "scf_service_get_pg() failed: %s", 121171590c90Snw scf_strerror(scf_error())); 1212c5c4113dSnw goto error; 1213c5c4113dSnw } 1214c5c4113dSnw 1215c8e26105Sjp /* Initialize AD Auto Discovery context */ 1216c8e26105Sjp handles->ad_ctx = ad_disc_init(); 1217c8e26105Sjp if (handles->ad_ctx == NULL) 1218c8e26105Sjp goto error; 1219c8e26105Sjp 1220c5c4113dSnw return (cfg); 1221c5c4113dSnw 1222c5c4113dSnw error: 1223c5c4113dSnw (void) idmap_cfg_fini(cfg); 1224c5c4113dSnw return (NULL); 1225c5c4113dSnw } 1226c5c4113dSnw 1227c8e26105Sjp void 12284edd44c5Sjp idmap_cfg_unload(idmap_pg_config_t *pgcfg) 12294edd44c5Sjp { 1230c8e26105Sjp 1231c8e26105Sjp if (pgcfg->default_domain) { 1232c8e26105Sjp free(pgcfg->default_domain); 1233c8e26105Sjp pgcfg->default_domain = NULL; 1234c8e26105Sjp } 1235c8e26105Sjp if (pgcfg->domain_name) { 1236c8e26105Sjp free(pgcfg->domain_name); 1237c8e26105Sjp pgcfg->domain_name = NULL; 1238c8e26105Sjp } 1239c8e26105Sjp if (pgcfg->machine_sid) { 1240c8e26105Sjp free(pgcfg->machine_sid); 1241c8e26105Sjp pgcfg->machine_sid = NULL; 1242c8e26105Sjp } 1243c8e26105Sjp if (pgcfg->domain_controller) { 1244c5c4113dSnw free(pgcfg->domain_controller); 1245c8e26105Sjp pgcfg->domain_controller = NULL; 1246c8e26105Sjp } 1247c8e26105Sjp if (pgcfg->forest_name) { 1248c8e26105Sjp free(pgcfg->forest_name); 1249c8e26105Sjp pgcfg->forest_name = NULL; 1250c8e26105Sjp } 1251c8e26105Sjp if (pgcfg->site_name) { 1252c8e26105Sjp free(pgcfg->site_name); 1253c8e26105Sjp pgcfg->site_name = NULL; 1254c8e26105Sjp } 1255c8e26105Sjp if (pgcfg->global_catalog) { 1256c8e26105Sjp free(pgcfg->global_catalog); 1257c8e26105Sjp pgcfg->global_catalog = NULL; 1258c8e26105Sjp } 1259e8c27ec8Sbaban if (pgcfg->ad_unixuser_attr) { 1260e8c27ec8Sbaban free(pgcfg->ad_unixuser_attr); 1261e8c27ec8Sbaban pgcfg->ad_unixuser_attr = NULL; 1262e8c27ec8Sbaban } 1263e8c27ec8Sbaban if (pgcfg->ad_unixgroup_attr) { 1264e8c27ec8Sbaban free(pgcfg->ad_unixgroup_attr); 1265e8c27ec8Sbaban pgcfg->ad_unixgroup_attr = NULL; 1266e8c27ec8Sbaban } 1267e8c27ec8Sbaban if (pgcfg->nldap_winname_attr) { 1268e8c27ec8Sbaban free(pgcfg->nldap_winname_attr); 1269e8c27ec8Sbaban pgcfg->nldap_winname_attr = NULL; 1270e8c27ec8Sbaban } 1271c5c4113dSnw } 1272c5c4113dSnw 1273c5c4113dSnw int 1274c5c4113dSnw idmap_cfg_fini(idmap_cfg_t *cfg) 1275c5c4113dSnw { 1276c8e26105Sjp idmap_cfg_handles_t *handles = &cfg->handles; 1277c8e26105Sjp idmap_cfg_unload(&cfg->pgcfg); 1278c8e26105Sjp 1279c8e26105Sjp (void) pthread_mutex_destroy(&handles->mutex); 1280c8e26105Sjp scf_pg_destroy(handles->config_pg); 1281c8e26105Sjp scf_pg_destroy(handles->general_pg); 1282c8e26105Sjp scf_instance_destroy(handles->instance); 1283c8e26105Sjp scf_service_destroy(handles->service); 1284c8e26105Sjp scf_handle_destroy(handles->main); 1285e8c27ec8Sbaban if (handles->ad_ctx != NULL) 1286e8c27ec8Sbaban ad_disc_fini(handles->ad_ctx); 1287c5c4113dSnw free(cfg); 1288c5c4113dSnw 1289c5c4113dSnw return (0); 1290c5c4113dSnw } 12910dcc7149Snw 12920dcc7149Snw void 12930dcc7149Snw idmap_cfg_poke_updates(void) 12940dcc7149Snw { 1295349d5d8fSnw if (idmapd_ev_port != -1) 1296349d5d8fSnw (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL); 12970dcc7149Snw } 12980dcc7149Snw 12990dcc7149Snw /*ARGSUSED*/ 13000dcc7149Snw void 1301349d5d8fSnw idmap_cfg_hup_handler(int sig) 1302349d5d8fSnw { 13030dcc7149Snw if (idmapd_ev_port >= 0) 13040dcc7149Snw (void) port_send(idmapd_ev_port, RECONFIGURE, NULL); 13050dcc7149Snw } 1306