1c8e26105Sjp /* 2c8e26105Sjp * CDDL HEADER START 3c8e26105Sjp * 4c8e26105Sjp * The contents of this file are subject to the terms of the 5c8e26105Sjp * Common Development and Distribution License (the "License"). 6c8e26105Sjp * You may not use this file except in compliance with the License. 7c8e26105Sjp * 8c8e26105Sjp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9c8e26105Sjp * or http://www.opensolaris.org/os/licensing. 10c8e26105Sjp * See the License for the specific language governing permissions 11c8e26105Sjp * and limitations under the License. 12c8e26105Sjp * 13c8e26105Sjp * When distributing Covered Code, include this CDDL HEADER in each 14c8e26105Sjp * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15c8e26105Sjp * If applicable, add the following below this CDDL HEADER, with the 16c8e26105Sjp * fields enclosed by brackets "[]" replaced with your own identifying 17c8e26105Sjp * information: Portions Copyright [yyyy] [name of copyright owner] 18c8e26105Sjp * 19c8e26105Sjp * CDDL HEADER END 20c8e26105Sjp */ 21c8e26105Sjp 22c8e26105Sjp /* 23148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24*d0bed8f2SGordon Ross * Copyright 2019 Nexenta Systems, Inc. All rights reserved. 25c8e26105Sjp */ 26c8e26105Sjp 270dcc7149Snw /* 280dcc7149Snw * Active Directory Auto-Discovery. 290dcc7149Snw * 300dcc7149Snw * This [project private] API allows the caller to provide whatever 310dcc7149Snw * details it knows a priori (i.e., provided via configuration so as to 320dcc7149Snw * override auto-discovery) and in any order. Then the caller can ask 330dcc7149Snw * for any of the auto-discoverable parameters in any order. 340dcc7149Snw * 350dcc7149Snw * But there is an actual order in which discovery must be done. Given 360dcc7149Snw * the discovery mechanism implemented here, that order is: 370dcc7149Snw * 380dcc7149Snw * - the domain name joined must be discovered first 390dcc7149Snw * - then the domain controllers 400dcc7149Snw * - then the forest name and site name 410dcc7149Snw * - then the global catalog servers, and site-specific domain 420dcc7149Snw * controllers and global catalog servers. 430dcc7149Snw * 440dcc7149Snw * The API does not require it be called in the same order because there 450dcc7149Snw * may be other discovery mechanisms in the future, and exposing 460dcc7149Snw * ordering requirements of the current mechanism now can create trouble 470dcc7149Snw * down the line. Also, this makes the API easier to use now, which 480dcc7149Snw * means less work to do some day when we make this a public API. 490dcc7149Snw * 500dcc7149Snw * Domain discovery is done by res_nsearch() of the DNS SRV RR name for 510dcc7149Snw * domain controllers. As long as the joined domain appears in the DNS 520dcc7149Snw * resolver's search list then we'll find it. 530dcc7149Snw * 540dcc7149Snw * Domain controller discovery is a matter of formatting the DNS SRV RR 550dcc7149Snw * FQDN for domain controllers and doing a lookup for them. Knowledge 560dcc7149Snw * of the domain name is not fundamentally required, but we separate the 570dcc7149Snw * two processes, which in practice can lead to one more DNS lookup than 580dcc7149Snw * is strictly required. 590dcc7149Snw * 600dcc7149Snw * Forest and site name discovery require an LDAP search of the AD 610dcc7149Snw * "configuration partition" at a domain controller for the joined 620dcc7149Snw * domain. Forest and site name discovery depend on knowing the joined 630dcc7149Snw * domain name and domain controllers for that domain. 640dcc7149Snw * 650dcc7149Snw * Global catalog server discovery requires knowledge of the forest 660dcc7149Snw * name in order to format the DNS SRV RR FQDN to lookup. Site-specific 670dcc7149Snw * domain controller discovery depends on knowing the site name (and, 680dcc7149Snw * therefore, joined domain, ...). Site-specific global catalog server 690dcc7149Snw * discovery depends on knowledge of the forest and site names, which 700dcc7149Snw * depend on... 710dcc7149Snw * 720dcc7149Snw * All the work of discovering particular items is done by functions 730dcc7149Snw * named validate_<item>(). Each such function calls validate_<item>() 740dcc7149Snw * for any items that it depends on. 750dcc7149Snw * 760dcc7149Snw * This API is not thread-safe. 770dcc7149Snw */ 780dcc7149Snw 79c8e26105Sjp 80c8e26105Sjp #include <stdio.h> 81c8e26105Sjp #include <string.h> 82c8e26105Sjp #include <strings.h> 83c8e26105Sjp #include <unistd.h> 844d61c878SJulian Pullen #include <assert.h> 85c8e26105Sjp #include <stdlib.h> 86c8e26105Sjp #include <net/if.h> 87c8e26105Sjp #include <sys/types.h> 88c8e26105Sjp #include <sys/socket.h> 89c8e26105Sjp #include <sys/sockio.h> 90c8e26105Sjp #include <netinet/in.h> 91c8e26105Sjp #include <arpa/inet.h> 92c8e26105Sjp #include <arpa/nameser.h> 93c8e26105Sjp #include <resolv.h> 94c8e26105Sjp #include <netdb.h> 95c8e26105Sjp #include <ctype.h> 96c8e26105Sjp #include <errno.h> 97c8e26105Sjp #include <ldap.h> 98b3700b07SGordon Ross #include <note.h> 99c8e26105Sjp #include <sasl/sasl.h> 1004d61c878SJulian Pullen #include <sys/u8_textprep.h> 1017a8a68f5SJulian Pullen #include <syslog.h> 102b3700b07SGordon Ross #include <uuid/uuid.h> 103b3700b07SGordon Ross #include <ads/dsgetdc.h> 1047a8a68f5SJulian Pullen #include "adutils_impl.h" 105b3700b07SGordon Ross #include "addisc_impl.h" 106c8e26105Sjp 107c5866007SKeyur Desai /* 108c5866007SKeyur Desai * These set some sanity policies for discovery. After a discovery 109c5866007SKeyur Desai * cycle, we will consider the results (successful or unsuccessful) 110c5866007SKeyur Desai * to be valid for at least MINIMUM_TTL seconds, and for at most 111c5866007SKeyur Desai * MAXIMUM_TTL seconds. Note that the caller is free to request 112c5866007SKeyur Desai * discovery cycles sooner than MINIMUM_TTL if it has reason to believe 113c5866007SKeyur Desai * that the situation has changed. 114c5866007SKeyur Desai */ 115c5866007SKeyur Desai #define MINIMUM_TTL (5 * 60) 116c5866007SKeyur Desai #define MAXIMUM_TTL (20 * 60) 117c8e26105Sjp 118c8e26105Sjp 119c8e26105Sjp #define DNS_MAX_NAME NS_MAXDNAME 120c8e26105Sjp 121b3700b07SGordon Ross #define GC_PORT 3268 122c8e26105Sjp 123c8e26105Sjp /* SRV RR names for various queries */ 124c8e26105Sjp #define LDAP_SRV_HEAD "_ldap._tcp." 125c8e26105Sjp #define SITE_SRV_MIDDLE "%s._sites." 126c8e26105Sjp #define GC_SRV_TAIL "gc._msdcs" 127c8e26105Sjp #define DC_SRV_TAIL "dc._msdcs" 128c8e26105Sjp #define ALL_GC_SRV_TAIL "_gc._tcp" 129c8e26105Sjp #define PDC_SRV "_ldap._tcp.pdc._msdcs.%s" 130c8e26105Sjp 131c8e26105Sjp /* A RR name for all GCs -- last resort this works */ 132c8e26105Sjp #define GC_ALL_A_NAME_FSTR "gc._msdcs.%s." 133c8e26105Sjp 134c8e26105Sjp 1350dcc7149Snw /* 1360dcc7149Snw * We try res_ninit() whenever we don't have one. res_ninit() fails if 1370dcc7149Snw * idmapd is running before the network is up! 1380dcc7149Snw */ 139b3700b07SGordon Ross #define DO_RES_NINIT(ctx) \ 140b3700b07SGordon Ross if (!(ctx)->res_ninitted) \ 141b3700b07SGordon Ross (void) do_res_ninit(ctx) 142b3700b07SGordon Ross 143b3700b07SGordon Ross #define DO_GETNAMEINFO(b, l, s) \ 144b3700b07SGordon Ross if (ad_disc_getnameinfo(b, l, s) != 0) \ 145b3700b07SGordon Ross (void) strlcpy(b, "?", l) 146b3700b07SGordon Ross 147b3700b07SGordon Ross #define DEBUG1STATUS(ctx, ...) do { \ 148b3700b07SGordon Ross if (DBG(DISC, 1)) \ 149b3700b07SGordon Ross logger(LOG_DEBUG, __VA_ARGS__); \ 150b3700b07SGordon Ross if (ctx->status_fp) { \ 151b3700b07SGordon Ross (void) fprintf(ctx->status_fp, __VA_ARGS__); \ 152b3700b07SGordon Ross (void) fprintf(ctx->status_fp, "\n"); \ 153b3700b07SGordon Ross } \ 154b3700b07SGordon Ross _NOTE(CONSTCOND) \ 155b3700b07SGordon Ross } while (0) 156c8e26105Sjp 157c8e26105Sjp #define is_fixed(item) \ 1584d61c878SJulian Pullen ((item)->state == AD_STATE_FIXED) 159c8e26105Sjp 160*d0bed8f2SGordon Ross #define is_changed(item, num, param) \ 161c8e26105Sjp ((item)->param_version[num] != (param)->version) 162c8e26105Sjp 163b3700b07SGordon Ross void * uuid_dup(void *); 164b3700b07SGordon Ross 165b3700b07SGordon Ross static ad_item_t *validate_SiteName(ad_disc_t ctx); 166b3700b07SGordon Ross static ad_item_t *validate_PreferredDC(ad_disc_t ctx); 167b3700b07SGordon Ross 168c8e26105Sjp /* 169c8e26105Sjp * Function definitions 170c8e26105Sjp */ 171c8e26105Sjp 172c8e26105Sjp 173b3700b07SGordon Ross static int 174b3700b07SGordon Ross do_res_ninit(ad_disc_t ctx) 175b3700b07SGordon Ross { 176b3700b07SGordon Ross int rc; 177b3700b07SGordon Ross 178b3700b07SGordon Ross rc = res_ninit(&ctx->res_state); 179b3700b07SGordon Ross if (rc != 0) 180b3700b07SGordon Ross return (rc); 181b3700b07SGordon Ross ctx->res_ninitted = 1; 182b3700b07SGordon Ross /* 183b3700b07SGordon Ross * The SRV records returnd by AD can be larger than 512 bytes, 184b3700b07SGordon Ross * so we'd like to use TCP for those searches. Unfortunately, 185b3700b07SGordon Ross * the TCP connect timeout seen by the resolver is very long 186b3700b07SGordon Ross * (more than a couple minutes) and we can't wait that long. 187b3700b07SGordon Ross * Don't do use TCP until we can override the timeout. 188b3700b07SGordon Ross * 189b3700b07SGordon Ross * Note that some queries will try TCP anyway. 190b3700b07SGordon Ross */ 191b3700b07SGordon Ross #if 0 192b3700b07SGordon Ross ctx->res_state.options |= RES_USEVC; 193b3700b07SGordon Ross #endif 194b3700b07SGordon Ross return (0); 195b3700b07SGordon Ross } 196b3700b07SGordon Ross 197b3700b07SGordon Ross /* 198b3700b07SGordon Ross * Private getnameinfo(3socket) variant tailored to our needs. 199b3700b07SGordon Ross */ 200b3700b07SGordon Ross int 201b3700b07SGordon Ross ad_disc_getnameinfo(char *obuf, int olen, struct sockaddr_storage *ss) 202b3700b07SGordon Ross { 203b3700b07SGordon Ross struct sockaddr *sa; 204b3700b07SGordon Ross int eai, slen; 205b3700b07SGordon Ross 206b3700b07SGordon Ross sa = (void *)ss; 207b3700b07SGordon Ross switch (sa->sa_family) { 208b3700b07SGordon Ross case AF_INET: 209b3700b07SGordon Ross slen = sizeof (struct sockaddr_in); 210b3700b07SGordon Ross break; 211b3700b07SGordon Ross case AF_INET6: 212b3700b07SGordon Ross slen = sizeof (struct sockaddr_in6); 213b3700b07SGordon Ross break; 214b3700b07SGordon Ross default: 215b3700b07SGordon Ross return (EAI_FAMILY); 216b3700b07SGordon Ross } 217b3700b07SGordon Ross 218b3700b07SGordon Ross eai = getnameinfo(sa, slen, obuf, olen, NULL, 0, NI_NUMERICHOST); 219b3700b07SGordon Ross 220b3700b07SGordon Ross return (eai); 221b3700b07SGordon Ross } 222c8e26105Sjp 223c8e26105Sjp static void 224c8e26105Sjp update_version(ad_item_t *item, int num, ad_item_t *param) 225c8e26105Sjp { 226c8e26105Sjp item->param_version[num] = param->version; 227c8e26105Sjp } 228c8e26105Sjp 229c8e26105Sjp 2304d61c878SJulian Pullen 2317a8a68f5SJulian Pullen static boolean_t 2324d61c878SJulian Pullen is_valid(ad_item_t *item) 233c8e26105Sjp { 2344d61c878SJulian Pullen if (item->value != NULL) { 2354d61c878SJulian Pullen if (item->state == AD_STATE_FIXED) 2367a8a68f5SJulian Pullen return (B_TRUE); 2374d61c878SJulian Pullen if (item->state == AD_STATE_AUTO && 238c5866007SKeyur Desai (item->expires == 0 || item->expires > time(NULL))) 2397a8a68f5SJulian Pullen return (B_TRUE); 2404d61c878SJulian Pullen } 2417a8a68f5SJulian Pullen return (B_FALSE); 242c8e26105Sjp } 243c8e26105Sjp 244c8e26105Sjp 245c8e26105Sjp static void 2464d61c878SJulian Pullen update_item(ad_item_t *item, void *value, enum ad_item_state state, 247c8e26105Sjp uint32_t ttl) 248c8e26105Sjp { 2494d61c878SJulian Pullen if (item->value != NULL && value != NULL) { 2504d61c878SJulian Pullen if ((item->type == AD_STRING && 2514d61c878SJulian Pullen strcmp(item->value, value) != 0) || 252b3700b07SGordon Ross (item->type == AD_UUID && 253b3700b07SGordon Ross ad_disc_compare_uuid(item->value, value) != 0)|| 2544d61c878SJulian Pullen (item->type == AD_DIRECTORY && 2554d61c878SJulian Pullen ad_disc_compare_ds(item->value, value) != 0)|| 2564d61c878SJulian Pullen (item->type == AD_DOMAINS_IN_FOREST && 2574d61c878SJulian Pullen ad_disc_compare_domainsinforest(item->value, value) != 0) || 2584d61c878SJulian Pullen (item->type == AD_TRUSTED_DOMAINS && 2594d61c878SJulian Pullen ad_disc_compare_trusteddomains(item->value, value) != 0)) 260c8e26105Sjp item->version++; 2614d61c878SJulian Pullen } else if (item->value != value) 262c8e26105Sjp item->version++; 263c8e26105Sjp 2644d61c878SJulian Pullen if (item->value != NULL) 2654d61c878SJulian Pullen free(item->value); 266c8e26105Sjp 2674d61c878SJulian Pullen item->value = value; 2684d61c878SJulian Pullen item->state = state; 269c8e26105Sjp 270c8e26105Sjp if (ttl == 0) 271c5866007SKeyur Desai item->expires = 0; 272c8e26105Sjp else 273c5866007SKeyur Desai item->expires = time(NULL) + ttl; 274c8e26105Sjp } 275c8e26105Sjp 276b3700b07SGordon Ross /* Compare UUIDs */ 277b3700b07SGordon Ross int 278b3700b07SGordon Ross ad_disc_compare_uuid(uuid_t *u1, uuid_t *u2) 279b3700b07SGordon Ross { 280b3700b07SGordon Ross int rc; 281b3700b07SGordon Ross 282b3700b07SGordon Ross rc = memcmp(u1, u2, UUID_LEN); 283b3700b07SGordon Ross return (rc); 284b3700b07SGordon Ross } 285b3700b07SGordon Ross 286b3700b07SGordon Ross void * 287b3700b07SGordon Ross uuid_dup(void *src) 288b3700b07SGordon Ross { 289b3700b07SGordon Ross void *dst; 290b3700b07SGordon Ross dst = malloc(UUID_LEN); 291b3700b07SGordon Ross if (dst != NULL) 292b3700b07SGordon Ross (void) memcpy(dst, src, UUID_LEN); 293b3700b07SGordon Ross return (dst); 294b3700b07SGordon Ross } 295c8e26105Sjp 2964d61c878SJulian Pullen /* Compare DS lists */ 2974d61c878SJulian Pullen int 298b3700b07SGordon Ross ad_disc_compare_ds(ad_disc_ds_t *ds1, ad_disc_ds_t *ds2) 299c8e26105Sjp { 3007a8a68f5SJulian Pullen int i, j; 3017a8a68f5SJulian Pullen int num_ds1; 3027a8a68f5SJulian Pullen int num_ds2; 3037a8a68f5SJulian Pullen boolean_t match; 304c8e26105Sjp 3054d61c878SJulian Pullen for (i = 0; ds1[i].host[0] != '\0'; i++) 3064d61c878SJulian Pullen continue; 3074d61c878SJulian Pullen num_ds1 = i; 3084d61c878SJulian Pullen for (j = 0; ds2[j].host[0] != '\0'; j++) 3094d61c878SJulian Pullen continue; 3104d61c878SJulian Pullen num_ds2 = j; 3114d61c878SJulian Pullen if (num_ds1 != num_ds2) 3124d61c878SJulian Pullen return (1); 313c8e26105Sjp 3144d61c878SJulian Pullen for (i = 0; i < num_ds1; i++) { 3157a8a68f5SJulian Pullen match = B_FALSE; 3164d61c878SJulian Pullen for (j = 0; j < num_ds2; j++) { 317928e1f97SJordan Brown if (strcmp(ds1[i].host, ds2[j].host) == 0 && 318928e1f97SJordan Brown ds1[i].port == ds2[j].port) { 3197a8a68f5SJulian Pullen match = B_TRUE; 3204d61c878SJulian Pullen break; 3214d61c878SJulian Pullen } 3224d61c878SJulian Pullen } 3234d61c878SJulian Pullen if (!match) 3244d61c878SJulian Pullen return (1); 3254d61c878SJulian Pullen } 3264d61c878SJulian Pullen return (0); 3274d61c878SJulian Pullen } 328c8e26105Sjp 3294d61c878SJulian Pullen 3304d61c878SJulian Pullen /* Copy a list of DSs */ 331b3700b07SGordon Ross static ad_disc_ds_t * 332b3700b07SGordon Ross ds_dup(const ad_disc_ds_t *srv) 3334d61c878SJulian Pullen { 3344d61c878SJulian Pullen int i; 3354d61c878SJulian Pullen int size; 336b3700b07SGordon Ross ad_disc_ds_t *new = NULL; 3374d61c878SJulian Pullen 3384d61c878SJulian Pullen for (i = 0; srv[i].host[0] != '\0'; i++) 3394d61c878SJulian Pullen continue; 3404d61c878SJulian Pullen 341b3700b07SGordon Ross size = (i + 1) * sizeof (ad_disc_ds_t); 3424d61c878SJulian Pullen new = malloc(size); 3434d61c878SJulian Pullen if (new != NULL) 344148c5f43SAlan Wright (void) memcpy(new, srv, size); 3454d61c878SJulian Pullen return (new); 346c8e26105Sjp } 347c8e26105Sjp 348c8e26105Sjp 3494d61c878SJulian Pullen int 3504d61c878SJulian Pullen ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1, 3514d61c878SJulian Pullen ad_disc_trusteddomains_t *td2) 352c8e26105Sjp { 3537a8a68f5SJulian Pullen int i, j; 3547a8a68f5SJulian Pullen int num_td1; 3557a8a68f5SJulian Pullen int num_td2; 3567a8a68f5SJulian Pullen boolean_t match; 357c8e26105Sjp 3584d61c878SJulian Pullen for (i = 0; td1[i].domain[0] != '\0'; i++) 3594d61c878SJulian Pullen continue; 3604d61c878SJulian Pullen num_td1 = i; 361c8e26105Sjp 3624d61c878SJulian Pullen for (j = 0; td2[j].domain[0] != '\0'; j++) 3634d61c878SJulian Pullen continue; 3644d61c878SJulian Pullen num_td2 = j; 3654d61c878SJulian Pullen 3664d61c878SJulian Pullen if (num_td1 != num_td2) 3674d61c878SJulian Pullen return (1); 3684d61c878SJulian Pullen 3694d61c878SJulian Pullen for (i = 0; i < num_td1; i++) { 3707a8a68f5SJulian Pullen match = B_FALSE; 3714d61c878SJulian Pullen for (j = 0; j < num_td2; j++) { 3721fcced4cSJordan Brown if (domain_eq(td1[i].domain, td2[j].domain)) { 3737a8a68f5SJulian Pullen match = B_TRUE; 3744d61c878SJulian Pullen break; 3754d61c878SJulian Pullen } 3764d61c878SJulian Pullen } 3774d61c878SJulian Pullen if (!match) 3784d61c878SJulian Pullen return (1); 3794d61c878SJulian Pullen } 3804d61c878SJulian Pullen return (0); 3814d61c878SJulian Pullen } 3824d61c878SJulian Pullen 3834d61c878SJulian Pullen 3844d61c878SJulian Pullen 3854d61c878SJulian Pullen /* Copy a list of Trusted Domains */ 3864d61c878SJulian Pullen static ad_disc_trusteddomains_t * 3874d61c878SJulian Pullen td_dup(const ad_disc_trusteddomains_t *td) 3884d61c878SJulian Pullen { 3894d61c878SJulian Pullen int i; 3904d61c878SJulian Pullen int size; 3914d61c878SJulian Pullen ad_disc_trusteddomains_t *new = NULL; 3924d61c878SJulian Pullen 3934d61c878SJulian Pullen for (i = 0; td[i].domain[0] != '\0'; i++) 3944d61c878SJulian Pullen continue; 3954d61c878SJulian Pullen 3964d61c878SJulian Pullen size = (i + 1) * sizeof (ad_disc_trusteddomains_t); 3974d61c878SJulian Pullen new = malloc(size); 3984d61c878SJulian Pullen if (new != NULL) 399148c5f43SAlan Wright (void) memcpy(new, td, size); 4004d61c878SJulian Pullen return (new); 4014d61c878SJulian Pullen } 4024d61c878SJulian Pullen 4034d61c878SJulian Pullen 4044d61c878SJulian Pullen 4054d61c878SJulian Pullen int 4064d61c878SJulian Pullen ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1, 4074d61c878SJulian Pullen ad_disc_domainsinforest_t *df2) 4084d61c878SJulian Pullen { 4097a8a68f5SJulian Pullen int i, j; 4107a8a68f5SJulian Pullen int num_df1; 4117a8a68f5SJulian Pullen int num_df2; 4127a8a68f5SJulian Pullen boolean_t match; 4134d61c878SJulian Pullen 4144d61c878SJulian Pullen for (i = 0; df1[i].domain[0] != '\0'; i++) 4154d61c878SJulian Pullen continue; 4164d61c878SJulian Pullen num_df1 = i; 4174d61c878SJulian Pullen 4184d61c878SJulian Pullen for (j = 0; df2[j].domain[0] != '\0'; j++) 4194d61c878SJulian Pullen continue; 4204d61c878SJulian Pullen num_df2 = j; 4214d61c878SJulian Pullen 4224d61c878SJulian Pullen if (num_df1 != num_df2) 4234d61c878SJulian Pullen return (1); 4244d61c878SJulian Pullen 4254d61c878SJulian Pullen for (i = 0; i < num_df1; i++) { 4267a8a68f5SJulian Pullen match = B_FALSE; 4274d61c878SJulian Pullen for (j = 0; j < num_df2; j++) { 4281fcced4cSJordan Brown if (domain_eq(df1[i].domain, df2[j].domain) && 429928e1f97SJordan Brown strcmp(df1[i].sid, df2[j].sid) == 0) { 4307a8a68f5SJulian Pullen match = B_TRUE; 4314d61c878SJulian Pullen break; 4324d61c878SJulian Pullen } 4334d61c878SJulian Pullen } 4344d61c878SJulian Pullen if (!match) 4354d61c878SJulian Pullen return (1); 4364d61c878SJulian Pullen } 4374d61c878SJulian Pullen return (0); 4384d61c878SJulian Pullen } 439c8e26105Sjp 4404d61c878SJulian Pullen 4414d61c878SJulian Pullen 4424d61c878SJulian Pullen /* Copy a list of Trusted Domains */ 4434d61c878SJulian Pullen static ad_disc_domainsinforest_t * 4444d61c878SJulian Pullen df_dup(const ad_disc_domainsinforest_t *df) 4454d61c878SJulian Pullen { 4464d61c878SJulian Pullen int i; 4474d61c878SJulian Pullen int size; 4484d61c878SJulian Pullen ad_disc_domainsinforest_t *new = NULL; 4494d61c878SJulian Pullen 4504d61c878SJulian Pullen for (i = 0; df[i].domain[0] != '\0'; i++) 4514d61c878SJulian Pullen continue; 4524d61c878SJulian Pullen 4534d61c878SJulian Pullen size = (i + 1) * sizeof (ad_disc_domainsinforest_t); 4544d61c878SJulian Pullen new = malloc(size); 4554d61c878SJulian Pullen if (new != NULL) 456148c5f43SAlan Wright (void) memcpy(new, df, size); 4574d61c878SJulian Pullen return (new); 458c8e26105Sjp } 459c8e26105Sjp 460c8e26105Sjp 461c8e26105Sjp 4624d61c878SJulian Pullen 4634d61c878SJulian Pullen 464c8e26105Sjp /* 465c8e26105Sjp * Returns an array of IPv4 address/prefix length 466c8e26105Sjp * The last subnet is NULL 467c8e26105Sjp */ 468c8e26105Sjp static ad_subnet_t * 469c8e26105Sjp find_subnets() 470c8e26105Sjp { 471c8e26105Sjp int sock, n, i; 472c8e26105Sjp struct lifconf lifc; 473c8e26105Sjp struct lifreq lifr, *lifrp; 474c8e26105Sjp struct lifnum lifn; 475c8e26105Sjp uint32_t prefix_len; 476c8e26105Sjp char *s; 477c8e26105Sjp ad_subnet_t *results; 478c8e26105Sjp 479c8e26105Sjp lifrp = &lifr; 480c8e26105Sjp 481c8e26105Sjp if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 4827a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to open IPv4 socket for " 48371590c90Snw "listing network interfaces (%s)", strerror(errno)); 484c8e26105Sjp return (NULL); 485c8e26105Sjp } 486c8e26105Sjp 487c8e26105Sjp lifn.lifn_family = AF_INET; 488c8e26105Sjp lifn.lifn_flags = 0; 489c8e26105Sjp if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 4907a8a68f5SJulian Pullen logger(LOG_ERR, 49171590c90Snw "Failed to find the number of network interfaces (%s)", 49271590c90Snw strerror(errno)); 493148c5f43SAlan Wright (void) close(sock); 494c8e26105Sjp return (NULL); 495c8e26105Sjp } 496c8e26105Sjp 497c8e26105Sjp if (lifn.lifn_count < 1) { 4987a8a68f5SJulian Pullen logger(LOG_ERR, "No IPv4 network interfaces found"); 499148c5f43SAlan Wright (void) close(sock); 500c8e26105Sjp return (NULL); 501c8e26105Sjp } 502c8e26105Sjp 503c8e26105Sjp lifc.lifc_family = AF_INET; 504c8e26105Sjp lifc.lifc_flags = 0; 505c8e26105Sjp lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 506c8e26105Sjp lifc.lifc_buf = malloc(lifc.lifc_len); 507c8e26105Sjp 508c8e26105Sjp if (lifc.lifc_buf == NULL) { 5097a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 510148c5f43SAlan Wright (void) close(sock); 511c8e26105Sjp return (NULL); 512c8e26105Sjp } 513c8e26105Sjp 514c8e26105Sjp if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 5157a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to list network interfaces (%s)", 51671590c90Snw strerror(errno)); 517c8e26105Sjp free(lifc.lifc_buf); 518148c5f43SAlan Wright (void) close(sock); 519c8e26105Sjp return (NULL); 520c8e26105Sjp } 521c8e26105Sjp 522c8e26105Sjp n = lifc.lifc_len / (int)sizeof (struct lifreq); 523c8e26105Sjp 524c8e26105Sjp if ((results = calloc(n + 1, sizeof (ad_subnet_t))) == NULL) { 525c8e26105Sjp free(lifc.lifc_buf); 526148c5f43SAlan Wright (void) close(sock); 527c8e26105Sjp return (NULL); 528c8e26105Sjp } 529c8e26105Sjp 530c8e26105Sjp for (i = 0, lifrp = lifc.lifc_req; i < n; i++, lifrp++) { 531c8e26105Sjp if (ioctl(sock, SIOCGLIFFLAGS, lifrp) < 0) 532c8e26105Sjp continue; 533c8e26105Sjp 534c8e26105Sjp if ((lifrp->lifr_flags & IFF_UP) == 0) 535c8e26105Sjp continue; 536c8e26105Sjp 537c8e26105Sjp if (ioctl(sock, SIOCGLIFSUBNET, lifrp) < 0) 538c8e26105Sjp continue; 539c8e26105Sjp 540c8e26105Sjp prefix_len = lifrp->lifr_addrlen; 541c8e26105Sjp 542c8e26105Sjp s = inet_ntoa(((struct sockaddr_in *) 543c8e26105Sjp &lifrp->lifr_addr)->sin_addr); 544c8e26105Sjp 545c8e26105Sjp (void) snprintf(results[i].subnet, sizeof (ad_subnet_t), 546c8e26105Sjp "%s/%d", s, prefix_len); 547c8e26105Sjp } 548c8e26105Sjp 549c8e26105Sjp free(lifc.lifc_buf); 550148c5f43SAlan Wright (void) close(sock); 551c8e26105Sjp 552c8e26105Sjp return (results); 553c8e26105Sjp } 554c8e26105Sjp 555c8e26105Sjp static int 556c8e26105Sjp cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2) 557c8e26105Sjp { 558c8e26105Sjp int num_subnets1; 559c8e26105Sjp int num_subnets2; 5607a8a68f5SJulian Pullen boolean_t matched; 561c8e26105Sjp int i, j; 562c8e26105Sjp 563c8e26105Sjp for (i = 0; subnets1[i].subnet[0] != '\0'; i++) 5644d61c878SJulian Pullen continue; 565c8e26105Sjp num_subnets1 = i; 566c8e26105Sjp 567c8e26105Sjp for (i = 0; subnets2[i].subnet[0] != '\0'; i++) 5684d61c878SJulian Pullen continue; 569c8e26105Sjp num_subnets2 = i; 570c8e26105Sjp 571c8e26105Sjp if (num_subnets1 != num_subnets2) 572c8e26105Sjp return (1); 573c8e26105Sjp 574c8e26105Sjp for (i = 0; i < num_subnets1; i++) { 5757a8a68f5SJulian Pullen matched = B_FALSE; 576c8e26105Sjp for (j = 0; j < num_subnets2; j++) { 577c8e26105Sjp if (strcmp(subnets1[i].subnet, 578c8e26105Sjp subnets2[j].subnet) == 0) { 5797a8a68f5SJulian Pullen matched = B_TRUE; 580c8e26105Sjp break; 581c8e26105Sjp } 582c8e26105Sjp } 583c8e26105Sjp if (!matched) 584c8e26105Sjp return (1); 585c8e26105Sjp } 586c8e26105Sjp return (0); 587c8e26105Sjp } 588c8e26105Sjp 589c8e26105Sjp 590c8e26105Sjp 591c8e26105Sjp 592c8e26105Sjp /* Convert a DN's DC components into a DNS domainname */ 5937a8a68f5SJulian Pullen char * 594c8e26105Sjp DN_to_DNS(const char *dn_name) 595c8e26105Sjp { 596c8e26105Sjp char dns[DNS_MAX_NAME]; 597c8e26105Sjp char *dns_name; 598c8e26105Sjp int i, j; 599c8e26105Sjp int num = 0; 600c8e26105Sjp 601c8e26105Sjp j = 0; 602c8e26105Sjp i = 0; 603c8e26105Sjp 6044d61c878SJulian Pullen if (dn_name == NULL) 6054d61c878SJulian Pullen return (NULL); 606c8e26105Sjp /* 607c8e26105Sjp * Find all DC=<value> and form DNS name of the 608c8e26105Sjp * form <value1>.<value2>... 609c8e26105Sjp */ 6104d61c878SJulian Pullen while (dn_name[i] != '\0') { 611c8e26105Sjp if (strncasecmp(&dn_name[i], "DC=", 3) == 0) { 612c8e26105Sjp i += 3; 6134d61c878SJulian Pullen if (dn_name[i] != '\0' && num > 0) 614c8e26105Sjp dns[j++] = '.'; 6154d61c878SJulian Pullen while (dn_name[i] != '\0' && 616c8e26105Sjp dn_name[i] != ',' && dn_name[i] != '+') 617c8e26105Sjp dns[j++] = dn_name[i++]; 618c8e26105Sjp num++; 619c8e26105Sjp } else { 620c8e26105Sjp /* Skip attr=value as it is not DC= */ 6214d61c878SJulian Pullen while (dn_name[i] != '\0' && 622c8e26105Sjp dn_name[i] != ',' && dn_name[i] != '+') 623c8e26105Sjp i++; 624c8e26105Sjp } 625c8e26105Sjp /* Skip over separator ',' or '+' */ 6264d61c878SJulian Pullen if (dn_name[i] != '\0') i++; 627c8e26105Sjp } 628c8e26105Sjp dns[j] = '\0'; 629c8e26105Sjp dns_name = malloc(j + 1); 630c8e26105Sjp if (dns_name != NULL) 631c8e26105Sjp (void) strlcpy(dns_name, dns, j + 1); 632c8e26105Sjp return (dns_name); 633c8e26105Sjp } 634c8e26105Sjp 635c8e26105Sjp 6364d61c878SJulian Pullen /* 6374d61c878SJulian Pullen * A utility function to bind to a Directory server 6384d61c878SJulian Pullen */ 6394d61c878SJulian Pullen 640c5866007SKeyur Desai static 641c5866007SKeyur Desai LDAP * 642b3700b07SGordon Ross ldap_lookup_init(ad_disc_ds_t *ds) 6434d61c878SJulian Pullen { 644*d0bed8f2SGordon Ross int i; 6454d61c878SJulian Pullen int rc, ldversion; 6464d61c878SJulian Pullen int zero = 0; 647*d0bed8f2SGordon Ross int timeoutms = 5 * 1000; 648*d0bed8f2SGordon Ross char *saslmech = "GSSAPI"; 6494d61c878SJulian Pullen uint32_t saslflags = LDAP_SASL_INTERACTIVE; 650*d0bed8f2SGordon Ross LDAP *ld = NULL; 6514d61c878SJulian Pullen 6524d61c878SJulian Pullen for (i = 0; ds[i].host[0] != '\0'; i++) { 653b3700b07SGordon Ross if (DBG(LDAP, 2)) { 654b3700b07SGordon Ross logger(LOG_DEBUG, "adutils: ldap_lookup_init, host %s", 655b3700b07SGordon Ross ds[i].host); 656b3700b07SGordon Ross } 657b3700b07SGordon Ross 6584d61c878SJulian Pullen ld = ldap_init(ds[i].host, ds[i].port); 6594d61c878SJulian Pullen if (ld == NULL) { 660148c5f43SAlan Wright if (DBG(LDAP, 1)) { 661148c5f43SAlan Wright logger(LOG_DEBUG, 662148c5f43SAlan Wright "Couldn't connect to AD DC %s:%d (%s)", 663148c5f43SAlan Wright ds[i].host, ds[i].port, 664148c5f43SAlan Wright strerror(errno)); 665148c5f43SAlan Wright } 6664d61c878SJulian Pullen continue; 6674d61c878SJulian Pullen } 6684d61c878SJulian Pullen 6694d61c878SJulian Pullen ldversion = LDAP_VERSION3; 6704d61c878SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 6714d61c878SJulian Pullen &ldversion); 6724d61c878SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, 6734d61c878SJulian Pullen LDAP_OPT_OFF); 6744d61c878SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 6754d61c878SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 6764d61c878SJulian Pullen /* setup TCP/IP connect timeout */ 6774d61c878SJulian Pullen (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 6784d61c878SJulian Pullen &timeoutms); 6794d61c878SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_RESTART, 6804d61c878SJulian Pullen LDAP_OPT_ON); 6814d61c878SJulian Pullen 682bd428526SJulian Pullen rc = adutils_set_thread_functions(ld); 683bd428526SJulian Pullen if (rc != LDAP_SUCCESS) { 684bd428526SJulian Pullen /* Error has already been logged */ 685bd428526SJulian Pullen (void) ldap_unbind(ld); 686bd428526SJulian Pullen ld = NULL; 687bd428526SJulian Pullen continue; 688bd428526SJulian Pullen } 689bd428526SJulian Pullen 6904d61c878SJulian Pullen rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */, 6914d61c878SJulian Pullen saslmech, NULL, NULL, saslflags, &saslcallback, 6924d61c878SJulian Pullen NULL /* defaults */); 6934d61c878SJulian Pullen if (rc == LDAP_SUCCESS) 6944d61c878SJulian Pullen break; 6954d61c878SJulian Pullen 696148c5f43SAlan Wright if (DBG(LDAP, 0)) { 697148c5f43SAlan Wright logger(LOG_INFO, "LDAP: %s:%d: %s", 698148c5f43SAlan Wright ds[i].host, ds[i].port, ldap_err2string(rc)); 699148c5f43SAlan Wright ldap_perror(ld, ds[i].host); 700148c5f43SAlan Wright } 7014d61c878SJulian Pullen (void) ldap_unbind(ld); 7024d61c878SJulian Pullen ld = NULL; 7034d61c878SJulian Pullen } 7044d61c878SJulian Pullen return (ld); 7054d61c878SJulian Pullen } 7064d61c878SJulian Pullen 707c8e26105Sjp 7087a8a68f5SJulian Pullen 7094d61c878SJulian Pullen /* 7104d61c878SJulian Pullen * Lookup the trusted domains in the global catalog. 7114d61c878SJulian Pullen * 7124d61c878SJulian Pullen * Returns: 7134d61c878SJulian Pullen * array of trusted domains which is terminated by 7144d61c878SJulian Pullen * an empty trusted domain. 7154d61c878SJulian Pullen * NULL an error occured 7164d61c878SJulian Pullen */ 7174d61c878SJulian Pullen ad_disc_trusteddomains_t * 718b3700b07SGordon Ross ldap_lookup_trusted_domains(LDAP **ld, ad_disc_ds_t *globalCatalog, 7194d61c878SJulian Pullen char *base_dn) 7204d61c878SJulian Pullen { 7214d61c878SJulian Pullen int scope = LDAP_SCOPE_SUBTREE; 7224d61c878SJulian Pullen char *attrs[3]; 7234d61c878SJulian Pullen int rc; 7244d61c878SJulian Pullen LDAPMessage *results = NULL; 7254d61c878SJulian Pullen LDAPMessage *entry; 7264d61c878SJulian Pullen char *filter; 7274d61c878SJulian Pullen char **partner = NULL; 7284d61c878SJulian Pullen char **direction = NULL; 7294d61c878SJulian Pullen int num = 0; 7304d61c878SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 7314d61c878SJulian Pullen 732148c5f43SAlan Wright if (DBG(DISC, 1)) 733148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for trusted domains..."); 7344d61c878SJulian Pullen 7354d61c878SJulian Pullen if (*ld == NULL) 7364d61c878SJulian Pullen *ld = ldap_lookup_init(globalCatalog); 7374d61c878SJulian Pullen 738b3700b07SGordon Ross if (*ld == NULL) { 739b3700b07SGordon Ross logger(LOG_ERR, "adutils: ldap_lookup_init failed"); 7404d61c878SJulian Pullen return (NULL); 741b3700b07SGordon Ross } 7424d61c878SJulian Pullen 7434d61c878SJulian Pullen attrs[0] = "trustPartner"; 7444d61c878SJulian Pullen attrs[1] = "trustDirection"; 7454d61c878SJulian Pullen attrs[2] = NULL; 7464d61c878SJulian Pullen 747148c5f43SAlan Wright /* 748148c5f43SAlan Wright * Trust direction values: 749148c5f43SAlan Wright * 1 - inbound (they trust us) 750148c5f43SAlan Wright * 2 - outbound (we trust them) 751148c5f43SAlan Wright * 3 - bidirectional (we trust each other) 752148c5f43SAlan Wright */ 7534d61c878SJulian Pullen filter = "(&(objectclass=trustedDomain)" 754148c5f43SAlan Wright "(|(trustDirection=3)(trustDirection=2)))"; 7554d61c878SJulian Pullen 7564d61c878SJulian Pullen rc = ldap_search_s(*ld, base_dn, scope, filter, attrs, 0, &results); 757148c5f43SAlan Wright if (DBG(DISC, 1)) 758148c5f43SAlan Wright logger(LOG_DEBUG, "Trusted domains:"); 7594d61c878SJulian Pullen if (rc == LDAP_SUCCESS) { 7604d61c878SJulian Pullen for (entry = ldap_first_entry(*ld, results); 7614d61c878SJulian Pullen entry != NULL; entry = ldap_next_entry(*ld, entry)) { 7624d61c878SJulian Pullen partner = ldap_get_values(*ld, entry, "trustPartner"); 7634d61c878SJulian Pullen direction = ldap_get_values( 7644d61c878SJulian Pullen *ld, entry, "trustDirection"); 7654d61c878SJulian Pullen 7664d61c878SJulian Pullen if (partner != NULL && direction != NULL) { 767148c5f43SAlan Wright if (DBG(DISC, 1)) { 768148c5f43SAlan Wright logger(LOG_DEBUG, " %s (%s)", 769148c5f43SAlan Wright partner[0], direction[0]); 770148c5f43SAlan Wright } 7714d61c878SJulian Pullen num++; 772c5866007SKeyur Desai void *tmp = realloc(trusted_domains, 7734d61c878SJulian Pullen (num + 1) * 7744d61c878SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 775c5866007SKeyur Desai if (tmp == NULL) { 776c5866007SKeyur Desai free(trusted_domains); 7774d61c878SJulian Pullen ldap_value_free(partner); 7784d61c878SJulian Pullen ldap_value_free(direction); 779148c5f43SAlan Wright (void) ldap_msgfree(results); 7804d61c878SJulian Pullen return (NULL); 7814d61c878SJulian Pullen } 782c5866007SKeyur Desai trusted_domains = tmp; 7834d61c878SJulian Pullen /* Last element should be zero */ 784148c5f43SAlan Wright (void) memset(&trusted_domains[num], 0, 7854d61c878SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 786148c5f43SAlan Wright (void) strcpy(trusted_domains[num - 1].domain, 7874d61c878SJulian Pullen partner[0]); 7884d61c878SJulian Pullen trusted_domains[num - 1].direction = 7894d61c878SJulian Pullen atoi(direction[0]); 7904d61c878SJulian Pullen } 7914d61c878SJulian Pullen if (partner != NULL) 7924d61c878SJulian Pullen ldap_value_free(partner); 7934d61c878SJulian Pullen if (direction != NULL) 7944d61c878SJulian Pullen ldap_value_free(direction); 7954d61c878SJulian Pullen } 7964d61c878SJulian Pullen } else if (rc == LDAP_NO_RESULTS_RETURNED) { 7974d61c878SJulian Pullen /* This is not an error - return empty trusted domain */ 7984d61c878SJulian Pullen trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t)); 799148c5f43SAlan Wright if (DBG(DISC, 1)) 800148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 801b3700b07SGordon Ross } else { 802b3700b07SGordon Ross if (DBG(DISC, 1)) 803b3700b07SGordon Ross logger(LOG_DEBUG, " rc=%d", rc); 8044d61c878SJulian Pullen } 8054d61c878SJulian Pullen if (results != NULL) 806148c5f43SAlan Wright (void) ldap_msgfree(results); 8074d61c878SJulian Pullen 8084d61c878SJulian Pullen return (trusted_domains); 8094d61c878SJulian Pullen } 8104d61c878SJulian Pullen 8114d61c878SJulian Pullen 8124d61c878SJulian Pullen /* 8134d61c878SJulian Pullen * This functions finds all the domains in a forest. 8144d61c878SJulian Pullen */ 8154d61c878SJulian Pullen ad_disc_domainsinforest_t * 816b3700b07SGordon Ross ldap_lookup_domains_in_forest(LDAP **ld, ad_disc_ds_t *globalCatalogs) 8174d61c878SJulian Pullen { 818928e1f97SJordan Brown static char *attrs[] = { 819928e1f97SJordan Brown "objectSid", 820928e1f97SJordan Brown NULL, 821928e1f97SJordan Brown }; 8224d61c878SJulian Pullen int rc; 8234d61c878SJulian Pullen LDAPMessage *result = NULL; 8244d61c878SJulian Pullen LDAPMessage *entry; 825928e1f97SJordan Brown int ndomains = 0; 826928e1f97SJordan Brown int nresults; 8274d61c878SJulian Pullen ad_disc_domainsinforest_t *domains = NULL; 8284d61c878SJulian Pullen 829b3700b07SGordon Ross if (DBG(DISC, 1)) 830148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for domains in forest..."); 831148c5f43SAlan Wright 8324d61c878SJulian Pullen if (*ld == NULL) 8334d61c878SJulian Pullen *ld = ldap_lookup_init(globalCatalogs); 8344d61c878SJulian Pullen 835b3700b07SGordon Ross if (*ld == NULL) { 836b3700b07SGordon Ross logger(LOG_ERR, "adutils: ldap_lookup_init failed"); 8374d61c878SJulian Pullen return (NULL); 838b3700b07SGordon Ross } 8394d61c878SJulian Pullen 840928e1f97SJordan Brown /* Find domains */ 841928e1f97SJordan Brown rc = ldap_search_s(*ld, "", LDAP_SCOPE_SUBTREE, 842928e1f97SJordan Brown "(objectClass=Domain)", attrs, 0, &result); 843b3700b07SGordon Ross if (rc != LDAP_SUCCESS) { 844b3700b07SGordon Ross logger(LOG_ERR, "adutils: ldap_search, rc=%d", rc); 845b3700b07SGordon Ross goto err; 846b3700b07SGordon Ross } 847148c5f43SAlan Wright if (DBG(DISC, 1)) 848148c5f43SAlan Wright logger(LOG_DEBUG, "Domains in forest:"); 849928e1f97SJordan Brown 850928e1f97SJordan Brown nresults = ldap_count_entries(*ld, result); 851928e1f97SJordan Brown domains = calloc(nresults + 1, sizeof (*domains)); 852b3700b07SGordon Ross if (domains == NULL) { 853b3700b07SGordon Ross if (DBG(DISC, 1)) 854b3700b07SGordon Ross logger(LOG_DEBUG, " (nomem)"); 855928e1f97SJordan Brown goto err; 856b3700b07SGordon Ross } 857928e1f97SJordan Brown 858928e1f97SJordan Brown for (entry = ldap_first_entry(*ld, result); 859928e1f97SJordan Brown entry != NULL; 860928e1f97SJordan Brown entry = ldap_next_entry(*ld, entry)) { 861928e1f97SJordan Brown struct berval **sid_ber; 862928e1f97SJordan Brown adutils_sid_t sid; 863928e1f97SJordan Brown char *sid_str; 864*d0bed8f2SGordon Ross char *name; 865bbf6f00cSJordan Brown char *dn; 866928e1f97SJordan Brown 867928e1f97SJordan Brown sid_ber = ldap_get_values_len(*ld, entry, 868928e1f97SJordan Brown "objectSid"); 869928e1f97SJordan Brown if (sid_ber == NULL) 870928e1f97SJordan Brown continue; 8714d61c878SJulian Pullen 872928e1f97SJordan Brown rc = adutils_getsid(sid_ber[0], &sid); 873928e1f97SJordan Brown ldap_value_free_len(sid_ber); 874928e1f97SJordan Brown if (rc < 0) 875928e1f97SJordan Brown goto err; 8764d61c878SJulian Pullen 877928e1f97SJordan Brown if ((sid_str = adutils_sid2txt(&sid)) == NULL) 878928e1f97SJordan Brown goto err; 8794d61c878SJulian Pullen 880148c5f43SAlan Wright (void) strcpy(domains[ndomains].sid, sid_str); 881928e1f97SJordan Brown free(sid_str); 882928e1f97SJordan Brown 883bbf6f00cSJordan Brown dn = ldap_get_dn(*ld, entry); 884bbf6f00cSJordan Brown name = DN_to_DNS(dn); 885bbf6f00cSJordan Brown free(dn); 886928e1f97SJordan Brown if (name == NULL) 887928e1f97SJordan Brown goto err; 888928e1f97SJordan Brown 889148c5f43SAlan Wright (void) strcpy(domains[ndomains].domain, name); 890928e1f97SJordan Brown free(name); 891928e1f97SJordan Brown 892148c5f43SAlan Wright if (DBG(DISC, 1)) 893148c5f43SAlan Wright logger(LOG_DEBUG, " %s", domains[ndomains].domain); 894928e1f97SJordan Brown 895928e1f97SJordan Brown ndomains++; 8964d61c878SJulian Pullen } 8974d61c878SJulian Pullen 898148c5f43SAlan Wright if (ndomains == 0) { 899148c5f43SAlan Wright if (DBG(DISC, 1)) 900148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 901928e1f97SJordan Brown goto err; 902148c5f43SAlan Wright } 903928e1f97SJordan Brown 904928e1f97SJordan Brown if (ndomains < nresults) { 905928e1f97SJordan Brown ad_disc_domainsinforest_t *tmp; 9061fcced4cSJordan Brown tmp = realloc(domains, (ndomains + 1) * sizeof (*domains)); 907928e1f97SJordan Brown if (tmp == NULL) 908928e1f97SJordan Brown goto err; 909928e1f97SJordan Brown domains = tmp; 9104d61c878SJulian Pullen } 911928e1f97SJordan Brown 912928e1f97SJordan Brown if (result != NULL) 913148c5f43SAlan Wright (void) ldap_msgfree(result); 9144d61c878SJulian Pullen 9154d61c878SJulian Pullen return (domains); 916928e1f97SJordan Brown 917928e1f97SJordan Brown err: 918928e1f97SJordan Brown free(domains); 919928e1f97SJordan Brown if (result != NULL) 920148c5f43SAlan Wright (void) ldap_msgfree(result); 921928e1f97SJordan Brown return (NULL); 9224d61c878SJulian Pullen } 9234d61c878SJulian Pullen 924c8e26105Sjp 925c8e26105Sjp ad_disc_t 926c8e26105Sjp ad_disc_init(void) 927c8e26105Sjp { 928c8e26105Sjp struct ad_disc *ctx; 929c8e26105Sjp ctx = calloc(1, sizeof (struct ad_disc)); 9300dcc7149Snw if (ctx != NULL) 9310dcc7149Snw DO_RES_NINIT(ctx); 9324d61c878SJulian Pullen 9334d61c878SJulian Pullen ctx->domain_name.type = AD_STRING; 934b3700b07SGordon Ross ctx->domain_guid.type = AD_UUID; 9354d61c878SJulian Pullen ctx->domain_controller.type = AD_DIRECTORY; 936b3700b07SGordon Ross ctx->preferred_dc.type = AD_DIRECTORY; 9374d61c878SJulian Pullen ctx->site_name.type = AD_STRING; 9384d61c878SJulian Pullen ctx->forest_name.type = AD_STRING; 9394d61c878SJulian Pullen ctx->global_catalog.type = AD_DIRECTORY; 9404d61c878SJulian Pullen ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST; 9414d61c878SJulian Pullen ctx->trusted_domains.type = AD_TRUSTED_DOMAINS; 9424d61c878SJulian Pullen /* Site specific versions */ 9434d61c878SJulian Pullen ctx->site_domain_controller.type = AD_DIRECTORY; 9444d61c878SJulian Pullen ctx->site_global_catalog.type = AD_DIRECTORY; 945c8e26105Sjp return (ctx); 946c8e26105Sjp } 947c8e26105Sjp 948c8e26105Sjp void 949c8e26105Sjp ad_disc_fini(ad_disc_t ctx) 950c8e26105Sjp { 951cd37da74Snw if (ctx == NULL) 952cd37da74Snw return; 953cd37da74Snw 9540dcc7149Snw if (ctx->res_ninitted) 9554d61c878SJulian Pullen res_ndestroy(&ctx->res_state); 956c8e26105Sjp 957c8e26105Sjp if (ctx->subnets != NULL) 958c8e26105Sjp free(ctx->subnets); 959c8e26105Sjp 9604d61c878SJulian Pullen if (ctx->domain_name.value != NULL) 9614d61c878SJulian Pullen free(ctx->domain_name.value); 9624d61c878SJulian Pullen 963b3700b07SGordon Ross if (ctx->domain_guid.value != NULL) 964b3700b07SGordon Ross free(ctx->domain_guid.value); 965b3700b07SGordon Ross 9664d61c878SJulian Pullen if (ctx->domain_controller.value != NULL) 9674d61c878SJulian Pullen free(ctx->domain_controller.value); 9684d61c878SJulian Pullen 969b3700b07SGordon Ross if (ctx->preferred_dc.value != NULL) 970b3700b07SGordon Ross free(ctx->preferred_dc.value); 971b3700b07SGordon Ross 9724d61c878SJulian Pullen if (ctx->site_name.value != NULL) 9734d61c878SJulian Pullen free(ctx->site_name.value); 974c8e26105Sjp 9754d61c878SJulian Pullen if (ctx->forest_name.value != NULL) 9764d61c878SJulian Pullen free(ctx->forest_name.value); 977c8e26105Sjp 9784d61c878SJulian Pullen if (ctx->global_catalog.value != NULL) 9794d61c878SJulian Pullen free(ctx->global_catalog.value); 980c8e26105Sjp 9814d61c878SJulian Pullen if (ctx->domains_in_forest.value != NULL) 9824d61c878SJulian Pullen free(ctx->domains_in_forest.value); 983c8e26105Sjp 9844d61c878SJulian Pullen if (ctx->trusted_domains.value != NULL) 9854d61c878SJulian Pullen free(ctx->trusted_domains.value); 986c8e26105Sjp 9874d61c878SJulian Pullen /* Site specific versions */ 9884d61c878SJulian Pullen if (ctx->site_domain_controller.value != NULL) 9894d61c878SJulian Pullen free(ctx->site_domain_controller.value); 990c8e26105Sjp 9914d61c878SJulian Pullen if (ctx->site_global_catalog.value != NULL) 9924d61c878SJulian Pullen free(ctx->site_global_catalog.value); 993c8e26105Sjp 994c8e26105Sjp free(ctx); 995c8e26105Sjp } 996c8e26105Sjp 997c8e26105Sjp void 998c8e26105Sjp ad_disc_refresh(ad_disc_t ctx) 999c8e26105Sjp { 1000b3700b07SGordon Ross if (ctx->res_ninitted) { 10014d61c878SJulian Pullen res_ndestroy(&ctx->res_state); 1002b3700b07SGordon Ross ctx->res_ninitted = 0; 1003b3700b07SGordon Ross } 10044d61c878SJulian Pullen (void) memset(&ctx->res_state, 0, sizeof (ctx->res_state)); 1005b3700b07SGordon Ross DO_RES_NINIT(ctx); 1006c8e26105Sjp 10074d61c878SJulian Pullen if (ctx->domain_name.state == AD_STATE_AUTO) 10084d61c878SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 1009c8e26105Sjp 1010b3700b07SGordon Ross if (ctx->domain_guid.state == AD_STATE_AUTO) 1011b3700b07SGordon Ross ctx->domain_guid.state = AD_STATE_INVALID; 1012b3700b07SGordon Ross 10134d61c878SJulian Pullen if (ctx->domain_controller.state == AD_STATE_AUTO) 10144d61c878SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 1015c8e26105Sjp 1016b3700b07SGordon Ross if (ctx->preferred_dc.state == AD_STATE_AUTO) 1017b3700b07SGordon Ross ctx->preferred_dc.state = AD_STATE_INVALID; 1018b3700b07SGordon Ross 10194d61c878SJulian Pullen if (ctx->site_name.state == AD_STATE_AUTO) 10204d61c878SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 1021c8e26105Sjp 10224d61c878SJulian Pullen if (ctx->forest_name.state == AD_STATE_AUTO) 10234d61c878SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 1024c8e26105Sjp 10254d61c878SJulian Pullen if (ctx->global_catalog.state == AD_STATE_AUTO) 10264d61c878SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 1027c8e26105Sjp 10284d61c878SJulian Pullen if (ctx->domains_in_forest.state == AD_STATE_AUTO) 10294d61c878SJulian Pullen ctx->domains_in_forest.state = AD_STATE_INVALID; 1030c8e26105Sjp 10314d61c878SJulian Pullen if (ctx->trusted_domains.state == AD_STATE_AUTO) 10324d61c878SJulian Pullen ctx->trusted_domains.state = AD_STATE_INVALID; 10334d61c878SJulian Pullen 10344d61c878SJulian Pullen if (ctx->site_domain_controller.state == AD_STATE_AUTO) 10354d61c878SJulian Pullen ctx->site_domain_controller.state = AD_STATE_INVALID; 10364d61c878SJulian Pullen 10374d61c878SJulian Pullen if (ctx->site_global_catalog.state == AD_STATE_AUTO) 10384d61c878SJulian Pullen ctx->site_global_catalog.state = AD_STATE_INVALID; 1039c8e26105Sjp } 1040c8e26105Sjp 1041c8e26105Sjp 1042c5866007SKeyur Desai /* 1043c5866007SKeyur Desai * Called when the discovery cycle is done. Sets a master TTL 1044c5866007SKeyur Desai * that will avoid doing new time-based discoveries too soon after 1045c5866007SKeyur Desai * the last discovery cycle. Most interesting when the discovery 1046c5866007SKeyur Desai * cycle failed, because then the TTLs on the individual items will 1047c5866007SKeyur Desai * not be updated and may go stale. 1048c5866007SKeyur Desai */ 1049c5866007SKeyur Desai void 1050c5866007SKeyur Desai ad_disc_done(ad_disc_t ctx) 1051c5866007SKeyur Desai { 1052c5866007SKeyur Desai time_t now = time(NULL); 1053c5866007SKeyur Desai 1054c5866007SKeyur Desai ctx->expires_not_before = now + MINIMUM_TTL; 1055c5866007SKeyur Desai ctx->expires_not_after = now + MAXIMUM_TTL; 1056c5866007SKeyur Desai } 1057c5866007SKeyur Desai 1058b3700b07SGordon Ross static void 1059b3700b07SGordon Ross log_cds(ad_disc_t ctx, ad_disc_cds_t *cds) 1060b3700b07SGordon Ross { 1061b3700b07SGordon Ross char buf[INET6_ADDRSTRLEN]; 1062b3700b07SGordon Ross struct addrinfo *ai; 1063b3700b07SGordon Ross 1064b3700b07SGordon Ross if (!DBG(DISC, 1) && ctx->status_fp == NULL) 1065b3700b07SGordon Ross return; 1066b3700b07SGordon Ross 1067b3700b07SGordon Ross DEBUG1STATUS(ctx, "Candidate servers:"); 1068b3700b07SGordon Ross if (cds->cds_ds.host[0] == '\0') { 1069b3700b07SGordon Ross DEBUG1STATUS(ctx, " (empty list)"); 1070b3700b07SGordon Ross return; 1071b3700b07SGordon Ross } 1072b3700b07SGordon Ross 1073b3700b07SGordon Ross while (cds->cds_ds.host[0] != '\0') { 1074b3700b07SGordon Ross 1075b3700b07SGordon Ross DEBUG1STATUS(ctx, " %s p=%d w=%d", 1076b3700b07SGordon Ross cds->cds_ds.host, 1077b3700b07SGordon Ross cds->cds_ds.priority, 1078b3700b07SGordon Ross cds->cds_ds.weight); 1079b3700b07SGordon Ross 1080b3700b07SGordon Ross ai = cds->cds_ai; 1081b3700b07SGordon Ross if (ai == NULL) { 1082b3700b07SGordon Ross DEBUG1STATUS(ctx, " (no address)"); 1083b3700b07SGordon Ross } 1084b3700b07SGordon Ross while (ai != NULL) { 1085b3700b07SGordon Ross int eai; 1086b3700b07SGordon Ross 1087b3700b07SGordon Ross eai = getnameinfo(ai->ai_addr, ai->ai_addrlen, 1088b3700b07SGordon Ross buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); 1089b3700b07SGordon Ross if (eai != 0) 1090b3700b07SGordon Ross (void) strlcpy(buf, "?", sizeof (buf)); 1091b3700b07SGordon Ross 1092b3700b07SGordon Ross DEBUG1STATUS(ctx, " %s", buf); 1093b3700b07SGordon Ross ai = ai->ai_next; 1094b3700b07SGordon Ross } 1095b3700b07SGordon Ross cds++; 1096b3700b07SGordon Ross } 1097b3700b07SGordon Ross } 1098b3700b07SGordon Ross 1099b3700b07SGordon Ross static void 1100b3700b07SGordon Ross log_ds(ad_disc_t ctx, ad_disc_ds_t *ds) 1101b3700b07SGordon Ross { 1102b3700b07SGordon Ross char buf[INET6_ADDRSTRLEN]; 1103b3700b07SGordon Ross 1104b3700b07SGordon Ross if (!DBG(DISC, 1) && ctx->status_fp == NULL) 1105b3700b07SGordon Ross return; 1106b3700b07SGordon Ross 1107b3700b07SGordon Ross DEBUG1STATUS(ctx, "Responding servers:"); 1108b3700b07SGordon Ross if (ds->host[0] == '\0') { 1109b3700b07SGordon Ross DEBUG1STATUS(ctx, " (empty list)"); 1110b3700b07SGordon Ross return; 1111b3700b07SGordon Ross } 1112b3700b07SGordon Ross 1113b3700b07SGordon Ross while (ds->host[0] != '\0') { 1114b3700b07SGordon Ross 1115b3700b07SGordon Ross DEBUG1STATUS(ctx, " %s", ds->host); 1116b3700b07SGordon Ross DO_GETNAMEINFO(buf, sizeof (buf), &ds->addr); 1117b3700b07SGordon Ross DEBUG1STATUS(ctx, " %s", buf); 1118b3700b07SGordon Ross 1119b3700b07SGordon Ross ds++; 1120b3700b07SGordon Ross } 1121b3700b07SGordon Ross } 1122c8e26105Sjp 11230dcc7149Snw /* Discover joined Active Directory domainName */ 11244d61c878SJulian Pullen static ad_item_t * 1125c8e26105Sjp validate_DomainName(ad_disc_t ctx) 1126c8e26105Sjp { 1127c8e26105Sjp char *dname, *srvname; 1128b3700b07SGordon Ross int len, rc; 1129c8e26105Sjp 11304d61c878SJulian Pullen if (is_valid(&ctx->domain_name)) 11314d61c878SJulian Pullen return (&ctx->domain_name); 1132c8e26105Sjp 1133c8e26105Sjp 1134c8e26105Sjp /* Try to find our domain by searching for DCs for it */ 11350dcc7149Snw DO_RES_NINIT(ctx); 1136b3700b07SGordon Ross if (DBG(DISC, 1)) 1137148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for our AD domain name..."); 1138b3700b07SGordon Ross rc = srv_getdom(&ctx->res_state, 1139b3700b07SGordon Ross LDAP_SRV_HEAD DC_SRV_TAIL, &srvname); 1140c8e26105Sjp 1141c8e26105Sjp /* 1142c8e26105Sjp * If we can't find DCs by via res_nsearch() then there's no 1143c8e26105Sjp * point in trying anything else to discover the AD domain name. 1144c8e26105Sjp */ 1145b3700b07SGordon Ross if (rc < 0) { 1146148c5f43SAlan Wright if (DBG(DISC, 1)) 1147148c5f43SAlan Wright logger(LOG_DEBUG, "Can't find our domain name."); 11484d61c878SJulian Pullen return (NULL); 1149148c5f43SAlan Wright } 1150c8e26105Sjp 1151c8e26105Sjp /* 1152c8e26105Sjp * We have the FQDN of the SRV RR name, so now we extract the 1153c8e26105Sjp * domainname suffix from it. 1154c8e26105Sjp */ 1155c8e26105Sjp dname = strdup(srvname + strlen(LDAP_SRV_HEAD DC_SRV_TAIL) + 1156c8e26105Sjp 1 /* for the dot between RR name and domainname */); 1157c8e26105Sjp 1158c8e26105Sjp free(srvname); 1159c8e26105Sjp 1160c8e26105Sjp if (dname == NULL) { 11617a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 11624d61c878SJulian Pullen return (NULL); 1163c8e26105Sjp } 1164c8e26105Sjp 1165c8e26105Sjp /* Eat any trailing dot */ 1166928e1f97SJordan Brown len = strlen(dname); 11671fcced4cSJordan Brown if (len > 0 && dname[len - 1] == '.') 11681fcced4cSJordan Brown dname[len - 1] = '\0'; 1169c8e26105Sjp 1170148c5f43SAlan Wright if (DBG(DISC, 1)) 1171148c5f43SAlan Wright logger(LOG_DEBUG, "Our domain name: %s", dname); 1172b3700b07SGordon Ross 1173b3700b07SGordon Ross /* 1174b3700b07SGordon Ross * There is no "time to live" on the discovered domain, 1175b3700b07SGordon Ross * so passing zero as TTL here, making it non-expiring. 1176b3700b07SGordon Ross * Note that current consumers do not auto-discover the 1177b3700b07SGordon Ross * domain name, though a future installer could. 1178b3700b07SGordon Ross */ 1179b3700b07SGordon Ross update_item(&ctx->domain_name, dname, AD_STATE_AUTO, 0); 11804d61c878SJulian Pullen 11814d61c878SJulian Pullen return (&ctx->domain_name); 1182c8e26105Sjp } 1183c8e26105Sjp 1184c8e26105Sjp 1185c8e26105Sjp char * 11867a8a68f5SJulian Pullen ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered) 1187c8e26105Sjp { 1188c8e26105Sjp char *domain_name = NULL; 11894d61c878SJulian Pullen ad_item_t *domain_name_item; 1190c8e26105Sjp 11914d61c878SJulian Pullen domain_name_item = validate_DomainName(ctx); 11924d61c878SJulian Pullen 11934d61c878SJulian Pullen if (domain_name_item) { 11944d61c878SJulian Pullen domain_name = strdup(domain_name_item->value); 11954d61c878SJulian Pullen if (auto_discovered != NULL) 11964d61c878SJulian Pullen *auto_discovered = 11974d61c878SJulian Pullen (domain_name_item->state == AD_STATE_AUTO); 11984d61c878SJulian Pullen } else if (auto_discovered != NULL) 11997a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1200c8e26105Sjp 1201c8e26105Sjp return (domain_name); 1202c8e26105Sjp } 1203c8e26105Sjp 1204c8e26105Sjp 12050dcc7149Snw /* Discover domain controllers */ 12064d61c878SJulian Pullen static ad_item_t * 1207c8e26105Sjp validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) 1208c8e26105Sjp { 1209b3700b07SGordon Ross ad_disc_ds_t *dc = NULL; 1210b3700b07SGordon Ross ad_disc_cds_t *cdc = NULL; 12117a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 12127a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 12134d61c878SJulian Pullen ad_item_t *domain_name_item; 1214b3700b07SGordon Ross char *domain_name; 12154d61c878SJulian Pullen ad_item_t *site_name_item = NULL; 1216b3700b07SGordon Ross char *site_name; 1217b3700b07SGordon Ross ad_item_t *prefer_dc_item; 1218b3700b07SGordon Ross ad_disc_ds_t *prefer_dc = NULL; 1219c8e26105Sjp 12204d61c878SJulian Pullen /* If the values is fixed there will not be a site specific version */ 1221c8e26105Sjp if (is_fixed(&ctx->domain_controller)) 12224d61c878SJulian Pullen return (&ctx->domain_controller); 12234d61c878SJulian Pullen 12244d61c878SJulian Pullen domain_name_item = validate_DomainName(ctx); 1225*d0bed8f2SGordon Ross if (domain_name_item == NULL) { 1226*d0bed8f2SGordon Ross DEBUG1STATUS(ctx, "(no domain name)"); 12274d61c878SJulian Pullen return (NULL); 1228*d0bed8f2SGordon Ross } 1229b3700b07SGordon Ross domain_name = (char *)domain_name_item->value; 1230b3700b07SGordon Ross 1231b3700b07SGordon Ross /* Get (optional) preferred DC. */ 1232b3700b07SGordon Ross prefer_dc_item = validate_PreferredDC(ctx); 1233b3700b07SGordon Ross if (prefer_dc_item != NULL) 1234b3700b07SGordon Ross prefer_dc = prefer_dc_item->value; 1235c8e26105Sjp 1236c8e26105Sjp if (req == AD_DISC_GLOBAL) 12377a8a68f5SJulian Pullen validate_global = B_TRUE; 1238c8e26105Sjp else { 1239b3700b07SGordon Ross if (is_fixed(&ctx->site_name)) 12407a8a68f5SJulian Pullen validate_site = B_TRUE; 1241*d0bed8f2SGordon Ross if (req == AD_DISC_PREFER_SITE) 12427a8a68f5SJulian Pullen validate_global = B_TRUE; 1243c8e26105Sjp } 1244c8e26105Sjp 1245*d0bed8f2SGordon Ross /* 1246*d0bed8f2SGordon Ross * If we're trying both site-specific and global, 1247*d0bed8f2SGordon Ross * try the site-specific first, then fall-back. 1248*d0bed8f2SGordon Ross */ 1249*d0bed8f2SGordon Ross if (validate_site) { 1250*d0bed8f2SGordon Ross site_name_item = &ctx->site_name; 1251*d0bed8f2SGordon Ross site_name = (char *)site_name_item->value; 1252*d0bed8f2SGordon Ross 1253*d0bed8f2SGordon Ross if (!is_valid(&ctx->site_domain_controller) || 1254*d0bed8f2SGordon Ross is_changed(&ctx->site_domain_controller, PARAM1, 1255*d0bed8f2SGordon Ross domain_name_item) || 1256*d0bed8f2SGordon Ross is_changed(&ctx->site_domain_controller, PARAM2, 1257*d0bed8f2SGordon Ross site_name_item)) { 1258*d0bed8f2SGordon Ross char rr_name[DNS_MAX_NAME]; 1259b3700b07SGordon Ross 1260c8e26105Sjp /* 12610dcc7149Snw * Lookup DNS SRV RR named 1262*d0bed8f2SGordon Ross * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName> 1263c8e26105Sjp */ 1264*d0bed8f2SGordon Ross DEBUG1STATUS(ctx, "DNS SRV query, dom=%s, site=%s", 1265*d0bed8f2SGordon Ross domain_name, site_name); 1266*d0bed8f2SGordon Ross (void) snprintf(rr_name, sizeof (rr_name), 1267*d0bed8f2SGordon Ross LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, 1268*d0bed8f2SGordon Ross site_name); 12690dcc7149Snw DO_RES_NINIT(ctx); 1270*d0bed8f2SGordon Ross cdc = srv_query(&ctx->res_state, rr_name, 1271b3700b07SGordon Ross domain_name, prefer_dc); 1272c8e26105Sjp 1273b3700b07SGordon Ross if (cdc == NULL) { 1274b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no DNS response)"); 1275*d0bed8f2SGordon Ross goto try_global; 1276148c5f43SAlan Wright } 1277b3700b07SGordon Ross log_cds(ctx, cdc); 1278148c5f43SAlan Wright 1279b3700b07SGordon Ross /* 1280b3700b07SGordon Ross * Filter out unresponsive servers, and 1281b3700b07SGordon Ross * save the domain info we get back. 1282b3700b07SGordon Ross */ 1283b3700b07SGordon Ross dc = ldap_ping( 1284b3700b07SGordon Ross ctx, 1285b3700b07SGordon Ross cdc, 1286b3700b07SGordon Ross domain_name, 1287b3700b07SGordon Ross DS_DS_FLAG); 1288b3700b07SGordon Ross srv_free(cdc); 1289b3700b07SGordon Ross cdc = NULL; 1290b3700b07SGordon Ross 1291b3700b07SGordon Ross if (dc == NULL) { 1292b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no LDAP response)"); 1293*d0bed8f2SGordon Ross goto try_global; 1294148c5f43SAlan Wright } 1295b3700b07SGordon Ross log_ds(ctx, dc); 1296c8e26105Sjp 1297*d0bed8f2SGordon Ross update_item(&ctx->site_domain_controller, dc, 1298b3700b07SGordon Ross AD_STATE_AUTO, dc->ttl); 1299*d0bed8f2SGordon Ross update_version(&ctx->site_domain_controller, PARAM1, 13004d61c878SJulian Pullen domain_name_item); 1301*d0bed8f2SGordon Ross update_version(&ctx->site_domain_controller, PARAM2, 1302*d0bed8f2SGordon Ross site_name_item); 13034d61c878SJulian Pullen } 1304*d0bed8f2SGordon Ross return (&ctx->site_domain_controller); 13054d61c878SJulian Pullen } 1306c8e26105Sjp 1307*d0bed8f2SGordon Ross try_global: 1308b3700b07SGordon Ross 1309*d0bed8f2SGordon Ross if (validate_global) { 1310*d0bed8f2SGordon Ross if (!is_valid(&ctx->domain_controller) || 1311*d0bed8f2SGordon Ross is_changed(&ctx->domain_controller, PARAM1, 1312*d0bed8f2SGordon Ross domain_name_item)) { 1313b3700b07SGordon Ross 1314c8e26105Sjp /* 13150dcc7149Snw * Lookup DNS SRV RR named 1316*d0bed8f2SGordon Ross * _ldap._tcp.dc._msdcs.<DomainName> 1317c8e26105Sjp */ 1318*d0bed8f2SGordon Ross DEBUG1STATUS(ctx, "DNS SRV query, dom=%s", 1319*d0bed8f2SGordon Ross domain_name); 13200dcc7149Snw DO_RES_NINIT(ctx); 1321*d0bed8f2SGordon Ross cdc = srv_query(&ctx->res_state, 1322*d0bed8f2SGordon Ross LDAP_SRV_HEAD DC_SRV_TAIL, 1323b3700b07SGordon Ross domain_name, prefer_dc); 1324b3700b07SGordon Ross 1325b3700b07SGordon Ross if (cdc == NULL) { 1326b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no DNS response)"); 13274d61c878SJulian Pullen return (NULL); 1328148c5f43SAlan Wright } 1329b3700b07SGordon Ross log_cds(ctx, cdc); 1330148c5f43SAlan Wright 1331b3700b07SGordon Ross /* 1332b3700b07SGordon Ross * Filter out unresponsive servers, and 1333b3700b07SGordon Ross * save the domain info we get back. 1334b3700b07SGordon Ross */ 1335b3700b07SGordon Ross dc = ldap_ping( 1336b3700b07SGordon Ross ctx, 1337b3700b07SGordon Ross cdc, 1338b3700b07SGordon Ross domain_name, 1339b3700b07SGordon Ross DS_DS_FLAG); 1340b3700b07SGordon Ross srv_free(cdc); 1341b3700b07SGordon Ross cdc = NULL; 1342b3700b07SGordon Ross 1343b3700b07SGordon Ross if (dc == NULL) { 1344b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no LDAP response)"); 1345b3700b07SGordon Ross return (NULL); 1346148c5f43SAlan Wright } 1347b3700b07SGordon Ross log_ds(ctx, dc); 13484d61c878SJulian Pullen 1349*d0bed8f2SGordon Ross update_item(&ctx->domain_controller, dc, 1350b3700b07SGordon Ross AD_STATE_AUTO, dc->ttl); 1351*d0bed8f2SGordon Ross update_version(&ctx->domain_controller, PARAM1, 13524d61c878SJulian Pullen domain_name_item); 1353c8e26105Sjp } 1354*d0bed8f2SGordon Ross return (&ctx->domain_controller); 1355c8e26105Sjp } 1356*d0bed8f2SGordon Ross 13574d61c878SJulian Pullen return (NULL); 1358c8e26105Sjp } 1359c8e26105Sjp 1360b3700b07SGordon Ross ad_disc_ds_t * 13614d61c878SJulian Pullen ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, 1362b3700b07SGordon Ross boolean_t *auto_discovered) 1363c8e26105Sjp { 13644d61c878SJulian Pullen ad_item_t *domain_controller_item; 1365b3700b07SGordon Ross ad_disc_ds_t *domain_controller = NULL; 1366c8e26105Sjp 13674d61c878SJulian Pullen domain_controller_item = validate_DomainController(ctx, req); 13684d61c878SJulian Pullen 13694d61c878SJulian Pullen if (domain_controller_item != NULL) { 13704d61c878SJulian Pullen domain_controller = ds_dup(domain_controller_item->value); 13714d61c878SJulian Pullen if (auto_discovered != NULL) 13724d61c878SJulian Pullen *auto_discovered = 13734d61c878SJulian Pullen (domain_controller_item->state == AD_STATE_AUTO); 13744d61c878SJulian Pullen } else if (auto_discovered != NULL) 13757a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 13764d61c878SJulian Pullen 1377c8e26105Sjp return (domain_controller); 1378c8e26105Sjp } 1379c8e26105Sjp 1380c8e26105Sjp 1381b3700b07SGordon Ross /* 1382b3700b07SGordon Ross * Discover the Domain GUID 1383b3700b07SGordon Ross * This info comes from validate_DomainController() 1384b3700b07SGordon Ross */ 13854d61c878SJulian Pullen static ad_item_t * 1386b3700b07SGordon Ross validate_DomainGUID(ad_disc_t ctx) 1387c8e26105Sjp { 13884d61c878SJulian Pullen ad_item_t *domain_controller_item; 1389c8e26105Sjp 1390b3700b07SGordon Ross if (is_fixed(&ctx->domain_guid)) 1391b3700b07SGordon Ross return (&ctx->domain_guid); 1392c8e26105Sjp 13934d61c878SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 13944d61c878SJulian Pullen if (domain_controller_item == NULL) 13954d61c878SJulian Pullen return (NULL); 1396c8e26105Sjp 1397b3700b07SGordon Ross if (!is_valid(&ctx->domain_guid)) 13984d61c878SJulian Pullen return (NULL); 13990dcc7149Snw 1400b3700b07SGordon Ross return (&ctx->domain_guid); 1401b3700b07SGordon Ross } 14020dcc7149Snw 1403148c5f43SAlan Wright 1404b3700b07SGordon Ross uchar_t * 1405b3700b07SGordon Ross ad_disc_get_DomainGUID(ad_disc_t ctx, boolean_t *auto_discovered) 1406b3700b07SGordon Ross { 1407b3700b07SGordon Ross ad_item_t *domain_guid_item; 1408b3700b07SGordon Ross uchar_t *domain_guid = NULL; 14094d61c878SJulian Pullen 1410b3700b07SGordon Ross domain_guid_item = validate_DomainGUID(ctx); 1411b3700b07SGordon Ross if (domain_guid_item != NULL) { 1412b3700b07SGordon Ross domain_guid = uuid_dup(domain_guid_item->value); 1413b3700b07SGordon Ross if (auto_discovered != NULL) 1414b3700b07SGordon Ross *auto_discovered = 1415b3700b07SGordon Ross (domain_guid_item->state == AD_STATE_AUTO); 1416b3700b07SGordon Ross } else if (auto_discovered != NULL) 1417b3700b07SGordon Ross *auto_discovered = B_FALSE; 1418148c5f43SAlan Wright 1419b3700b07SGordon Ross return (domain_guid); 1420b3700b07SGordon Ross } 1421148c5f43SAlan Wright 1422c8e26105Sjp 1423b3700b07SGordon Ross /* 1424b3700b07SGordon Ross * Discover site name (for multi-homed systems the first one found wins) 1425b3700b07SGordon Ross * This info comes from validate_DomainController() 1426b3700b07SGordon Ross */ 1427b3700b07SGordon Ross static ad_item_t * 1428b3700b07SGordon Ross validate_SiteName(ad_disc_t ctx) 1429b3700b07SGordon Ross { 1430b3700b07SGordon Ross ad_item_t *domain_controller_item; 14314d61c878SJulian Pullen 1432b3700b07SGordon Ross if (is_fixed(&ctx->site_name)) 1433b3700b07SGordon Ross return (&ctx->site_name); 1434c8e26105Sjp 1435b3700b07SGordon Ross domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1436b3700b07SGordon Ross if (domain_controller_item == NULL) 1437b3700b07SGordon Ross return (NULL); 14380dcc7149Snw 1439b3700b07SGordon Ross if (!is_valid(&ctx->site_name)) 14404d61c878SJulian Pullen return (NULL); 1441c8e26105Sjp 1442b3700b07SGordon Ross return (&ctx->site_name); 1443c8e26105Sjp } 1444c8e26105Sjp 1445c8e26105Sjp 1446c8e26105Sjp char * 14477a8a68f5SJulian Pullen ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered) 1448c8e26105Sjp { 14494d61c878SJulian Pullen ad_item_t *site_name_item; 1450c8e26105Sjp char *site_name = NULL; 1451c8e26105Sjp 14524d61c878SJulian Pullen site_name_item = validate_SiteName(ctx); 14534d61c878SJulian Pullen if (site_name_item != NULL) { 14544d61c878SJulian Pullen site_name = strdup(site_name_item->value); 14554d61c878SJulian Pullen if (auto_discovered != NULL) 14564d61c878SJulian Pullen *auto_discovered = 14574d61c878SJulian Pullen (site_name_item->state == AD_STATE_AUTO); 14584d61c878SJulian Pullen } else if (auto_discovered != NULL) 14597a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 14604d61c878SJulian Pullen 1461c8e26105Sjp return (site_name); 1462c8e26105Sjp } 1463c8e26105Sjp 1464c8e26105Sjp 1465c8e26105Sjp 1466b3700b07SGordon Ross /* 1467b3700b07SGordon Ross * Discover forest name 1468b3700b07SGordon Ross * This info comes from validate_DomainController() 1469b3700b07SGordon Ross */ 14704d61c878SJulian Pullen static ad_item_t * 1471c8e26105Sjp validate_ForestName(ad_disc_t ctx) 1472c8e26105Sjp { 14734d61c878SJulian Pullen ad_item_t *domain_controller_item; 1474c8e26105Sjp 1475c8e26105Sjp if (is_fixed(&ctx->forest_name)) 14764d61c878SJulian Pullen return (&ctx->forest_name); 1477b3700b07SGordon Ross 14784d61c878SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 14794d61c878SJulian Pullen if (domain_controller_item == NULL) 14804d61c878SJulian Pullen return (NULL); 1481c8e26105Sjp 1482b3700b07SGordon Ross if (!is_valid(&ctx->forest_name)) 1483b3700b07SGordon Ross return (NULL); 14844d61c878SJulian Pullen 14854d61c878SJulian Pullen return (&ctx->forest_name); 1486c8e26105Sjp } 1487c8e26105Sjp 1488c8e26105Sjp 1489c8e26105Sjp char * 14907a8a68f5SJulian Pullen ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered) 1491c8e26105Sjp { 14924d61c878SJulian Pullen ad_item_t *forest_name_item; 1493c8e26105Sjp char *forest_name = NULL; 1494c8e26105Sjp 14954d61c878SJulian Pullen forest_name_item = validate_ForestName(ctx); 14964d61c878SJulian Pullen 14974d61c878SJulian Pullen if (forest_name_item != NULL) { 14984d61c878SJulian Pullen forest_name = strdup(forest_name_item->value); 14994d61c878SJulian Pullen if (auto_discovered != NULL) 15004d61c878SJulian Pullen *auto_discovered = 15014d61c878SJulian Pullen (forest_name_item->state == AD_STATE_AUTO); 15024d61c878SJulian Pullen } else if (auto_discovered != NULL) 15037a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1504c8e26105Sjp 1505c8e26105Sjp return (forest_name); 1506c8e26105Sjp } 1507c8e26105Sjp 1508c8e26105Sjp 15090dcc7149Snw /* Discover global catalog servers */ 15104d61c878SJulian Pullen static ad_item_t * 1511c8e26105Sjp validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) 1512c8e26105Sjp { 1513b3700b07SGordon Ross ad_disc_ds_t *gc = NULL; 1514b3700b07SGordon Ross ad_disc_cds_t *cgc = NULL; 15157a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 15167a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 1517b3700b07SGordon Ross ad_item_t *dc_item; 15184d61c878SJulian Pullen ad_item_t *forest_name_item; 15194d61c878SJulian Pullen ad_item_t *site_name_item; 1520b3700b07SGordon Ross char *forest_name; 1521b3700b07SGordon Ross char *site_name; 1522c8e26105Sjp 15234d61c878SJulian Pullen /* If the values is fixed there will not be a site specific version */ 1524c8e26105Sjp if (is_fixed(&ctx->global_catalog)) 15254d61c878SJulian Pullen return (&ctx->global_catalog); 15264d61c878SJulian Pullen 15274d61c878SJulian Pullen forest_name_item = validate_ForestName(ctx); 1528*d0bed8f2SGordon Ross if (forest_name_item == NULL) { 1529*d0bed8f2SGordon Ross DEBUG1STATUS(ctx, "(no forrest name)"); 15304d61c878SJulian Pullen return (NULL); 1531*d0bed8f2SGordon Ross } 1532b3700b07SGordon Ross forest_name = (char *)forest_name_item->value; 1533c8e26105Sjp 1534c8e26105Sjp if (req == AD_DISC_GLOBAL) 15357a8a68f5SJulian Pullen validate_global = B_TRUE; 1536c8e26105Sjp else { 1537b3700b07SGordon Ross if (is_fixed(&ctx->site_name)) 15387a8a68f5SJulian Pullen validate_site = B_TRUE; 1539*d0bed8f2SGordon Ross if (req == AD_DISC_PREFER_SITE) 15407a8a68f5SJulian Pullen validate_global = B_TRUE; 1541c8e26105Sjp } 1542c8e26105Sjp 1543*d0bed8f2SGordon Ross /* 1544*d0bed8f2SGordon Ross * If we're trying both site-specific and global, 1545*d0bed8f2SGordon Ross * try the site-specific first, then fall-back. 1546*d0bed8f2SGordon Ross */ 1547*d0bed8f2SGordon Ross if (validate_site) { 1548*d0bed8f2SGordon Ross site_name_item = &ctx->site_name; 1549*d0bed8f2SGordon Ross site_name = (char *)site_name_item->value; 1550*d0bed8f2SGordon Ross 1551*d0bed8f2SGordon Ross if (!is_valid(&ctx->site_global_catalog) || 1552*d0bed8f2SGordon Ross is_changed(&ctx->site_global_catalog, PARAM1, 1553*d0bed8f2SGordon Ross forest_name_item) || 1554*d0bed8f2SGordon Ross is_changed(&ctx->site_global_catalog, PARAM2, 1555*d0bed8f2SGordon Ross site_name_item)) { 1556*d0bed8f2SGordon Ross char rr_name[DNS_MAX_NAME]; 1557b3700b07SGordon Ross 1558c8e26105Sjp /* 1559b3700b07SGordon Ross * See if our DC is also a GC. 1560b3700b07SGordon Ross */ 1561b3700b07SGordon Ross dc_item = validate_DomainController(ctx, req); 1562b3700b07SGordon Ross if (dc_item != NULL) { 1563b3700b07SGordon Ross ad_disc_ds_t *ds = dc_item->value; 1564b3700b07SGordon Ross if ((ds->flags & DS_GC_FLAG) != 0) { 1565b3700b07SGordon Ross DEBUG1STATUS(ctx, 1566*d0bed8f2SGordon Ross "DC is also a GC for %s in %s", 1567*d0bed8f2SGordon Ross forest_name, site_name); 1568b3700b07SGordon Ross gc = ds_dup(ds); 1569b3700b07SGordon Ross if (gc != NULL) { 1570b3700b07SGordon Ross gc->port = GC_PORT; 1571*d0bed8f2SGordon Ross goto update_site; 1572b3700b07SGordon Ross } 1573b3700b07SGordon Ross } 1574b3700b07SGordon Ross } 1575b3700b07SGordon Ross 1576b3700b07SGordon Ross /* 1577b3700b07SGordon Ross * Lookup DNS SRV RR named: 1578*d0bed8f2SGordon Ross * _ldap._tcp.<siteName>._sites.gc. 1579*d0bed8f2SGordon Ross * _msdcs.<ForestName> 1580c8e26105Sjp */ 1581*d0bed8f2SGordon Ross DEBUG1STATUS(ctx, "DNS SRV query, forest=%s, site=%s", 1582*d0bed8f2SGordon Ross forest_name, site_name); 1583*d0bed8f2SGordon Ross (void) snprintf(rr_name, sizeof (rr_name), 1584*d0bed8f2SGordon Ross LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, 1585*d0bed8f2SGordon Ross site_name); 15860dcc7149Snw DO_RES_NINIT(ctx); 1587*d0bed8f2SGordon Ross cgc = srv_query(&ctx->res_state, rr_name, 1588b3700b07SGordon Ross forest_name, NULL); 1589c8e26105Sjp 1590b3700b07SGordon Ross if (cgc == NULL) { 1591b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no DNS response)"); 1592*d0bed8f2SGordon Ross goto try_global; 1593148c5f43SAlan Wright } 1594b3700b07SGordon Ross log_cds(ctx, cgc); 1595148c5f43SAlan Wright 1596b3700b07SGordon Ross /* 1597b3700b07SGordon Ross * Filter out unresponsive servers, and 1598b3700b07SGordon Ross * save the domain info we get back. 1599b3700b07SGordon Ross */ 1600b3700b07SGordon Ross gc = ldap_ping( 1601b3700b07SGordon Ross NULL, 1602b3700b07SGordon Ross cgc, 1603b3700b07SGordon Ross forest_name, 1604b3700b07SGordon Ross DS_GC_FLAG); 1605b3700b07SGordon Ross srv_free(cgc); 1606b3700b07SGordon Ross cgc = NULL; 1607b3700b07SGordon Ross 1608b3700b07SGordon Ross if (gc == NULL) { 1609b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no LDAP response)"); 1610*d0bed8f2SGordon Ross goto try_global; 1611148c5f43SAlan Wright } 1612b3700b07SGordon Ross log_ds(ctx, gc); 1613c8e26105Sjp 1614*d0bed8f2SGordon Ross update_site: 1615*d0bed8f2SGordon Ross update_item(&ctx->site_global_catalog, gc, 1616b3700b07SGordon Ross AD_STATE_AUTO, gc->ttl); 1617*d0bed8f2SGordon Ross update_version(&ctx->site_global_catalog, PARAM1, 16184d61c878SJulian Pullen forest_name_item); 1619*d0bed8f2SGordon Ross update_version(&ctx->site_global_catalog, PARAM2, 1620*d0bed8f2SGordon Ross site_name_item); 16214d61c878SJulian Pullen } 1622*d0bed8f2SGordon Ross return (&ctx->site_global_catalog); 16234d61c878SJulian Pullen } 1624c8e26105Sjp 1625*d0bed8f2SGordon Ross try_global: 1626b3700b07SGordon Ross 1627*d0bed8f2SGordon Ross if (validate_global) { 1628*d0bed8f2SGordon Ross if (!is_valid(&ctx->global_catalog) || 1629*d0bed8f2SGordon Ross is_changed(&ctx->global_catalog, PARAM1, 1630*d0bed8f2SGordon Ross forest_name_item)) { 1631b3700b07SGordon Ross 1632b3700b07SGordon Ross /* 1633b3700b07SGordon Ross * See if our DC is also a GC. 1634b3700b07SGordon Ross */ 1635b3700b07SGordon Ross dc_item = validate_DomainController(ctx, req); 1636b3700b07SGordon Ross if (dc_item != NULL) { 1637b3700b07SGordon Ross ad_disc_ds_t *ds = dc_item->value; 1638b3700b07SGordon Ross if ((ds->flags & DS_GC_FLAG) != 0) { 1639b3700b07SGordon Ross DEBUG1STATUS(ctx, 1640*d0bed8f2SGordon Ross "DC is also a GC for %s", 1641*d0bed8f2SGordon Ross forest_name); 1642b3700b07SGordon Ross gc = ds_dup(ds); 1643b3700b07SGordon Ross if (gc != NULL) { 1644b3700b07SGordon Ross gc->port = GC_PORT; 1645*d0bed8f2SGordon Ross goto update_global; 1646b3700b07SGordon Ross } 1647b3700b07SGordon Ross } 1648b3700b07SGordon Ross } 16494d61c878SJulian Pullen 1650c8e26105Sjp /* 16510dcc7149Snw * Lookup DNS SRV RR named: 1652*d0bed8f2SGordon Ross * _ldap._tcp.gc._msdcs.<ForestName> 1653c8e26105Sjp */ 1654*d0bed8f2SGordon Ross DEBUG1STATUS(ctx, "DNS SRV query, forest=%s", 1655*d0bed8f2SGordon Ross forest_name); 16560dcc7149Snw DO_RES_NINIT(ctx); 1657*d0bed8f2SGordon Ross cgc = srv_query(&ctx->res_state, 1658*d0bed8f2SGordon Ross LDAP_SRV_HEAD GC_SRV_TAIL, 1659b3700b07SGordon Ross forest_name, NULL); 16604d61c878SJulian Pullen 1661b3700b07SGordon Ross if (cgc == NULL) { 1662b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no DNS response)"); 16634d61c878SJulian Pullen return (NULL); 1664148c5f43SAlan Wright } 1665b3700b07SGordon Ross log_cds(ctx, cgc); 1666148c5f43SAlan Wright 1667b3700b07SGordon Ross /* 1668b3700b07SGordon Ross * Filter out unresponsive servers, and 1669b3700b07SGordon Ross * save the domain info we get back. 1670b3700b07SGordon Ross */ 1671b3700b07SGordon Ross gc = ldap_ping( 1672b3700b07SGordon Ross NULL, 1673b3700b07SGordon Ross cgc, 1674b3700b07SGordon Ross forest_name, 1675b3700b07SGordon Ross DS_GC_FLAG); 1676b3700b07SGordon Ross srv_free(cgc); 1677b3700b07SGordon Ross cgc = NULL; 1678b3700b07SGordon Ross 1679b3700b07SGordon Ross if (gc == NULL) { 1680b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no LDAP response)"); 1681b3700b07SGordon Ross return (NULL); 1682148c5f43SAlan Wright } 1683b3700b07SGordon Ross log_ds(ctx, gc); 1684148c5f43SAlan Wright 1685*d0bed8f2SGordon Ross update_global: 1686*d0bed8f2SGordon Ross update_item(&ctx->global_catalog, gc, 1687b3700b07SGordon Ross AD_STATE_AUTO, gc->ttl); 1688*d0bed8f2SGordon Ross update_version(&ctx->global_catalog, PARAM1, 16894d61c878SJulian Pullen forest_name_item); 1690c8e26105Sjp } 1691*d0bed8f2SGordon Ross return (&ctx->global_catalog); 1692c8e26105Sjp } 16934d61c878SJulian Pullen return (NULL); 1694c8e26105Sjp } 1695c8e26105Sjp 1696c8e26105Sjp 1697b3700b07SGordon Ross ad_disc_ds_t * 16984d61c878SJulian Pullen ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, 16997a8a68f5SJulian Pullen boolean_t *auto_discovered) 1700c8e26105Sjp { 1701b3700b07SGordon Ross ad_disc_ds_t *global_catalog = NULL; 17024d61c878SJulian Pullen ad_item_t *global_catalog_item; 17034d61c878SJulian Pullen 17044d61c878SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, req); 1705c8e26105Sjp 17064d61c878SJulian Pullen if (global_catalog_item != NULL) { 17074d61c878SJulian Pullen global_catalog = ds_dup(global_catalog_item->value); 17084d61c878SJulian Pullen if (auto_discovered != NULL) 17094d61c878SJulian Pullen *auto_discovered = 17104d61c878SJulian Pullen (global_catalog_item->state == AD_STATE_AUTO); 17114d61c878SJulian Pullen } else if (auto_discovered != NULL) 17127a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1713c8e26105Sjp 1714c8e26105Sjp return (global_catalog); 1715c8e26105Sjp } 1716c8e26105Sjp 1717c8e26105Sjp 17184d61c878SJulian Pullen static ad_item_t * 17194d61c878SJulian Pullen validate_TrustedDomains(ad_disc_t ctx) 17204d61c878SJulian Pullen { 17214d61c878SJulian Pullen LDAP *ld = NULL; 17224d61c878SJulian Pullen ad_item_t *global_catalog_item; 17234d61c878SJulian Pullen ad_item_t *forest_name_item; 17244d61c878SJulian Pullen ad_disc_trusteddomains_t *trusted_domains; 17254d61c878SJulian Pullen char *dn = NULL; 17264d61c878SJulian Pullen char *forest_name_dn; 17274d61c878SJulian Pullen int len; 17284d61c878SJulian Pullen int num_parts; 17294d61c878SJulian Pullen 17304d61c878SJulian Pullen if (is_fixed(&ctx->trusted_domains)) 17314d61c878SJulian Pullen return (&ctx->trusted_domains); 17324d61c878SJulian Pullen 17334d61c878SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 17344d61c878SJulian Pullen if (global_catalog_item == NULL) 17354d61c878SJulian Pullen return (NULL); 17364d61c878SJulian Pullen 17374d61c878SJulian Pullen forest_name_item = validate_ForestName(ctx); 17384d61c878SJulian Pullen if (forest_name_item == NULL) 17394d61c878SJulian Pullen return (NULL); 17404d61c878SJulian Pullen 17414d61c878SJulian Pullen if (!is_valid(&ctx->trusted_domains) || 17424d61c878SJulian Pullen is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) || 17434d61c878SJulian Pullen is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) { 17444d61c878SJulian Pullen 17454d61c878SJulian Pullen forest_name_dn = ldap_dns_to_dn(forest_name_item->value, 17464d61c878SJulian Pullen &num_parts); 17474d61c878SJulian Pullen if (forest_name_dn == NULL) 17484d61c878SJulian Pullen return (NULL); 17494d61c878SJulian Pullen 17504d61c878SJulian Pullen len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1; 17514d61c878SJulian Pullen dn = malloc(len); 17524d61c878SJulian Pullen if (dn == NULL) { 17534d61c878SJulian Pullen free(forest_name_dn); 17544d61c878SJulian Pullen return (NULL); 17554d61c878SJulian Pullen } 17564d61c878SJulian Pullen (void) snprintf(dn, len, "CN=System,%s", forest_name_dn); 17574d61c878SJulian Pullen free(forest_name_dn); 17584d61c878SJulian Pullen 17594d61c878SJulian Pullen trusted_domains = ldap_lookup_trusted_domains( 17604d61c878SJulian Pullen &ld, global_catalog_item->value, dn); 17614d61c878SJulian Pullen 17624d61c878SJulian Pullen if (ld != NULL) 17634d61c878SJulian Pullen (void) ldap_unbind(ld); 17644d61c878SJulian Pullen free(dn); 17654d61c878SJulian Pullen 17664d61c878SJulian Pullen if (trusted_domains == NULL) 17674d61c878SJulian Pullen return (NULL); 17684d61c878SJulian Pullen 17694d61c878SJulian Pullen update_item(&ctx->trusted_domains, trusted_domains, 17704d61c878SJulian Pullen AD_STATE_AUTO, 0); 17714d61c878SJulian Pullen update_version(&ctx->trusted_domains, PARAM1, 17724d61c878SJulian Pullen global_catalog_item); 17734d61c878SJulian Pullen update_version(&ctx->trusted_domains, PARAM2, 17744d61c878SJulian Pullen forest_name_item); 17754d61c878SJulian Pullen } 17764d61c878SJulian Pullen 17774d61c878SJulian Pullen return (&ctx->trusted_domains); 17784d61c878SJulian Pullen } 17794d61c878SJulian Pullen 17804d61c878SJulian Pullen 17814d61c878SJulian Pullen ad_disc_trusteddomains_t * 17827a8a68f5SJulian Pullen ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered) 17834d61c878SJulian Pullen { 17844d61c878SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 17854d61c878SJulian Pullen ad_item_t *trusted_domains_item; 17864d61c878SJulian Pullen 17874d61c878SJulian Pullen trusted_domains_item = validate_TrustedDomains(ctx); 17884d61c878SJulian Pullen 17894d61c878SJulian Pullen if (trusted_domains_item != NULL) { 17904d61c878SJulian Pullen trusted_domains = td_dup(trusted_domains_item->value); 17914d61c878SJulian Pullen if (auto_discovered != NULL) 17924d61c878SJulian Pullen *auto_discovered = 17934d61c878SJulian Pullen (trusted_domains_item->state == AD_STATE_AUTO); 17944d61c878SJulian Pullen } else if (auto_discovered != NULL) 17957a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 17964d61c878SJulian Pullen 17974d61c878SJulian Pullen return (trusted_domains); 17984d61c878SJulian Pullen } 17994d61c878SJulian Pullen 18004d61c878SJulian Pullen 18014d61c878SJulian Pullen static ad_item_t * 18024d61c878SJulian Pullen validate_DomainsInForest(ad_disc_t ctx) 18034d61c878SJulian Pullen { 18044d61c878SJulian Pullen ad_item_t *global_catalog_item; 18054d61c878SJulian Pullen LDAP *ld = NULL; 18064d61c878SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest; 18074d61c878SJulian Pullen 18084d61c878SJulian Pullen if (is_fixed(&ctx->domains_in_forest)) 18094d61c878SJulian Pullen return (&ctx->domains_in_forest); 18104d61c878SJulian Pullen 18114d61c878SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 18124d61c878SJulian Pullen if (global_catalog_item == NULL) 18134d61c878SJulian Pullen return (NULL); 18144d61c878SJulian Pullen 18154d61c878SJulian Pullen if (!is_valid(&ctx->domains_in_forest) || 18164d61c878SJulian Pullen is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) { 18174d61c878SJulian Pullen 18184d61c878SJulian Pullen domains_in_forest = ldap_lookup_domains_in_forest( 18194d61c878SJulian Pullen &ld, global_catalog_item->value); 18204d61c878SJulian Pullen 18214d61c878SJulian Pullen if (ld != NULL) 18224d61c878SJulian Pullen (void) ldap_unbind(ld); 18234d61c878SJulian Pullen 18244d61c878SJulian Pullen if (domains_in_forest == NULL) 18254d61c878SJulian Pullen return (NULL); 18264d61c878SJulian Pullen 18274d61c878SJulian Pullen update_item(&ctx->domains_in_forest, domains_in_forest, 18284d61c878SJulian Pullen AD_STATE_AUTO, 0); 18294d61c878SJulian Pullen update_version(&ctx->domains_in_forest, PARAM1, 18304d61c878SJulian Pullen global_catalog_item); 18314d61c878SJulian Pullen } 18324d61c878SJulian Pullen return (&ctx->domains_in_forest); 18334d61c878SJulian Pullen } 18344d61c878SJulian Pullen 18354d61c878SJulian Pullen 18364d61c878SJulian Pullen ad_disc_domainsinforest_t * 18377a8a68f5SJulian Pullen ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered) 18384d61c878SJulian Pullen { 18394d61c878SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest = NULL; 18404d61c878SJulian Pullen ad_item_t *domains_in_forest_item; 18414d61c878SJulian Pullen 18424d61c878SJulian Pullen domains_in_forest_item = validate_DomainsInForest(ctx); 18434d61c878SJulian Pullen 18444d61c878SJulian Pullen if (domains_in_forest_item != NULL) { 18454d61c878SJulian Pullen domains_in_forest = df_dup(domains_in_forest_item->value); 18464d61c878SJulian Pullen if (auto_discovered != NULL) 18474d61c878SJulian Pullen *auto_discovered = 18484d61c878SJulian Pullen (domains_in_forest_item->state == AD_STATE_AUTO); 18494d61c878SJulian Pullen } else if (auto_discovered != NULL) 18507a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 18514d61c878SJulian Pullen 18524d61c878SJulian Pullen return (domains_in_forest); 18534d61c878SJulian Pullen } 18544d61c878SJulian Pullen 1855b3700b07SGordon Ross static ad_item_t * 1856b3700b07SGordon Ross validate_PreferredDC(ad_disc_t ctx) 1857b3700b07SGordon Ross { 1858b3700b07SGordon Ross if (is_valid(&ctx->preferred_dc)) 1859b3700b07SGordon Ross return (&ctx->preferred_dc); 1860b3700b07SGordon Ross 1861b3700b07SGordon Ross return (NULL); 1862b3700b07SGordon Ross } 1863b3700b07SGordon Ross 1864b3700b07SGordon Ross ad_disc_ds_t * 1865b3700b07SGordon Ross ad_disc_get_PreferredDC(ad_disc_t ctx, boolean_t *auto_discovered) 1866b3700b07SGordon Ross { 1867b3700b07SGordon Ross ad_disc_ds_t *preferred_dc = NULL; 1868b3700b07SGordon Ross ad_item_t *preferred_dc_item; 1869b3700b07SGordon Ross 1870b3700b07SGordon Ross preferred_dc_item = validate_PreferredDC(ctx); 1871b3700b07SGordon Ross 1872b3700b07SGordon Ross if (preferred_dc_item != NULL) { 1873b3700b07SGordon Ross preferred_dc = ds_dup(preferred_dc_item->value); 1874b3700b07SGordon Ross if (auto_discovered != NULL) 1875b3700b07SGordon Ross *auto_discovered = 1876b3700b07SGordon Ross (preferred_dc_item->state == AD_STATE_AUTO); 1877b3700b07SGordon Ross } else if (auto_discovered != NULL) 1878b3700b07SGordon Ross *auto_discovered = B_FALSE; 1879b3700b07SGordon Ross 1880b3700b07SGordon Ross return (preferred_dc); 1881b3700b07SGordon Ross } 18824d61c878SJulian Pullen 18834d61c878SJulian Pullen 18844d61c878SJulian Pullen 1885c8e26105Sjp int 1886c8e26105Sjp ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) 1887c8e26105Sjp { 1888c8e26105Sjp char *domain_name = NULL; 1889c8e26105Sjp if (domainName != NULL) { 1890c8e26105Sjp domain_name = strdup(domainName); 1891c8e26105Sjp if (domain_name == NULL) 1892c8e26105Sjp return (-1); 18934d61c878SJulian Pullen update_item(&ctx->domain_name, domain_name, 18944d61c878SJulian Pullen AD_STATE_FIXED, 0); 18954d61c878SJulian Pullen } else if (ctx->domain_name.state == AD_STATE_FIXED) 18964d61c878SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 1897c8e26105Sjp return (0); 1898c8e26105Sjp } 1899c8e26105Sjp 1900b3700b07SGordon Ross int 1901b3700b07SGordon Ross ad_disc_set_DomainGUID(ad_disc_t ctx, uchar_t *u) 1902b3700b07SGordon Ross { 1903b3700b07SGordon Ross char *domain_guid = NULL; 1904b3700b07SGordon Ross if (u != NULL) { 1905b3700b07SGordon Ross domain_guid = uuid_dup(u); 1906b3700b07SGordon Ross if (domain_guid == NULL) 1907b3700b07SGordon Ross return (-1); 1908b3700b07SGordon Ross update_item(&ctx->domain_guid, domain_guid, 1909b3700b07SGordon Ross AD_STATE_FIXED, 0); 1910b3700b07SGordon Ross } else if (ctx->domain_guid.state == AD_STATE_FIXED) 1911b3700b07SGordon Ross ctx->domain_guid.state = AD_STATE_INVALID; 1912b3700b07SGordon Ross return (0); 1913b3700b07SGordon Ross } 1914b3700b07SGordon Ross 1915b3700b07SGordon Ross void 1916b3700b07SGordon Ross auto_set_DomainGUID(ad_disc_t ctx, uchar_t *u) 1917b3700b07SGordon Ross { 1918b3700b07SGordon Ross char *domain_guid = NULL; 1919b3700b07SGordon Ross 1920b3700b07SGordon Ross if (is_fixed(&ctx->domain_guid)) 1921b3700b07SGordon Ross return; 1922b3700b07SGordon Ross 1923b3700b07SGordon Ross domain_guid = uuid_dup(u); 1924b3700b07SGordon Ross if (domain_guid == NULL) 1925b3700b07SGordon Ross return; 1926b3700b07SGordon Ross update_item(&ctx->domain_guid, domain_guid, AD_STATE_AUTO, 0); 1927b3700b07SGordon Ross } 1928c8e26105Sjp 1929c8e26105Sjp int 1930c8e26105Sjp ad_disc_set_DomainController(ad_disc_t ctx, 1931b3700b07SGordon Ross const ad_disc_ds_t *domainController) 1932c8e26105Sjp { 1933b3700b07SGordon Ross ad_disc_ds_t *domain_controller = NULL; 1934c8e26105Sjp if (domainController != NULL) { 19354d61c878SJulian Pullen domain_controller = ds_dup(domainController); 1936c8e26105Sjp if (domain_controller == NULL) 1937c8e26105Sjp return (-1); 19384d61c878SJulian Pullen update_item(&ctx->domain_controller, domain_controller, 19394d61c878SJulian Pullen AD_STATE_FIXED, 0); 19404d61c878SJulian Pullen } else if (ctx->domain_controller.state == AD_STATE_FIXED) 19414d61c878SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 1942c8e26105Sjp return (0); 1943c8e26105Sjp } 1944c8e26105Sjp 1945c8e26105Sjp int 1946c8e26105Sjp ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) 1947c8e26105Sjp { 1948c8e26105Sjp char *site_name = NULL; 1949c8e26105Sjp if (siteName != NULL) { 1950c8e26105Sjp site_name = strdup(siteName); 1951c8e26105Sjp if (site_name == NULL) 1952c8e26105Sjp return (-1); 19534d61c878SJulian Pullen update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0); 19544d61c878SJulian Pullen } else if (ctx->site_name.state == AD_STATE_FIXED) 19554d61c878SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 1956c8e26105Sjp return (0); 1957c8e26105Sjp } 1958c8e26105Sjp 1959b3700b07SGordon Ross void 1960b3700b07SGordon Ross auto_set_SiteName(ad_disc_t ctx, char *siteName) 1961b3700b07SGordon Ross { 1962b3700b07SGordon Ross char *site_name = NULL; 1963b3700b07SGordon Ross 1964b3700b07SGordon Ross if (is_fixed(&ctx->site_name)) 1965b3700b07SGordon Ross return; 1966b3700b07SGordon Ross 1967b3700b07SGordon Ross site_name = strdup(siteName); 1968b3700b07SGordon Ross if (site_name == NULL) 1969b3700b07SGordon Ross return; 1970b3700b07SGordon Ross update_item(&ctx->site_name, site_name, AD_STATE_AUTO, 0); 1971b3700b07SGordon Ross } 1972b3700b07SGordon Ross 1973c8e26105Sjp int 1974c8e26105Sjp ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) 1975c8e26105Sjp { 1976c8e26105Sjp char *forest_name = NULL; 1977c8e26105Sjp if (forestName != NULL) { 1978c8e26105Sjp forest_name = strdup(forestName); 1979c8e26105Sjp if (forest_name == NULL) 1980c8e26105Sjp return (-1); 19814d61c878SJulian Pullen update_item(&ctx->forest_name, forest_name, 19824d61c878SJulian Pullen AD_STATE_FIXED, 0); 19834d61c878SJulian Pullen } else if (ctx->forest_name.state == AD_STATE_FIXED) 19844d61c878SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 1985c8e26105Sjp return (0); 1986c8e26105Sjp } 1987c8e26105Sjp 1988b3700b07SGordon Ross void 1989b3700b07SGordon Ross auto_set_ForestName(ad_disc_t ctx, char *forestName) 1990b3700b07SGordon Ross { 1991b3700b07SGordon Ross char *forest_name = NULL; 1992b3700b07SGordon Ross 1993b3700b07SGordon Ross if (is_fixed(&ctx->forest_name)) 1994b3700b07SGordon Ross return; 1995b3700b07SGordon Ross 1996b3700b07SGordon Ross forest_name = strdup(forestName); 1997b3700b07SGordon Ross if (forest_name == NULL) 1998b3700b07SGordon Ross return; 1999b3700b07SGordon Ross update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); 2000b3700b07SGordon Ross } 2001b3700b07SGordon Ross 2002c8e26105Sjp int 2003479ac375Sdm ad_disc_set_GlobalCatalog(ad_disc_t ctx, 2004b3700b07SGordon Ross const ad_disc_ds_t *globalCatalog) 2005c8e26105Sjp { 2006b3700b07SGordon Ross ad_disc_ds_t *global_catalog = NULL; 2007c8e26105Sjp if (globalCatalog != NULL) { 20084d61c878SJulian Pullen global_catalog = ds_dup(globalCatalog); 2009c8e26105Sjp if (global_catalog == NULL) 2010c8e26105Sjp return (-1); 20114d61c878SJulian Pullen update_item(&ctx->global_catalog, global_catalog, 20124d61c878SJulian Pullen AD_STATE_FIXED, 0); 20134d61c878SJulian Pullen } else if (ctx->global_catalog.state == AD_STATE_FIXED) 20144d61c878SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 2015c8e26105Sjp return (0); 2016c8e26105Sjp } 2017c8e26105Sjp 2018b3700b07SGordon Ross int 2019b3700b07SGordon Ross ad_disc_set_PreferredDC(ad_disc_t ctx, const ad_disc_ds_t *pref_dc) 2020b3700b07SGordon Ross { 2021b3700b07SGordon Ross ad_disc_ds_t *new_pref_dc = NULL; 2022b3700b07SGordon Ross if (pref_dc != NULL) { 2023b3700b07SGordon Ross new_pref_dc = ds_dup(pref_dc); 2024b3700b07SGordon Ross if (new_pref_dc == NULL) 2025b3700b07SGordon Ross return (-1); 2026b3700b07SGordon Ross update_item(&ctx->preferred_dc, new_pref_dc, 2027b3700b07SGordon Ross AD_STATE_FIXED, 0); 2028b3700b07SGordon Ross } else if (ctx->preferred_dc.state == AD_STATE_FIXED) 2029b3700b07SGordon Ross ctx->preferred_dc.state = AD_STATE_INVALID; 2030b3700b07SGordon Ross return (0); 2031b3700b07SGordon Ross } 2032b3700b07SGordon Ross 2033b3700b07SGordon Ross void 2034b3700b07SGordon Ross ad_disc_set_StatusFP(ad_disc_t ctx, struct __FILE_TAG *fp) 2035b3700b07SGordon Ross { 2036b3700b07SGordon Ross ctx->status_fp = fp; 2037b3700b07SGordon Ross } 2038b3700b07SGordon Ross 2039c8e26105Sjp 2040c8e26105Sjp int 2041c8e26105Sjp ad_disc_unset(ad_disc_t ctx) 2042c8e26105Sjp { 20434d61c878SJulian Pullen if (ctx->domain_name.state == AD_STATE_FIXED) 20444d61c878SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 2045c8e26105Sjp 20464d61c878SJulian Pullen if (ctx->domain_controller.state == AD_STATE_FIXED) 20474d61c878SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 2048c8e26105Sjp 2049b3700b07SGordon Ross if (ctx->preferred_dc.state == AD_STATE_FIXED) 2050b3700b07SGordon Ross ctx->preferred_dc.state = AD_STATE_INVALID; 2051b3700b07SGordon Ross 20524d61c878SJulian Pullen if (ctx->site_name.state == AD_STATE_FIXED) 20534d61c878SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 2054c8e26105Sjp 20554d61c878SJulian Pullen if (ctx->forest_name.state == AD_STATE_FIXED) 20564d61c878SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 2057c8e26105Sjp 20584d61c878SJulian Pullen if (ctx->global_catalog.state == AD_STATE_FIXED) 20594d61c878SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 2060c8e26105Sjp 2061c8e26105Sjp return (0); 2062c8e26105Sjp } 2063c8e26105Sjp 2064c8e26105Sjp /* 2065c8e26105Sjp * ad_disc_get_TTL 2066c8e26105Sjp * 2067c8e26105Sjp * This routines the time to live for AD 2068c8e26105Sjp * auto discovered items. 2069c8e26105Sjp * 2070c8e26105Sjp * Returns: 2071c8e26105Sjp * -1 if there are no TTL items 2072c8e26105Sjp * 0 if there are expired items 2073c8e26105Sjp * else the number of seconds 20740dcc7149Snw * 20750dcc7149Snw * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it 20760dcc7149Snw * is positive -- min() greater than zero. 2077c8e26105Sjp */ 20780dcc7149Snw #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \ 20790dcc7149Snw (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x)))) 2080c8e26105Sjp int 2081c8e26105Sjp ad_disc_get_TTL(ad_disc_t ctx) 2082c8e26105Sjp { 2083c5866007SKeyur Desai time_t expires; 2084c8e26105Sjp int ttl; 2085c8e26105Sjp 2086c5866007SKeyur Desai expires = MIN_GT_ZERO(ctx->domain_controller.expires, 2087c5866007SKeyur Desai ctx->global_catalog.expires); 2088c5866007SKeyur Desai expires = MIN_GT_ZERO(expires, ctx->site_domain_controller.expires); 2089c5866007SKeyur Desai expires = MIN_GT_ZERO(expires, ctx->site_global_catalog.expires); 2090c8e26105Sjp 2091c5866007SKeyur Desai if (expires == -1) { 2092c8e26105Sjp return (-1); 2093c5866007SKeyur Desai } 2094c5866007SKeyur Desai 2095c5866007SKeyur Desai if (ctx->expires_not_before != 0 && 2096c5866007SKeyur Desai expires < ctx->expires_not_before) { 2097c5866007SKeyur Desai expires = ctx->expires_not_before; 2098c5866007SKeyur Desai } 2099c5866007SKeyur Desai 2100c5866007SKeyur Desai if (ctx->expires_not_after != 0 && 2101c5866007SKeyur Desai expires > ctx->expires_not_after) { 2102c5866007SKeyur Desai expires = ctx->expires_not_after; 2103c5866007SKeyur Desai } 2104c5866007SKeyur Desai 2105c5866007SKeyur Desai ttl = expires - time(NULL); 2106c5866007SKeyur Desai 2107c5866007SKeyur Desai if (ttl < 0) { 21080dcc7149Snw return (0); 2109c5866007SKeyur Desai } 2110c8e26105Sjp return (ttl); 2111c8e26105Sjp } 2112c8e26105Sjp 21137a8a68f5SJulian Pullen boolean_t 2114c8e26105Sjp ad_disc_SubnetChanged(ad_disc_t ctx) 2115c8e26105Sjp { 2116c8e26105Sjp ad_subnet_t *subnets; 2117c8e26105Sjp 2118c8e26105Sjp if (ctx->subnets_changed || ctx->subnets == NULL) 21197a8a68f5SJulian Pullen return (B_TRUE); 2120c8e26105Sjp 2121c8e26105Sjp if ((subnets = find_subnets()) != NULL) { 2122c8e26105Sjp if (cmpsubnets(subnets, ctx->subnets) != 0) 21237a8a68f5SJulian Pullen ctx->subnets_changed = B_TRUE; 2124c8e26105Sjp free(subnets); 2125c8e26105Sjp } 2126c8e26105Sjp 2127c8e26105Sjp return (ctx->subnets_changed); 2128c8e26105Sjp } 2129