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.
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.
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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 * Config routines common to idmap(1M) and idmapd(1M)
38 #include <uuid/uuid.h>
41 #include <sys/socket.h>
42 #include <net/route.h>
43 #include <sys/u8_textprep.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
51 #define MACHINE_SID_LEN (9 + 3 * 11)
52 #define FMRI_BASE "svc:/system/idmap"
53 #define CONFIG_PG "config"
54 #define DEBUG_PG "debug"
56 #define POKE_AUTO_DISCOVERY 2
57 #define KICK_AUTO_DISCOVERY 3
60 * Default cache timeouts. Can override via svccfg
61 * config/id_cache_timeout = count: seconds
62 * config/name_cache_timeout = count: seconds
64 #define ID_CACHE_TMO_DEFAULT 86400
65 #define NAME_CACHE_TMO_DEFAULT 604800
68 * Default maximum time between rediscovery runs.
69 * config/rediscovery_interval = count: seconds
71 #define REDISCOVERY_INTERVAL_DEFAULT 3600
74 * Mininum time between rediscovery runs, in case adutils gives us a
75 * really short TTL (which it never should, but be defensive)
76 * (not configurable) seconds.
78 #define MIN_REDISCOVERY_INTERVAL 60
81 EVENT_NOTHING
, /* Woke up for no good reason */
82 EVENT_TIMEOUT
, /* Timeout expired */
83 EVENT_ROUTING
, /* An interesting routing event happened */
84 EVENT_POKED
, /* Requested from degrade_svc() */
85 EVENT_KICKED
, /* Force rediscovery, i.e. DC failed. */
86 EVENT_REFRESH
, /* SMF refresh */
90 static void idmapd_set_krb5_realm(char *);
92 static pthread_t update_thread_handle
= 0;
94 static int idmapd_ev_port
= -1;
95 static int rt_sock
= -1;
97 struct enum_lookup_map directory_mapping_map
[] = {
98 { DIRECTORY_MAPPING_NONE
, "none" },
99 { DIRECTORY_MAPPING_NAME
, "name" },
100 { DIRECTORY_MAPPING_IDMU
, "idmu" },
104 struct enum_lookup_map trust_dir_map
[] = {
105 { 1, "they trust us" },
106 { 2, "we trust them" },
107 { 3, "we trust each other" },
112 generate_machine_uuid(char **machine_uuid
)
116 *machine_uuid
= calloc(1, UUID_PRINTABLE_STRING_LENGTH
+ 1);
117 if (*machine_uuid
== NULL
) {
118 idmapdlog(LOG_ERR
, "Out of memory");
123 uuid_generate_time(uu
);
124 uuid_unparse(uu
, *machine_uuid
);
130 generate_machine_sid(char **machine_sid
, char *machine_uuid
)
139 * Split the 128-bit machine UUID into three 32-bit values
140 * we'll use as the "sub-authorities" of the machine SID.
141 * The machine_sid will have the form S-1-5-21-J-K-L
142 * (that's four sub-authorities altogether) where:
143 * J = last 4 bytes of node_addr,
144 * K = time_mid, time_hi_and_version
149 (void) memset(&uv
, 0, sizeof (uv
));
150 (void) uuid_parse(machine_uuid
, uv
.uu
);
152 len
= asprintf(machine_sid
, "S-1-5-21-%u-%u-%u",
153 uv
.v
[3], uv
.v
[0], uv
.v
[1]);
155 if (len
== -1 || *machine_sid
== NULL
) {
156 idmapdlog(LOG_ERR
, "Out of memory");
164 /* In the case of error, exists is set to FALSE anyway */
166 prop_exists(idmap_cfg_handles_t
*handles
, const char *name
, boolean_t
*exists
)
169 scf_property_t
*scf_prop
;
173 scf_prop
= scf_property_create(handles
->main
);
174 if (scf_prop
== NULL
) {
175 idmapdlog(LOG_ERR
, "scf_property_create() failed: %s",
176 scf_strerror(scf_error()));
180 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) == 0)
183 scf_property_destroy(scf_prop
);
189 get_debug(idmap_cfg_handles_t
*handles
, const char *name
)
193 scf_property_t
*scf_prop
;
196 scf_prop
= scf_property_create(handles
->main
);
197 if (scf_prop
== NULL
) {
198 idmapdlog(LOG_ERR
, "scf_property_create() failed: %s",
199 scf_strerror(scf_error()));
202 value
= scf_value_create(handles
->main
);
204 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
205 scf_strerror(scf_error()));
209 if (scf_pg_get_property(handles
->debug_pg
, name
, scf_prop
) < 0) {
210 /* this is OK: the property is just undefined */
215 if (scf_property_get_value(scf_prop
, value
) < 0) {
216 /* It is still OK when a property doesn't have any value */
220 if (scf_value_get_integer(value
, &i64
) != 0) {
221 idmapdlog(LOG_ERR
, "Can not retrieve %s/%s: %s",
222 DEBUG_PG
, name
, scf_strerror(scf_error()));
227 scf_value_destroy(value
);
228 scf_property_destroy(scf_prop
);
234 get_val_bool(idmap_cfg_handles_t
*handles
, const char *name
,
235 boolean_t
*val
, boolean_t default_val
)
239 scf_property_t
*scf_prop
;
244 scf_prop
= scf_property_create(handles
->main
);
245 if (scf_prop
== NULL
) {
246 idmapdlog(LOG_ERR
, "scf_property_create() failed: %s",
247 scf_strerror(scf_error()));
250 value
= scf_value_create(handles
->main
);
252 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
253 scf_strerror(scf_error()));
254 scf_property_destroy(scf_prop
);
258 /* It is OK if the property is undefined */
259 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) < 0)
263 /* It is still OK when a property doesn't have any value */
264 if (scf_property_get_value(scf_prop
, value
) < 0)
268 rc
= scf_value_get_boolean(value
, &b
);
274 scf_value_destroy(value
);
275 scf_property_destroy(scf_prop
);
281 get_val_int(idmap_cfg_handles_t
*handles
, const char *name
,
282 void *val
, scf_type_t type
)
286 scf_property_t
*scf_prop
;
291 *(uint64_t *)val
= 0;
293 case SCF_TYPE_INTEGER
:
297 idmapdlog(LOG_ERR
, "Invalid scf integer type (%d)",
302 scf_prop
= scf_property_create(handles
->main
);
303 if (scf_prop
== NULL
) {
304 idmapdlog(LOG_ERR
, "scf_property_create() failed: %s",
305 scf_strerror(scf_error()));
308 value
= scf_value_create(handles
->main
);
310 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
311 scf_strerror(scf_error()));
312 scf_property_destroy(scf_prop
);
316 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) < 0)
317 /* this is OK: the property is just undefined */
321 if (scf_property_get_value(scf_prop
, value
) < 0)
322 /* It is still OK when a property doesn't have any value */
327 rc
= scf_value_get_count(value
, val
);
329 case SCF_TYPE_INTEGER
:
330 rc
= scf_value_get_integer(value
, val
);
333 abort(); /* tested above */
338 idmapdlog(LOG_ERR
, "Can not retrieve config/%s: %s",
339 name
, scf_strerror(scf_error()));
343 scf_value_destroy(value
);
344 scf_property_destroy(scf_prop
);
350 scf_value2string(const char *name
, scf_value_t
*value
)
352 static size_t max_val
= 0;
355 max_val
= scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH
);
357 char buf
[max_val
+ 1];
358 if (scf_value_get_astring(value
, buf
, max_val
+ 1) < 0) {
359 idmapdlog(LOG_ERR
, "Can not retrieve config/%s: %s",
360 name
, scf_strerror(scf_error()));
364 char *s
= strdup(buf
);
366 idmapdlog(LOG_ERR
, "Out of memory");
372 get_val_ds(idmap_cfg_handles_t
*handles
, const char *name
, int defport
,
376 struct addrinfo hints
;
378 ad_disc_ds_t
*servers
= NULL
;
379 scf_property_t
*scf_prop
;
382 char *host
, *portstr
;
390 scf_prop
= scf_property_create(handles
->main
);
391 if (scf_prop
== NULL
) {
392 idmapdlog(LOG_ERR
, "scf_property_create() failed: %s",
393 scf_strerror(scf_error()));
397 value
= scf_value_create(handles
->main
);
399 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
400 scf_strerror(scf_error()));
401 scf_property_destroy(scf_prop
);
405 iter
= scf_iter_create(handles
->main
);
407 idmapdlog(LOG_ERR
, "scf_iter_create() failed: %s",
408 scf_strerror(scf_error()));
409 scf_value_destroy(value
);
410 scf_property_destroy(scf_prop
);
414 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) < 0) {
415 /* this is OK: the property is just undefined */
420 if (scf_iter_property_values(iter
, scf_prop
) < 0) {
422 "scf_iter_property_values(%s) failed: %s",
423 name
, scf_strerror(scf_error()));
427 /* Workaround scf bugs -- can't reset an iteration */
429 while (scf_iter_next_value(iter
, value
) > 0)
438 scf_value_destroy(value
);
439 scf_iter_destroy(iter
);
440 scf_property_destroy(scf_prop
);
444 if ((servers
= calloc(count
+ 1, sizeof (*servers
))) == NULL
) {
445 idmapdlog(LOG_ERR
, "Out of memory");
449 (void) memset(&hints
, 0, sizeof (hints
));
450 hints
.ai_protocol
= IPPROTO_TCP
;
451 hints
.ai_socktype
= SOCK_STREAM
;
455 while (i
< count
&& scf_iter_next_value(iter
, value
) > 0) {
460 servers
[i
].priority
= 0;
461 servers
[i
].weight
= 100;
462 servers
[i
].port
= defport
;
463 if ((host
= scf_value2string(name
, value
)) == NULL
)
465 if ((portstr
= strchr(host
, ':')) != NULL
) {
467 servers
[i
].port
= strtol(portstr
,
469 if (servers
[i
].port
== 0)
470 servers
[i
].port
= defport
;
474 * Ignore this server if the hostname is too long
475 * or empty (continue without i++)
479 if (DBG(CONFIG
, 1)) {
480 idmapdlog(LOG_INFO
, "%s host=\"\"", name
);
484 if (len
>= sizeof (servers
->host
)) {
485 idmapdlog(LOG_ERR
, "Host name too long: %s", host
);
486 idmapdlog(LOG_ERR
, "ignoring %s value", name
);
491 * Get the host address too. If we can't, then
492 * log an error and skip this host.
494 (void) snprintf(port_str
, sizeof (port_str
),
495 "%d", servers
[i
].port
);
497 err
= getaddrinfo(host
, port_str
, &hints
, &ai
);
499 idmapdlog(LOG_ERR
, "No address for host: %s (%s)",
500 host
, gai_strerror(err
));
501 idmapdlog(LOG_ERR
, "ignoring %s value", name
);
505 (void) strlcpy(servers
[i
].host
, host
,
506 sizeof (servers
->host
));
507 (void) memcpy(&servers
[i
].addr
, ai
->ai_addr
, ai
->ai_addrlen
);
510 /* Added a DS to the array. */
516 if (DBG(CONFIG
, 1)) {
517 idmapdlog(LOG_INFO
, "%s is empty", name
);
527 scf_value_destroy(value
);
528 scf_iter_destroy(iter
);
529 scf_property_destroy(scf_prop
);
541 get_val_astring(idmap_cfg_handles_t
*handles
, const char *name
, char **val
)
545 scf_property_t
*scf_prop
;
548 scf_prop
= scf_property_create(handles
->main
);
549 if (scf_prop
== NULL
) {
550 idmapdlog(LOG_ERR
, "scf_property_create() failed: %s",
551 scf_strerror(scf_error()));
554 value
= scf_value_create(handles
->main
);
556 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
557 scf_strerror(scf_error()));
558 scf_property_destroy(scf_prop
);
564 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) < 0)
565 /* this is OK: the property is just undefined */
568 if (scf_property_get_value(scf_prop
, value
) < 0) {
570 "scf_property_get_value(%s) failed: %s",
571 name
, scf_strerror(scf_error()));
576 *val
= scf_value2string(name
, value
);
581 scf_value_destroy(value
);
582 scf_property_destroy(scf_prop
);
595 idmap_cfg_handles_t
*handles
,
596 scf_propertygroup_t
*pg
,
601 scf_transaction_t
*tx
= NULL
;
602 scf_transaction_entry_t
*ent
= NULL
;
604 if ((tx
= scf_transaction_create(handles
->main
)) == NULL
) {
606 "scf_transaction_create() failed: %s",
607 scf_strerror(scf_error()));
610 if ((ent
= scf_entry_create(handles
->main
)) == NULL
) {
612 "scf_entry_create() failed: %s",
613 scf_strerror(scf_error()));
618 if (scf_pg_update(pg
) == -1) {
620 "scf_pg_update(%s) failed: %s",
621 name
, scf_strerror(scf_error()));
624 if (scf_transaction_start(tx
, pg
) != 0) {
626 "scf_transaction_start(%s) failed: %s",
627 name
, scf_strerror(scf_error()));
631 if (scf_transaction_property_delete(tx
, ent
, name
) != 0) {
632 /* Don't complain if it already doesn't exist. */
633 if (scf_error() != SCF_ERROR_NOT_FOUND
) {
635 "scf_transaction_property_delete() failed:"
637 scf_strerror(scf_error()));
642 ret
= scf_transaction_commit(tx
);
645 scf_transaction_reset(tx
);
650 "scf_transaction_commit(%s) failed: %s",
651 name
, scf_strerror(scf_error()));
659 scf_entry_destroy(ent
);
661 scf_transaction_destroy(tx
);
668 idmap_cfg_handles_t
*handles
,
669 scf_propertygroup_t
*pg
,
675 scf_property_t
*prop
= NULL
;
676 scf_transaction_t
*tx
= NULL
;
677 scf_transaction_entry_t
*ent
= NULL
;
679 if ((prop
= scf_property_create(handles
->main
)) == NULL
||
680 (tx
= scf_transaction_create(handles
->main
)) == NULL
||
681 (ent
= scf_entry_create(handles
->main
)) == NULL
) {
682 idmapdlog(LOG_ERR
, "Unable to set property %s",
683 name
, scf_strerror(scf_error()));
687 for (i
= 0; i
< MAX_TRIES
; i
++) {
690 if (scf_pg_update(pg
) == -1) {
692 "scf_pg_update() failed: %s",
693 scf_strerror(scf_error()));
697 if (scf_transaction_start(tx
, pg
) == -1) {
699 "scf_transaction_start(%s) failed: %s",
700 name
, scf_strerror(scf_error()));
704 ret
= scf_pg_get_property(pg
, name
, prop
);
705 if (ret
== SCF_SUCCESS
) {
706 if (scf_transaction_property_change_type(tx
, ent
, name
,
707 scf_value_type(value
)) < 0) {
709 "scf_transaction_property_change_type(%s)"
711 name
, scf_strerror(scf_error()));
714 } else if (scf_error() == SCF_ERROR_NOT_FOUND
) {
715 if (scf_transaction_property_new(tx
, ent
, name
,
716 scf_value_type(value
)) < 0) {
718 "scf_transaction_property_new() failed: %s",
719 scf_strerror(scf_error()));
724 "scf_pg_get_property(%s) failed: %s",
725 name
, scf_strerror(scf_error()));
729 if (scf_entry_add_value(ent
, value
) == -1) {
731 "scf_entry_add_value() failed: %s",
732 scf_strerror(scf_error()));
736 ret
= scf_transaction_commit(tx
);
739 * Property group set in scf_transaction_start()
740 * is not the most recent. Update pg, reset tx and
743 idmapdlog(LOG_WARNING
,
744 "scf_transaction_commit(%s) failed: %s",
745 name
, scf_strerror(scf_error()));
746 scf_transaction_reset(tx
);
751 "scf_transaction_commit(%s) failed: %s",
752 name
, scf_strerror(scf_error()));
761 scf_entry_destroy(ent
);
762 scf_transaction_destroy(tx
);
763 scf_property_destroy(prop
);
769 idmap_cfg_handles_t
*handles
,
770 scf_propertygroup_t
*pg
,
774 scf_value_t
*value
= NULL
;
777 if ((value
= scf_value_create(handles
->main
)) == NULL
) {
778 idmapdlog(LOG_ERR
, "Unable to set property %s",
779 name
, scf_strerror(scf_error()));
783 scf_value_set_integer(value
, val
);
785 rc
= set_val(handles
, pg
, name
, value
);
787 scf_value_destroy(value
);
795 idmap_cfg_handles_t
*handles
,
796 scf_propertygroup_t
*pg
,
800 scf_value_t
*value
= NULL
;
803 if ((value
= scf_value_create(handles
->main
)) == NULL
) {
804 idmapdlog(LOG_ERR
, "Unable to set property %s",
805 name
, scf_strerror(scf_error()));
809 if (scf_value_set_astring(value
, val
) == -1) {
811 "scf_value_set_astring() failed: %s",
812 scf_strerror(scf_error()));
816 rc
= set_val(handles
, pg
, name
, value
);
819 scf_value_destroy(value
);
826 * This function updates a boolean value.
827 * If nothing has changed it returns 0 else 1
830 update_bool(boolean_t
*value
, boolean_t
*new, char *name
)
835 if (DBG(CONFIG
, 1)) {
836 idmapdlog(LOG_INFO
, "change %s=%s", name
,
837 *new ? "true" : "false");
845 * This function updates a uint64_t value.
846 * If nothing has changed it returns 0 else 1
849 update_uint64(uint64_t *value
, uint64_t *new, char *name
)
855 idmapdlog(LOG_INFO
, "change %s=%llu", name
, *new);
862 * This function updates a string value.
863 * If nothing has changed it returns 0 else 1
866 update_string(char **value
, char **new, char *name
)
870 if (*new == NULL
&& *value
!= NULL
)
872 else if (*new != NULL
&& *value
== NULL
)
874 else if (*new != NULL
&& *value
!= NULL
&& strcmp(*new, *value
) != 0)
880 * Note that even if unchanged we can't just return; we must free one
884 if (DBG(CONFIG
, 1) && changed
)
885 idmapdlog(LOG_INFO
, "change %s=%s", name
, CHECK_NULL(*new));
894 update_enum(int *value
, int *new, char *name
, struct enum_lookup_map
*map
)
899 if (DBG(CONFIG
, 1)) {
900 idmapdlog(LOG_INFO
, "change %s=%s", name
,
901 enum_lookup(*new, map
));
910 * This function updates a directory service structure.
911 * If nothing has changed it returns 0 else 1
914 update_dirs(ad_disc_ds_t
**value
, ad_disc_ds_t
**new, char *name
)
921 if (*value
!= NULL
&& *new != NULL
&&
922 ad_disc_compare_ds(*value
, *new) == 0) {
934 if (*value
== NULL
) {
935 /* We're unsetting this DS property */
937 idmapdlog(LOG_INFO
, "change %s=<none>", name
);
941 if (DBG(CONFIG
, 1)) {
942 /* List all the new DSs */
945 for (ds
= *value
; ds
->host
[0] != '\0'; ds
++) {
946 if (ad_disc_getnameinfo(buf
, sizeof (buf
), &ds
->addr
))
947 (void) strlcpy(buf
, "?", sizeof (buf
));
948 idmapdlog(LOG_INFO
, "change %s=%s addr=%s port=%d",
949 name
, ds
->host
, buf
, ds
->port
);
956 * This function updates a trusted domains structure.
957 * If nothing has changed it returns 0 else 1
960 update_trusted_domains(ad_disc_trusteddomains_t
**value
,
961 ad_disc_trusteddomains_t
**new, char *name
)
969 if (*value
!= NULL
&& *new != NULL
&&
970 ad_disc_compare_trusteddomains(*value
, *new) == 0) {
982 if (*value
== NULL
) {
983 /* We're unsetting this DS property */
985 idmapdlog(LOG_INFO
, "change %s=<none>", name
);
989 if (DBG(CONFIG
, 1)) {
990 /* List all the new domains */
991 for (i
= 0; (*value
)[i
].domain
[0] != '\0'; i
++) {
992 idmapdlog(LOG_INFO
, "change %s=%s direction=%s", name
,
994 enum_lookup((*value
)[i
].direction
, trust_dir_map
));
1002 * This function updates a domains in a forest structure.
1003 * If nothing has changed it returns 0 else 1
1006 update_domains_in_forest(ad_disc_domainsinforest_t
**value
,
1007 ad_disc_domainsinforest_t
**new, char *name
)
1015 if (*value
!= NULL
&& *new != NULL
&&
1016 ad_disc_compare_domainsinforest(*value
, *new) == 0) {
1028 if (*value
== NULL
) {
1029 /* We're unsetting this DS property */
1031 idmapdlog(LOG_INFO
, "change %s=<none>", name
);
1035 if (DBG(CONFIG
, 1)) {
1036 /* List all the new domains */
1037 for (i
= 0; (*value
)[i
].domain
[0] != '\0'; i
++) {
1038 idmapdlog(LOG_INFO
, "change %s=%s", name
,
1039 (*value
)[i
].domain
);
1047 free_trusted_forests(idmap_trustedforest_t
**value
, int *num_values
)
1051 for (i
= 0; i
< *num_values
; i
++) {
1052 free((*value
)[i
].forest_name
);
1053 free((*value
)[i
].global_catalog
);
1054 free((*value
)[i
].domains_in_forest
);
1063 compare_trusteddomainsinforest(ad_disc_domainsinforest_t
*df1
,
1064 ad_disc_domainsinforest_t
*df2
)
1071 for (i
= 0; df1
[i
].domain
[0] != '\0'; i
++)
1075 for (j
= 0; df2
[j
].domain
[0] != '\0'; j
++)
1079 if (num_df1
!= num_df2
)
1082 for (i
= 0; df1
[i
].domain
[0] != '\0'; i
++) {
1083 if (df1
[i
].trusted
) {
1085 for (j
= 0; df2
[j
].domain
[0] != '\0'; j
++) {
1086 if (df2
[j
].trusted
&&
1087 domain_eq(df1
[i
].domain
, df2
[j
].domain
) &&
1088 strcmp(df1
[i
].sid
, df2
[j
].sid
) == 0) {
1103 * This function updates trusted forest structure.
1104 * If nothing has changed it returns 0 else 1
1107 update_trusted_forest(idmap_trustedforest_t
**value
, int *num_value
,
1108 idmap_trustedforest_t
**new, int *num_new
, char *name
)
1117 if (*value
!= NULL
&& *new != NULL
) {
1118 if (*num_value
!= *num_new
)
1120 for (i
= 0; i
< *num_value
; i
++) {
1122 for (j
= 0; j
< *num_new
; j
++) {
1123 if (strcmp((*value
)[i
].forest_name
,
1124 (*new)[j
].forest_name
) == 0 &&
1126 (*value
)[i
].global_catalog
,
1127 (*new)[j
].global_catalog
) == 0 &&
1128 compare_trusteddomainsinforest(
1129 (*value
)[i
].domains_in_forest
,
1130 (*new)[j
].domains_in_forest
) == 0) {
1138 free_trusted_forests(new, num_new
);
1143 free_trusted_forests(value
, num_value
);
1145 *num_value
= *num_new
;
1149 if (*value
== NULL
) {
1150 /* We're unsetting this DS property */
1152 idmapdlog(LOG_INFO
, "change %s=<none>", name
);
1156 if (DBG(CONFIG
, 1)) {
1157 /* List all the trusted forests */
1158 for (i
= 0; i
< *num_value
; i
++) {
1159 idmap_trustedforest_t
*f
= &(*value
)[i
];
1161 f
->domains_in_forest
[j
].domain
[0] != '\0';
1163 /* List trusted Domains in the forest. */
1164 if (f
->domains_in_forest
[j
].trusted
)
1166 "change %s=%s domain=%s",
1167 name
, f
->forest_name
,
1168 f
->domains_in_forest
[j
].domain
);
1170 /* List the hosts */
1172 f
->global_catalog
[j
].host
[0] != '\0';
1175 "change %s=%s host=%s port=%d",
1176 name
, f
->forest_name
,
1177 f
->global_catalog
[j
].host
,
1178 f
->global_catalog
[j
].port
);
1186 enum_lookup(int value
, struct enum_lookup_map
*map
)
1188 for (; map
->string
!= NULL
; map
++) {
1189 if (value
== map
->value
) {
1190 return (map
->string
);
1193 return ("(invalid)");
1197 * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the
1200 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON.
1204 pfroute_event_is_interesting(int rt_sock
)
1207 int64_t msg
[2048 / 8];
1208 struct rt_msghdr
*rtm
;
1209 boolean_t is_interesting
= B_FALSE
;
1212 if ((nbytes
= read(rt_sock
, msg
, sizeof (msg
))) <= 0)
1214 rtm
= (struct rt_msghdr
*)msg
;
1215 if (rtm
->rtm_version
!= RTM_VERSION
)
1217 if (nbytes
< rtm
->rtm_msglen
)
1219 switch (rtm
->rtm_type
) {
1223 is_interesting
= B_TRUE
;
1229 return (is_interesting
);
1233 * Wait for an event, and report what kind of event occurred.
1235 * Note that there are cases where we are awoken but don't care about
1236 * the lower-level event. We can't just loop here because we can't
1237 * readily calculate how long to sleep the next time. We return
1238 * EVENT_NOTHING and let the caller loop.
1242 wait_for_event(struct timespec
*timeoutp
)
1246 (void) memset(&pe
, 0, sizeof (pe
));
1247 if (port_get(idmapd_ev_port
, &pe
, timeoutp
) != 0) {
1250 return (EVENT_NOTHING
);
1253 return (EVENT_TIMEOUT
);
1255 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */
1256 idmapdlog(LOG_ERR
, "Event port failed: %s",
1264 switch (pe
.portev_source
) {
1267 * This isn't documented, but seems to be what you get if
1268 * the timeout is zero seconds and there are no events
1271 return (EVENT_TIMEOUT
);
1273 case PORT_SOURCE_USER
:
1274 switch (pe
.portev_events
) {
1276 return (EVENT_REFRESH
);
1277 case POKE_AUTO_DISCOVERY
:
1278 return (EVENT_POKED
);
1279 case KICK_AUTO_DISCOVERY
:
1280 return (EVENT_KICKED
);
1282 return (EVENT_NOTHING
);
1284 case PORT_SOURCE_FD
:
1285 if (pe
.portev_object
== rt_sock
) {
1287 * PF_ROUTE socket read event:
1291 if (port_associate(idmapd_ev_port
, PORT_SOURCE_FD
,
1292 rt_sock
, POLLIN
, NULL
) != 0) {
1293 idmapdlog(LOG_ERR
, "Failed to re-associate the "
1294 "routing socket with the event port: %s",
1299 * The network configuration may still be in flux.
1300 * No matter, the resolver will re-transmit and
1301 * timeout if need be.
1303 if (pfroute_event_is_interesting(rt_sock
)) {
1304 if (DBG(CONFIG
, 1)) {
1305 idmapdlog(LOG_DEBUG
,
1306 "Interesting routing event");
1308 return (EVENT_ROUTING
);
1310 if (DBG(CONFIG
, 2)) {
1311 idmapdlog(LOG_DEBUG
,
1312 "Boring routing event");
1314 return (EVENT_NOTHING
);
1317 /* Event on an FD other than the routing FD? Ignore it. */
1321 return (EVENT_NOTHING
);
1325 idmap_cfg_update_thread(void *arg
)
1327 NOTE(ARGUNUSED(arg
))
1328 idmap_pg_config_t
*pgcfg
= &_idmapdstate
.cfg
->pgcfg
;
1329 const ad_disc_t ad_ctx
= _idmapdstate
.cfg
->handles
.ad_ctx
;
1330 int flags
= CFG_DISCOVER
;
1333 struct timespec timeout
;
1334 struct timespec
*timeoutp
;
1338 (void) ad_disc_SubnetChanged(ad_ctx
);
1340 rc
= idmap_cfg_load(_idmapdstate
.cfg
, flags
);
1342 idmapdlog(LOG_ERR
, "Fatal errors while reading "
1345 } else if (rc
== -1) {
1346 idmapdlog(LOG_WARNING
,
1347 "Errors re-loading configuration may cause AD "
1352 * Wait for an interesting event. Note that we might get
1353 * boring events between interesting events. If so, we loop.
1355 flags
= CFG_DISCOVER
;
1358 * If we don't know our domain name, don't bother
1359 * with rediscovery until the next config change.
1360 * Avoids hourly noise in workgroup mode.
1362 if (pgcfg
->domain_name
== NULL
)
1365 ttl
= ad_disc_get_TTL(ad_ctx
);
1369 max_ttl
= (int)pgcfg
->rediscovery_interval
;
1372 if (ttl
< MIN_REDISCOVERY_INTERVAL
)
1373 ttl
= MIN_REDISCOVERY_INTERVAL
;
1374 timeout
.tv_sec
= ttl
;
1375 timeout
.tv_nsec
= 0;
1376 timeoutp
= &timeout
;
1380 idmapdlog(LOG_DEBUG
,
1381 "_cfg_update_thread waiting");
1383 switch (wait_for_event(timeoutp
)) {
1386 idmapdlog(LOG_DEBUG
, "Boring event.");
1390 idmapdlog(LOG_INFO
, "SMF refresh");
1392 * Forget any DC we had previously.
1394 flags
|= CFG_FORGET_DC
;
1397 * Blow away the ccache, we might have
1398 * re-joined the domain or joined a new one
1400 (void) unlink(IDMAP_CACHEDIR
"/ccache");
1404 idmapdlog(LOG_DEBUG
, "poked");
1408 idmapdlog(LOG_DEBUG
, "kicked");
1409 flags
|= CFG_FORGET_DC
;
1413 idmapdlog(LOG_DEBUG
, "TTL expired");
1416 /* Already logged to DEBUG */
1419 /* An interesting event! */
1424 * Lint isn't happy with the concept of a function declared to
1425 * return something, that doesn't return. Of course, merely adding
1426 * the return isn't enough, because it's never reached...
1433 idmap_cfg_start_updates(void)
1435 if ((idmapd_ev_port
= port_create()) < 0) {
1436 idmapdlog(LOG_ERR
, "Failed to create event port: %s",
1441 if ((rt_sock
= socket(PF_ROUTE
, SOCK_RAW
, 0)) < 0) {
1442 idmapdlog(LOG_ERR
, "Failed to open routing socket: %s",
1444 (void) close(idmapd_ev_port
);
1448 if (fcntl(rt_sock
, F_SETFL
, O_NDELAY
|O_NONBLOCK
) < 0) {
1449 idmapdlog(LOG_ERR
, "Failed to set routing socket flags: %s",
1451 (void) close(rt_sock
);
1452 (void) close(idmapd_ev_port
);
1456 if (port_associate(idmapd_ev_port
, PORT_SOURCE_FD
,
1457 rt_sock
, POLLIN
, NULL
) != 0) {
1458 idmapdlog(LOG_ERR
, "Failed to associate the routing "
1459 "socket with the event port: %s", strerror(errno
));
1460 (void) close(rt_sock
);
1461 (void) close(idmapd_ev_port
);
1465 if ((errno
= pthread_create(&update_thread_handle
, NULL
,
1466 idmap_cfg_update_thread
, NULL
)) != 0) {
1467 idmapdlog(LOG_ERR
, "Failed to start update thread: %s",
1469 (void) port_dissociate(idmapd_ev_port
, PORT_SOURCE_FD
, rt_sock
);
1470 (void) close(rt_sock
);
1471 (void) close(idmapd_ev_port
);
1479 * Reject attribute names with invalid characters.
1483 valid_ldap_attr(const char *attr
) {
1484 for (; *attr
; attr
++) {
1485 if (!isalnum(*attr
) && *attr
!= '-' &&
1486 *attr
!= '_' && *attr
!= '.' && *attr
!= ';')
1495 idmap_cfg_handles_t
*handles
,
1496 enum idmapd_debug item
,
1501 if (item
< 0 || item
> IDMAPD_DEBUG_MAX
)
1504 val
= get_debug(handles
, name
);
1506 if (val
!= _idmapdstate
.debug
[item
])
1507 idmapdlog(LOG_DEBUG
, "%s/%s = %d", DEBUG_PG
, name
, val
);
1509 _idmapdstate
.debug
[item
] = val
;
1514 check_smf_debug_mode(idmap_cfg_handles_t
*handles
)
1516 idmapd_set_debug(handles
, IDMAPD_DEBUG_ALL
, "all");
1517 idmapd_set_debug(handles
, IDMAPD_DEBUG_CONFIG
, "config");
1518 idmapd_set_debug(handles
, IDMAPD_DEBUG_MAPPING
, "mapping");
1519 idmapd_set_debug(handles
, IDMAPD_DEBUG_DISC
, "discovery");
1520 idmapd_set_debug(handles
, IDMAPD_DEBUG_DNS
, "dns");
1521 idmapd_set_debug(handles
, IDMAPD_DEBUG_LDAP
, "ldap");
1523 adutils_set_debug(AD_DEBUG_ALL
, _idmapdstate
.debug
[IDMAPD_DEBUG_ALL
]);
1524 adutils_set_debug(AD_DEBUG_DISC
, _idmapdstate
.debug
[IDMAPD_DEBUG_DISC
]);
1525 adutils_set_debug(AD_DEBUG_DNS
, _idmapdstate
.debug
[IDMAPD_DEBUG_DNS
]);
1526 adutils_set_debug(AD_DEBUG_LDAP
, _idmapdstate
.debug
[IDMAPD_DEBUG_LDAP
]);
1530 * This is the half of idmap_cfg_load() that loads property values from
1531 * SMF (using the config/ property group of the idmap FMRI).
1533 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
1534 * -3 -> hard smf config failures
1538 idmap_cfg_load_smf(idmap_cfg_handles_t
*handles
, idmap_pg_config_t
*pgcfg
,
1546 if (scf_pg_update(handles
->config_pg
) < 0) {
1547 idmapdlog(LOG_ERR
, "scf_pg_update() failed: %s",
1548 scf_strerror(scf_error()));
1552 if (scf_pg_update(handles
->debug_pg
) < 0) {
1553 idmapdlog(LOG_ERR
, "scf_pg_update() failed: %s",
1554 scf_strerror(scf_error()));
1558 check_smf_debug_mode(handles
);
1560 rc
= get_val_bool(handles
, "unresolvable_sid_mapping",
1561 &pgcfg
->eph_map_unres_sids
, B_TRUE
);
1565 rc
= get_val_bool(handles
, "use_ads",
1566 &pgcfg
->use_ads
, B_TRUE
);
1570 rc
= get_val_bool(handles
, "use_lsa",
1571 &pgcfg
->use_lsa
, B_TRUE
);
1575 rc
= get_val_bool(handles
, "disable_cross_forest_trusts",
1576 &pgcfg
->disable_cross_forest_trusts
, B_TRUE
);
1580 rc
= get_val_astring(handles
, "directory_based_mapping", &s
);
1583 else if (s
== NULL
|| strcasecmp(s
, "none") == 0)
1584 pgcfg
->directory_based_mapping
= DIRECTORY_MAPPING_NONE
;
1585 else if (strcasecmp(s
, "name") == 0)
1586 pgcfg
->directory_based_mapping
= DIRECTORY_MAPPING_NAME
;
1587 else if (strcasecmp(s
, "idmu") == 0)
1588 pgcfg
->directory_based_mapping
= DIRECTORY_MAPPING_IDMU
;
1590 pgcfg
->directory_based_mapping
= DIRECTORY_MAPPING_NONE
;
1592 "config/directory_based_mapping: invalid value \"%s\" ignored",
1598 rc
= get_val_int(handles
, "list_size_limit",
1599 &pgcfg
->list_size_limit
, SCF_TYPE_COUNT
);
1603 rc
= get_val_int(handles
, "id_cache_timeout",
1604 &pgcfg
->id_cache_timeout
, SCF_TYPE_COUNT
);
1607 if (pgcfg
->id_cache_timeout
== 0)
1608 pgcfg
->id_cache_timeout
= ID_CACHE_TMO_DEFAULT
;
1610 rc
= get_val_int(handles
, "name_cache_timeout",
1611 &pgcfg
->name_cache_timeout
, SCF_TYPE_COUNT
);
1614 if (pgcfg
->name_cache_timeout
== 0)
1615 pgcfg
->name_cache_timeout
= NAME_CACHE_TMO_DEFAULT
;
1617 rc
= get_val_int(handles
, "rediscovery_interval",
1618 &pgcfg
->rediscovery_interval
, SCF_TYPE_COUNT
);
1621 if (pgcfg
->rediscovery_interval
== 0)
1622 pgcfg
->rediscovery_interval
= REDISCOVERY_INTERVAL_DEFAULT
;
1624 rc
= get_val_astring(handles
, "domain_name",
1625 &pgcfg
->domain_name
);
1629 if (pgcfg
->domain_name
!= NULL
&&
1630 pgcfg
->domain_name
[0] == '\0') {
1631 free(pgcfg
->domain_name
);
1632 pgcfg
->domain_name
= NULL
;
1634 (void) ad_disc_set_DomainName(handles
->ad_ctx
,
1635 pgcfg
->domain_name
);
1636 pgcfg
->domain_name_auto_disc
= B_FALSE
;
1639 rc
= get_val_astring(handles
, "default_domain",
1640 &pgcfg
->default_domain
);
1643 * SCF failures fetching config/default_domain we treat
1644 * as fatal as they may leave ID mapping rules that
1645 * match unqualified winnames flapping in the wind.
1650 if (pgcfg
->default_domain
== NULL
&& pgcfg
->domain_name
!= NULL
) {
1651 pgcfg
->default_domain
= strdup(pgcfg
->domain_name
);
1654 rc
= get_val_astring(handles
, "domain_guid", &s
);
1657 } else if (s
== NULL
|| s
[0] == '\0') {
1663 if (uuid_parse(s
, u
) != 0) {
1665 "config/domain_guid: invalid value \"%s\" ignored", s
);
1669 pgcfg
->domain_guid
= s
;
1670 pgcfg
->domain_guid_auto_disc
= B_FALSE
;
1671 (void) ad_disc_set_DomainGUID(handles
->ad_ctx
, u
);
1675 rc
= get_val_astring(handles
, "machine_uuid", &pgcfg
->machine_uuid
);
1678 if (pgcfg
->machine_uuid
== NULL
) {
1679 /* If machine_uuid not configured, generate one */
1680 if (generate_machine_uuid(&pgcfg
->machine_uuid
) < 0)
1682 rc
= set_val_astring(handles
, handles
->config_pg
,
1683 "machine_uuid", pgcfg
->machine_uuid
);
1688 rc
= get_val_astring(handles
, "machine_sid", &pgcfg
->machine_sid
);
1691 if (pgcfg
->machine_sid
== NULL
) {
1693 * If machine_sid not configured, generate one
1694 * from the machine UUID.
1696 if (generate_machine_sid(&pgcfg
->machine_sid
,
1697 pgcfg
->machine_uuid
) < 0)
1699 rc
= set_val_astring(handles
, handles
->config_pg
,
1700 "machine_sid", pgcfg
->machine_sid
);
1705 rc
= get_val_ds(handles
, "domain_controller", 389,
1706 &pgcfg
->domain_controller
);
1710 (void) ad_disc_set_DomainController(handles
->ad_ctx
,
1711 pgcfg
->domain_controller
);
1712 pgcfg
->domain_controller_auto_disc
= B_FALSE
;
1715 rc
= get_val_ds(handles
, "preferred_dc", 389,
1716 &pgcfg
->preferred_dc
);
1720 (void) ad_disc_set_PreferredDC(handles
->ad_ctx
,
1721 pgcfg
->preferred_dc
);
1722 pgcfg
->preferred_dc_auto_disc
= B_FALSE
;
1725 rc
= get_val_astring(handles
, "forest_name", &pgcfg
->forest_name
);
1729 (void) ad_disc_set_ForestName(handles
->ad_ctx
,
1730 pgcfg
->forest_name
);
1731 pgcfg
->forest_name_auto_disc
= B_FALSE
;
1734 rc
= get_val_astring(handles
, "site_name", &pgcfg
->site_name
);
1738 (void) ad_disc_set_SiteName(handles
->ad_ctx
, pgcfg
->site_name
);
1740 rc
= get_val_ds(handles
, "global_catalog", 3268,
1741 &pgcfg
->global_catalog
);
1745 (void) ad_disc_set_GlobalCatalog(handles
->ad_ctx
,
1746 pgcfg
->global_catalog
);
1747 pgcfg
->global_catalog_auto_disc
= B_FALSE
;
1750 /* Unless we're doing directory-based name mapping, we're done. */
1751 if (pgcfg
->directory_based_mapping
!= DIRECTORY_MAPPING_NAME
)
1754 rc
= get_val_astring(handles
, "ad_unixuser_attr",
1755 &pgcfg
->ad_unixuser_attr
);
1758 if (pgcfg
->ad_unixuser_attr
!= NULL
&&
1759 !valid_ldap_attr(pgcfg
->ad_unixuser_attr
)) {
1760 idmapdlog(LOG_ERR
, "config/ad_unixuser_attr=%s is not a "
1761 "valid LDAP attribute name", pgcfg
->ad_unixuser_attr
);
1765 rc
= get_val_astring(handles
, "ad_unixgroup_attr",
1766 &pgcfg
->ad_unixgroup_attr
);
1769 if (pgcfg
->ad_unixgroup_attr
!= NULL
&&
1770 !valid_ldap_attr(pgcfg
->ad_unixgroup_attr
)) {
1771 idmapdlog(LOG_ERR
, "config/ad_unixgroup_attr=%s is not a "
1772 "valid LDAP attribute name", pgcfg
->ad_unixgroup_attr
);
1776 rc
= get_val_astring(handles
, "nldap_winname_attr",
1777 &pgcfg
->nldap_winname_attr
);
1780 if (pgcfg
->nldap_winname_attr
!= NULL
&&
1781 !valid_ldap_attr(pgcfg
->nldap_winname_attr
)) {
1782 idmapdlog(LOG_ERR
, "config/nldap_winname_attr=%s is not a "
1783 "valid LDAP attribute name", pgcfg
->nldap_winname_attr
);
1786 if (pgcfg
->ad_unixuser_attr
== NULL
&&
1787 pgcfg
->ad_unixgroup_attr
== NULL
&&
1788 pgcfg
->nldap_winname_attr
== NULL
) {
1790 "If config/directory_based_mapping property is set to "
1791 "\"name\" then at least one of the following name mapping "
1792 "attributes must be specified. (config/ad_unixuser_attr OR "
1793 "config/ad_unixgroup_attr OR config/nldap_winname_attr)");
1802 log_if_unable(const void *val
, const char *what
)
1805 idmapdlog(LOG_DEBUG
, "unable to discover %s", what
);
1811 discover_trusted_domains(idmap_pg_config_t
*pgcfg
, ad_disc_t ad_ctx
)
1813 ad_disc_t trusted_ctx
;
1816 int num_trusteddomains
;
1817 boolean_t new_forest
;
1818 char *trusteddomain
;
1819 ad_disc_ds_t
*globalcatalog
;
1820 idmap_trustedforest_t
*trustedforests
;
1821 ad_disc_domainsinforest_t
*domainsinforest
;
1823 pgcfg
->trusted_domains
=
1824 ad_disc_get_TrustedDomains(ad_ctx
, NULL
);
1826 if (pgcfg
->forest_name
!= NULL
&& pgcfg
->trusted_domains
!= NULL
&&
1827 pgcfg
->trusted_domains
[0].domain
[0] != '\0') {
1829 * We have trusted domains. We need to go through every
1830 * one and find its forest. If it is a new forest we then need
1831 * to find its Global Catalog and the domains in the forest
1833 for (i
= 0; pgcfg
->trusted_domains
[i
].domain
[0] != '\0'; i
++)
1835 num_trusteddomains
= i
;
1837 trustedforests
= calloc(num_trusteddomains
,
1838 sizeof (idmap_trustedforest_t
));
1840 for (i
= 0; pgcfg
->trusted_domains
[i
].domain
[0] != '\0'; i
++) {
1841 trusteddomain
= pgcfg
->trusted_domains
[i
].domain
;
1842 trusted_ctx
= ad_disc_init();
1843 (void) ad_disc_set_DomainName(trusted_ctx
,
1846 ad_disc_get_ForestName(trusted_ctx
, NULL
);
1847 if (forestname
== NULL
) {
1848 if (DBG(CONFIG
, 1)) {
1849 idmapdlog(LOG_DEBUG
,
1850 "unable to discover Forest Name"
1851 " for the trusted domain %s",
1854 ad_disc_fini(trusted_ctx
);
1858 if (strcasecmp(forestname
, pgcfg
->forest_name
) == 0) {
1860 * Ignore the domain as it is part of
1861 * the primary forest
1864 ad_disc_fini(trusted_ctx
);
1868 /* Is this a new forest? */
1869 new_forest
= B_TRUE
;
1870 for (k
= 0; k
< j
; k
++) {
1871 if (strcasecmp(forestname
,
1872 trustedforests
[k
].forest_name
) == 0) {
1873 new_forest
= B_FALSE
;
1875 trustedforests
[k
].domains_in_forest
;
1880 /* Mark the domain as trusted */
1882 domainsinforest
[l
].domain
[0] != '\0'; l
++) {
1883 if (domain_eq(trusteddomain
,
1884 domainsinforest
[l
].domain
)) {
1885 domainsinforest
[l
].trusted
=
1891 ad_disc_fini(trusted_ctx
);
1896 * Get the Global Catalog and the domains in
1900 ad_disc_get_GlobalCatalog(trusted_ctx
,
1901 AD_DISC_PREFER_SITE
, NULL
);
1902 if (globalcatalog
== NULL
) {
1903 if (DBG(CONFIG
, 1)) {
1904 idmapdlog(LOG_DEBUG
,
1905 "unable to discover Global Catalog"
1906 " for the trusted domain %s",
1910 ad_disc_fini(trusted_ctx
);
1914 ad_disc_get_DomainsInForest(trusted_ctx
, NULL
);
1915 if (domainsinforest
== NULL
) {
1916 if (DBG(CONFIG
, 1)) {
1917 idmapdlog(LOG_DEBUG
,
1918 "unable to discover Domains in the"
1919 " Forest for the trusted domain %s",
1922 free(globalcatalog
);
1924 ad_disc_fini(trusted_ctx
);
1928 trustedforests
[j
].forest_name
= forestname
;
1929 trustedforests
[j
].global_catalog
= globalcatalog
;
1930 trustedforests
[j
].domains_in_forest
= domainsinforest
;
1932 /* Mark the domain as trusted */
1933 for (l
= 0; domainsinforest
[l
].domain
[0] != '\0';
1935 if (domain_eq(trusteddomain
,
1936 domainsinforest
[l
].domain
)) {
1937 domainsinforest
[l
].trusted
= TRUE
;
1941 ad_disc_fini(trusted_ctx
);
1944 pgcfg
->num_trusted_forests
= j
;
1945 pgcfg
->trusted_forests
= trustedforests
;
1947 free(trustedforests
);
1953 * This is the half of idmap_cfg_load() that auto-discovers values of
1954 * discoverable properties that weren't already set via SMF properties.
1956 * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it
1957 * needs to be careful not to overwrite any properties set in SMF.
1960 idmap_cfg_discover1(idmap_cfg_handles_t
*handles
, idmap_pg_config_t
*pgcfg
)
1962 ad_disc_t ad_ctx
= handles
->ad_ctx
;
1963 FILE *status_fp
= NULL
;
1968 idmapdlog(LOG_DEBUG
, "Running domain discovery.");
1970 (void) unlink(IDMAP_CACHEDIR
"/discovery.log");
1971 status_fp
= fopen(IDMAP_CACHEDIR
"/discovery.log", "w");
1973 (void) fchmod(fileno(status_fp
), 0644);
1974 ad_disc_set_StatusFP(ad_ctx
, status_fp
);
1977 if (pgcfg
->domain_name
== NULL
) {
1978 idmapdlog(LOG_DEBUG
, "No domain name specified.");
1980 (void) fprintf(status_fp
, "(no domain name)\n");
1984 if (pgcfg
->domain_controller
== NULL
)
1985 pgcfg
->domain_controller
=
1986 ad_disc_get_DomainController(ad_ctx
,
1987 AD_DISC_PREFER_SITE
,
1988 &pgcfg
->domain_controller_auto_disc
);
1990 if (pgcfg
->domain_guid
== NULL
) {
1991 char buf
[UUID_PRINTABLE_STRING_LENGTH
];
1992 uchar_t
*u
= ad_disc_get_DomainGUID(ad_ctx
,
1993 &pgcfg
->domain_guid_auto_disc
);
1994 (void) memset(buf
, 0, sizeof (buf
));
1996 uuid_unparse(u
, buf
);
1997 pgcfg
->domain_guid
= strdup(buf
);
2001 if (pgcfg
->forest_name
== NULL
)
2002 pgcfg
->forest_name
= ad_disc_get_ForestName(ad_ctx
,
2003 &pgcfg
->forest_name_auto_disc
);
2005 if (pgcfg
->site_name
== NULL
)
2006 pgcfg
->site_name
= ad_disc_get_SiteName(ad_ctx
,
2007 &pgcfg
->site_name_auto_disc
);
2009 if (DBG(CONFIG
, 1)) {
2010 log_if_unable(pgcfg
->domain_name
, "Domain Name");
2011 log_if_unable(pgcfg
->domain_controller
,
2012 "Domain Controller");
2013 log_if_unable(pgcfg
->domain_guid
, "Domain GUID");
2014 log_if_unable(pgcfg
->forest_name
, "Forest Name");
2015 log_if_unable(pgcfg
->site_name
, "Site Name");
2020 ad_disc_set_StatusFP(ad_ctx
, NULL
);
2021 (void) fclose(status_fp
);
2026 idmapdlog(LOG_DEBUG
, "Domain discovery done.");
2029 * Log when this took more than 15 sec.
2032 if (t1
> (t0
+ 15)) {
2033 idmapdlog(LOG_NOTICE
, "Domain discovery took %d sec.",
2035 idmapdlog(LOG_NOTICE
, "Check the DNS configuration.");
2040 * This is the second part of discovery, which can take a while.
2041 * We don't want to hold up parties who just want to know what
2042 * domain controller we're using (like smbd), so this part runs
2043 * after we've updated that info in the "live" config and told
2044 * such consumers to go ahead.
2046 * This is a lot like idmap_cfg_discover(), but used LDAP queries
2047 * get the forest information from the global catalog servers.
2049 * Note: the previous update_* calls have usually nuked any
2050 * useful information from pgcfg before we get here, so we
2051 * can only use it store discovery results, not to read.
2054 idmap_cfg_discover2(idmap_cfg_handles_t
*handles
, idmap_pg_config_t
*pgcfg
)
2056 ad_disc_t ad_ctx
= handles
->ad_ctx
;
2057 FILE *status_fp
= NULL
;
2062 idmapdlog(LOG_DEBUG
, "Running forest discovery.");
2064 status_fp
= fopen(IDMAP_CACHEDIR
"/discovery.log", "a");
2066 ad_disc_set_StatusFP(ad_ctx
, status_fp
);
2068 if (pgcfg
->global_catalog
== NULL
)
2069 pgcfg
->global_catalog
=
2070 ad_disc_get_GlobalCatalog(ad_ctx
,
2071 AD_DISC_PREFER_SITE
,
2072 &pgcfg
->global_catalog_auto_disc
);
2074 if (pgcfg
->global_catalog
!= NULL
) {
2075 pgcfg
->domains_in_forest
=
2076 ad_disc_get_DomainsInForest(ad_ctx
, NULL
);
2078 if (!pgcfg
->disable_cross_forest_trusts
)
2079 discover_trusted_domains(pgcfg
, ad_ctx
);
2082 if (DBG(CONFIG
, 1)) {
2083 log_if_unable(pgcfg
->global_catalog
, "Global Catalog");
2084 log_if_unable(pgcfg
->domains_in_forest
,
2085 "Domains in the Forest");
2086 /* Empty trusted domains list is OK. */
2090 ad_disc_set_StatusFP(ad_ctx
, NULL
);
2091 (void) fclose(status_fp
);
2096 idmapdlog(LOG_DEBUG
, "Forest discovery done.");
2099 * Log when this took more than 30 sec.
2102 if (t1
> (t0
+ 30)) {
2103 idmapdlog(LOG_NOTICE
, "Forest discovery took %d sec.",
2105 idmapdlog(LOG_NOTICE
, "Check AD join status.");
2111 * idmap_cfg_load() is called at startup, and periodically via the
2112 * update thread when the auto-discovery TTLs expire, as well as part of
2113 * the refresh method, to update the current configuration. It always
2114 * reads from SMF, but you still have to refresh the service after
2115 * changing the config pg in order for the changes to take effect.
2117 * There is one flag:
2121 * If CFG_DISCOVER is set then idmap_cfg_load() calls
2122 * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property
2123 * values that weren't set in SMF.
2125 * idmap_cfg_load() will log (to LOG_NOTICE) whether the configuration
2128 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
2132 idmap_cfg_load(idmap_cfg_t
*cfg
, int flags
)
2134 const ad_disc_t ad_ctx
= cfg
->handles
.ad_ctx
;
2139 int ad_reload_required
= 0;
2140 idmap_pg_config_t new_pgcfg
, *live_pgcfg
;
2143 idmapdlog(LOG_DEBUG
, "Loading configuration.");
2145 live_pgcfg
= &cfg
->pgcfg
;
2146 (void) memset(&new_pgcfg
, 0, sizeof (new_pgcfg
));
2148 (void) pthread_mutex_lock(&cfg
->handles
.mutex
);
2150 if ((rc
= idmap_cfg_load_smf(&cfg
->handles
, &new_pgcfg
, &errors
)) < -1)
2153 if (flags
& CFG_DISCOVER
) {
2155 ad_disc_refresh(ad_ctx
);
2158 * Unless we've been asked to forget the current DC,
2159 * give preference (in order) to the preferred DC if
2160 * configured, or the current DC. These preferences
2161 * reduce undesirable DC changes.
2163 if (flags
& CFG_FORGET_DC
) {
2164 (void) ad_disc_set_PreferredDC(ad_ctx
, NULL
);
2165 } else if (new_pgcfg
.preferred_dc
!= NULL
) {
2166 (void) ad_disc_set_PreferredDC(ad_ctx
,
2167 new_pgcfg
.preferred_dc
);
2168 } else if (live_pgcfg
->domain_controller
!= NULL
) {
2169 (void) ad_disc_set_PreferredDC(ad_ctx
,
2170 live_pgcfg
->domain_controller
);
2172 (void) ad_disc_set_PreferredDC(ad_ctx
, NULL
);
2176 * We want a way to tell adspriv_getdcname_1_svc()
2177 * (and others) that discovery is running and therefore
2178 * they may want to wait a bit or return an error...
2180 (void) mutex_lock(&_idmapdstate
.addisc_lk
);
2181 _idmapdstate
.addisc_st
|= ADDISC_ST_RUNNING
;
2182 (void) mutex_unlock(&_idmapdstate
.addisc_lk
);
2184 idmap_cfg_discover1(&cfg
->handles
, &new_pgcfg
);
2187 (void) mutex_lock(&_idmapdstate
.addisc_lk
);
2188 _idmapdstate
.addisc_st
= 0;
2189 (void) cond_broadcast(&_idmapdstate
.addisc_cv
);
2190 (void) mutex_unlock(&_idmapdstate
.addisc_lk
);
2195 /* Non-discoverable props updated here */
2197 changed
+= update_uint64(&live_pgcfg
->list_size_limit
,
2198 &new_pgcfg
.list_size_limit
, "list_size_limit");
2200 changed
+= update_uint64(&live_pgcfg
->id_cache_timeout
,
2201 &new_pgcfg
.id_cache_timeout
, "id_cache_timeout");
2203 changed
+= update_uint64(&live_pgcfg
->name_cache_timeout
,
2204 &new_pgcfg
.name_cache_timeout
, "name_cache_timeout");
2206 changed
+= update_uint64(&live_pgcfg
->rediscovery_interval
,
2207 &new_pgcfg
.rediscovery_interval
, "rediscovery_interval");
2209 changed
+= update_string(&live_pgcfg
->machine_sid
,
2210 &new_pgcfg
.machine_sid
, "machine_sid");
2212 changed
+= update_bool(&live_pgcfg
->eph_map_unres_sids
,
2213 &new_pgcfg
.eph_map_unres_sids
, "unresolvable_sid_mapping");
2215 changed
+= update_bool(&live_pgcfg
->use_ads
,
2216 &new_pgcfg
.use_ads
, "use_ads");
2218 changed
+= update_bool(&live_pgcfg
->use_lsa
,
2219 &new_pgcfg
.use_lsa
, "use_lsa");
2221 changed
+= update_bool(&live_pgcfg
->disable_cross_forest_trusts
,
2222 &new_pgcfg
.disable_cross_forest_trusts
,
2223 "disable_cross_forest_trusts");
2225 changed
+= update_enum(&live_pgcfg
->directory_based_mapping
,
2226 &new_pgcfg
.directory_based_mapping
, "directory_based_mapping",
2227 directory_mapping_map
);
2229 changed
+= update_string(&live_pgcfg
->ad_unixuser_attr
,
2230 &new_pgcfg
.ad_unixuser_attr
, "ad_unixuser_attr");
2232 changed
+= update_string(&live_pgcfg
->ad_unixgroup_attr
,
2233 &new_pgcfg
.ad_unixgroup_attr
, "ad_unixgroup_attr");
2235 changed
+= update_string(&live_pgcfg
->nldap_winname_attr
,
2236 &new_pgcfg
.nldap_winname_attr
, "nldap_winname_attr");
2238 changed
+= update_string(&live_pgcfg
->default_domain
,
2239 &new_pgcfg
.default_domain
, "default_domain");
2241 changed
+= update_dirs(&live_pgcfg
->preferred_dc
,
2242 &new_pgcfg
.preferred_dc
, "preferred_dc");
2244 /* Props that can be discovered or set in SMF updated here */
2246 if (update_string(&live_pgcfg
->domain_name
,
2247 &new_pgcfg
.domain_name
, "domain_name")) {
2249 ad_reload_required
= TRUE
;
2250 idmapd_set_krb5_realm(live_pgcfg
->domain_name
);
2252 live_pgcfg
->domain_name_auto_disc
= new_pgcfg
.domain_name_auto_disc
;
2254 changed
+= update_string(&live_pgcfg
->domain_guid
,
2255 &new_pgcfg
.domain_guid
, "domain_guid");
2256 live_pgcfg
->domain_guid_auto_disc
= new_pgcfg
.domain_guid_auto_disc
;
2258 dc_changed
= update_dirs(&live_pgcfg
->domain_controller
,
2259 &new_pgcfg
.domain_controller
, "domain_controller");
2260 changed
+= dc_changed
;
2261 live_pgcfg
->domain_controller_auto_disc
=
2262 new_pgcfg
.domain_controller_auto_disc
;
2264 changed
+= update_string(&live_pgcfg
->forest_name
,
2265 &new_pgcfg
.forest_name
, "forest_name");
2266 live_pgcfg
->forest_name_auto_disc
= new_pgcfg
.forest_name_auto_disc
;
2268 changed
+= update_string(&live_pgcfg
->site_name
,
2269 &new_pgcfg
.site_name
, "site_name");
2270 live_pgcfg
->site_name_auto_disc
= new_pgcfg
.site_name_auto_disc
;
2272 if (DBG(CONFIG
, 1)) {
2274 idmapdlog(LOG_NOTICE
, "Configuration changed");
2276 idmapdlog(LOG_NOTICE
, "Configuration unchanged");
2281 if (dc_changed
!= 0) {
2282 notify_dc_changed();
2286 * Discovery2 can take a while.
2288 if (flags
& CFG_DISCOVER
) {
2289 if (live_pgcfg
->domain_name
!= NULL
&&
2290 live_pgcfg
->forest_name
!= NULL
)
2291 idmap_cfg_discover2(&cfg
->handles
, &new_pgcfg
);
2292 ad_disc_done(ad_ctx
);
2297 /* More props that can be discovered or set in SMF */
2299 changed
+= update_dirs(&live_pgcfg
->global_catalog
,
2300 &new_pgcfg
.global_catalog
, "global_catalog");
2301 live_pgcfg
->global_catalog_auto_disc
=
2302 new_pgcfg
.global_catalog_auto_disc
;
2304 /* Props that are only discovered (never in SMF) */
2306 if (update_domains_in_forest(&live_pgcfg
->domains_in_forest
,
2307 &new_pgcfg
.domains_in_forest
, "domains_in_forest")) {
2309 ad_reload_required
= TRUE
;
2312 if (update_trusted_domains(&live_pgcfg
->trusted_domains
,
2313 &new_pgcfg
.trusted_domains
, "trusted_domains")) {
2315 if (live_pgcfg
->trusted_domains
!= NULL
&&
2316 live_pgcfg
->trusted_domains
[0].domain
[0] != '\0')
2317 ad_reload_required
= TRUE
;
2320 if (update_trusted_forest(&live_pgcfg
->trusted_forests
,
2321 &live_pgcfg
->num_trusted_forests
, &new_pgcfg
.trusted_forests
,
2322 &new_pgcfg
.num_trusted_forests
, "trusted_forest")) {
2324 if (live_pgcfg
->trusted_forests
!= NULL
)
2325 ad_reload_required
= TRUE
;
2328 if (DBG(CONFIG
, 1)) {
2330 idmapdlog(LOG_NOTICE
, "Configuration changed");
2332 idmapdlog(LOG_NOTICE
, "Configuration unchanged");
2337 if (ad_reload_required
)
2340 idmap_cfg_unload(&new_pgcfg
);
2343 (void) pthread_mutex_unlock(&cfg
->handles
.mutex
);
2348 return ((errors
== 0) ? 0 : -1);
2357 idmap_cfg_handles_t
*handles
;
2359 /* First the smf repository handles: */
2360 idmap_cfg_t
*cfg
= calloc(1, sizeof (idmap_cfg_t
));
2362 idmapdlog(LOG_ERR
, "Out of memory");
2365 handles
= &cfg
->handles
;
2367 (void) pthread_mutex_init(&handles
->mutex
, NULL
);
2369 if (!(handles
->main
= scf_handle_create(SCF_VERSION
))) {
2370 idmapdlog(LOG_ERR
, "scf_handle_create() failed: %s",
2371 scf_strerror(scf_error()));
2375 if (scf_handle_bind(handles
->main
) < 0) {
2376 idmapdlog(LOG_ERR
, "scf_handle_bind() failed: %s",
2377 scf_strerror(scf_error()));
2381 if (!(handles
->service
= scf_service_create(handles
->main
)) ||
2382 !(handles
->instance
= scf_instance_create(handles
->main
)) ||
2383 !(handles
->config_pg
= scf_pg_create(handles
->main
)) ||
2384 !(handles
->debug_pg
= scf_pg_create(handles
->main
))) {
2385 idmapdlog(LOG_ERR
, "scf handle creation failed: %s",
2386 scf_strerror(scf_error()));
2390 if (scf_handle_decode_fmri(handles
->main
,
2391 FMRI_BASE
"/:properties/" CONFIG_PG
,
2393 handles
->service
, /* service */
2394 handles
->instance
, /* instance */
2395 handles
->config_pg
, /* pg */
2397 SCF_DECODE_FMRI_EXACT
) < 0) {
2398 idmapdlog(LOG_ERR
, "scf_handle_decode_fmri() failed: %s",
2399 scf_strerror(scf_error()));
2403 if (scf_service_get_pg(handles
->service
,
2404 DEBUG_PG
, handles
->debug_pg
) < 0) {
2405 idmapdlog(LOG_ERR
, "Property group \"%s\": %s",
2406 DEBUG_PG
, scf_strerror(scf_error()));
2410 check_smf_debug_mode(handles
);
2412 /* Initialize AD Auto Discovery context */
2413 handles
->ad_ctx
= ad_disc_init();
2414 if (handles
->ad_ctx
== NULL
)
2420 (void) idmap_cfg_fini(cfg
);
2425 idmap_cfg_unload(idmap_pg_config_t
*pgcfg
)
2428 if (pgcfg
->default_domain
) {
2429 free(pgcfg
->default_domain
);
2430 pgcfg
->default_domain
= NULL
;
2432 if (pgcfg
->domain_name
) {
2433 free(pgcfg
->domain_name
);
2434 pgcfg
->domain_name
= NULL
;
2436 if (pgcfg
->domain_guid
) {
2437 free(pgcfg
->domain_guid
);
2438 pgcfg
->domain_guid
= NULL
;
2440 if (pgcfg
->machine_sid
) {
2441 free(pgcfg
->machine_sid
);
2442 pgcfg
->machine_sid
= NULL
;
2444 if (pgcfg
->domain_controller
) {
2445 free(pgcfg
->domain_controller
);
2446 pgcfg
->domain_controller
= NULL
;
2448 if (pgcfg
->forest_name
) {
2449 free(pgcfg
->forest_name
);
2450 pgcfg
->forest_name
= NULL
;
2452 if (pgcfg
->site_name
) {
2453 free(pgcfg
->site_name
);
2454 pgcfg
->site_name
= NULL
;
2456 if (pgcfg
->global_catalog
) {
2457 free(pgcfg
->global_catalog
);
2458 pgcfg
->global_catalog
= NULL
;
2460 if (pgcfg
->trusted_domains
) {
2461 free(pgcfg
->trusted_domains
);
2462 pgcfg
->trusted_domains
= NULL
;
2464 if (pgcfg
->trusted_forests
)
2465 free_trusted_forests(&pgcfg
->trusted_forests
,
2466 &pgcfg
->num_trusted_forests
);
2468 if (pgcfg
->ad_unixuser_attr
) {
2469 free(pgcfg
->ad_unixuser_attr
);
2470 pgcfg
->ad_unixuser_attr
= NULL
;
2472 if (pgcfg
->ad_unixgroup_attr
) {
2473 free(pgcfg
->ad_unixgroup_attr
);
2474 pgcfg
->ad_unixgroup_attr
= NULL
;
2476 if (pgcfg
->nldap_winname_attr
) {
2477 free(pgcfg
->nldap_winname_attr
);
2478 pgcfg
->nldap_winname_attr
= NULL
;
2483 idmap_cfg_fini(idmap_cfg_t
*cfg
)
2485 idmap_cfg_handles_t
*handles
= &cfg
->handles
;
2486 idmap_cfg_unload(&cfg
->pgcfg
);
2488 (void) pthread_mutex_destroy(&handles
->mutex
);
2489 scf_pg_destroy(handles
->config_pg
);
2490 if (handles
->debug_pg
!= NULL
)
2491 scf_pg_destroy(handles
->debug_pg
);
2492 scf_instance_destroy(handles
->instance
);
2493 scf_service_destroy(handles
->service
);
2494 scf_handle_destroy(handles
->main
);
2495 if (handles
->ad_ctx
!= NULL
)
2496 ad_disc_fini(handles
->ad_ctx
);
2503 idmap_cfg_poke_updates(void)
2507 if (DBG(CONFIG
, 1)) {
2508 idmapdlog(LOG_INFO
, "idmap_cfg_poke_updates");
2511 (void) mutex_lock(&_idmapdstate
.addisc_lk
);
2512 prev_st
= _idmapdstate
.addisc_st
;
2513 _idmapdstate
.addisc_st
|= ADDISC_ST_REQUESTED
;
2514 (void) mutex_unlock(&_idmapdstate
.addisc_lk
);
2516 if (prev_st
& ADDISC_ST_REQUESTED
) {
2517 idmapdlog(LOG_DEBUG
, "already poked");
2519 idmapdlog(LOG_DEBUG
, "port send poke");
2520 (void) port_send(idmapd_ev_port
, POKE_AUTO_DISCOVERY
, NULL
);
2525 idmap_cfg_force_rediscovery(void)
2529 if (DBG(CONFIG
, 1)) {
2530 idmapdlog(LOG_INFO
, "idmap_cfg_force_rediscovery");
2533 (void) mutex_lock(&_idmapdstate
.addisc_lk
);
2534 prev_st
= _idmapdstate
.addisc_st
;
2535 _idmapdstate
.addisc_st
|= ADDISC_ST_REQUESTED
;
2536 (void) mutex_unlock(&_idmapdstate
.addisc_lk
);
2538 if (prev_st
& ADDISC_ST_REQUESTED
) {
2539 idmapdlog(LOG_DEBUG
, "already kicked");
2541 idmapdlog(LOG_DEBUG
, "port send kick");
2542 (void) port_send(idmapd_ev_port
, KICK_AUTO_DISCOVERY
, NULL
);
2548 idmap_cfg_hup_handler(int sig
)
2550 if (idmapd_ev_port
>= 0)
2551 (void) port_send(idmapd_ev_port
, RECONFIGURE
, NULL
);
2555 * Upgrade the debug flags.
2557 * We're replacing a single debug flag with a fine-grained mechanism that
2558 * is also capable of considerably more verbosity. We'll take a stab at
2559 * producing roughly the same level of output.
2563 upgrade_debug(idmap_cfg_handles_t
*handles
)
2565 boolean_t debug_present
;
2566 const char DEBUG_PROP
[] = "debug";
2569 rc
= prop_exists(handles
, DEBUG_PROP
, &debug_present
);
2578 "Upgrading old %s/%s setting to %s/* settings.",
2579 CONFIG_PG
, DEBUG_PROP
, DEBUG_PG
);
2581 rc
= set_val_integer(handles
, handles
->debug_pg
, "config", 1);
2584 rc
= set_val_integer(handles
, handles
->debug_pg
, "discovery", 1);
2588 rc
= del_val(handles
, handles
->config_pg
, DEBUG_PROP
);
2596 * Upgrade the DS mapping flags.
2598 * If the old ds_name_mapping_enabled flag is present, then
2599 * if the new directory_based_mapping value is present, then
2600 * if the two are compatible, delete the old and note it
2601 * else delete the old and warn
2603 * set the new based on the old, and note it
2608 upgrade_directory_mapping(idmap_cfg_handles_t
*handles
)
2610 boolean_t legacy_ds_name_mapping_present
;
2611 const char DS_NAME_MAPPING_ENABLED
[] = "ds_name_mapping_enabled";
2612 const char DIRECTORY_BASED_MAPPING
[] = "directory_based_mapping";
2615 rc
= prop_exists(handles
, DS_NAME_MAPPING_ENABLED
,
2616 &legacy_ds_name_mapping_present
);
2621 if (!legacy_ds_name_mapping_present
)
2624 boolean_t legacy_ds_name_mapping_enabled
;
2625 rc
= get_val_bool(handles
, DS_NAME_MAPPING_ENABLED
,
2626 &legacy_ds_name_mapping_enabled
, B_FALSE
);
2631 char *legacy_bool_string
;
2632 if (legacy_ds_name_mapping_enabled
) {
2633 legacy_mode
= "name";
2634 legacy_bool_string
= "true";
2636 legacy_mode
= "none";
2637 legacy_bool_string
= "false";
2640 char *directory_based_mapping
;
2641 rc
= get_val_astring(handles
, DIRECTORY_BASED_MAPPING
,
2642 &directory_based_mapping
);
2646 if (directory_based_mapping
== NULL
) {
2648 "Upgrading old %s=%s setting\n"
2650 DS_NAME_MAPPING_ENABLED
, legacy_bool_string
,
2651 DIRECTORY_BASED_MAPPING
, legacy_mode
);
2652 rc
= set_val_astring(handles
, handles
->config_pg
,
2653 DIRECTORY_BASED_MAPPING
, legacy_mode
);
2657 boolean_t new_name_mapping
;
2658 if (strcasecmp(directory_based_mapping
, "name") == 0)
2659 new_name_mapping
= B_TRUE
;
2661 new_name_mapping
= B_FALSE
;
2663 if (legacy_ds_name_mapping_enabled
== new_name_mapping
) {
2665 "Automatically removing old %s=%s setting\n"
2666 "in favor of %s=%s.",
2667 DS_NAME_MAPPING_ENABLED
, legacy_bool_string
,
2668 DIRECTORY_BASED_MAPPING
, directory_based_mapping
);
2670 idmapdlog(LOG_WARNING
,
2671 "Removing conflicting %s=%s setting\n"
2672 "in favor of %s=%s.",
2673 DS_NAME_MAPPING_ENABLED
, legacy_bool_string
,
2674 DIRECTORY_BASED_MAPPING
, directory_based_mapping
);
2676 free(directory_based_mapping
);
2679 rc
= del_val(handles
, handles
->config_pg
, DS_NAME_MAPPING_ENABLED
);
2687 * Do whatever is necessary to upgrade idmap's configuration before
2691 idmap_cfg_upgrade(idmap_cfg_t
*cfg
)
2695 rc
= upgrade_directory_mapping(&cfg
->handles
);
2699 rc
= upgrade_debug(&cfg
->handles
);
2707 * The LDAP code passes principal names lacking any
2708 * realm information, which causes mech_krb5 to do
2709 * awful things trying to figure out the realm.
2710 * Avoid that by making sure it has a default,
2711 * even when krb5.conf is not configured.
2714 idmapd_set_krb5_realm(char *domain
)
2716 static char realm
[MAXHOSTNAMELEN
];
2720 if (domain
== NULL
) {
2721 (void) unsetenv("KRB5_DEFAULT_REALM");
2725 /* Convert to upper case, in place. */
2726 (void) strlcpy(realm
, domain
, sizeof (realm
));
2727 olen
= ilen
= strlen(realm
);
2728 (void) u8_textprep_str(realm
, &ilen
, realm
, &olen
,
2729 U8_TEXTPREP_TOUPPER
, U8_UNICODE_LATEST
, &err
);
2731 (void) setenv("KRB5_DEFAULT_REALM", realm
, 1);