17a8a68f5SJulian Pullen /* 27a8a68f5SJulian Pullen * CDDL HEADER START 37a8a68f5SJulian Pullen * 47a8a68f5SJulian Pullen * The contents of this file are subject to the terms of the 57a8a68f5SJulian Pullen * Common Development and Distribution License (the "License"). 67a8a68f5SJulian Pullen * You may not use this file except in compliance with the License. 77a8a68f5SJulian Pullen * 87a8a68f5SJulian Pullen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97a8a68f5SJulian Pullen * or http://www.opensolaris.org/os/licensing. 107a8a68f5SJulian Pullen * See the License for the specific language governing permissions 117a8a68f5SJulian Pullen * and limitations under the License. 127a8a68f5SJulian Pullen * 137a8a68f5SJulian Pullen * When distributing Covered Code, include this CDDL HEADER in each 147a8a68f5SJulian Pullen * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157a8a68f5SJulian Pullen * If applicable, add the following below this CDDL HEADER, with the 167a8a68f5SJulian Pullen * fields enclosed by brackets "[]" replaced with your own identifying 177a8a68f5SJulian Pullen * information: Portions Copyright [yyyy] [name of copyright owner] 187a8a68f5SJulian Pullen * 197a8a68f5SJulian Pullen * CDDL HEADER END 207a8a68f5SJulian Pullen */ 217a8a68f5SJulian Pullen 227a8a68f5SJulian Pullen /* 23148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24*b3700b07SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 257a8a68f5SJulian Pullen */ 267a8a68f5SJulian Pullen 277a8a68f5SJulian Pullen /* 287a8a68f5SJulian Pullen * Active Directory Auto-Discovery. 297a8a68f5SJulian Pullen * 307a8a68f5SJulian Pullen * This [project private] API allows the caller to provide whatever 317a8a68f5SJulian Pullen * details it knows a priori (i.e., provided via configuration so as to 327a8a68f5SJulian Pullen * override auto-discovery) and in any order. Then the caller can ask 337a8a68f5SJulian Pullen * for any of the auto-discoverable parameters in any order. 347a8a68f5SJulian Pullen * 357a8a68f5SJulian Pullen * But there is an actual order in which discovery must be done. Given 367a8a68f5SJulian Pullen * the discovery mechanism implemented here, that order is: 377a8a68f5SJulian Pullen * 387a8a68f5SJulian Pullen * - the domain name joined must be discovered first 397a8a68f5SJulian Pullen * - then the domain controllers 407a8a68f5SJulian Pullen * - then the forest name and site name 417a8a68f5SJulian Pullen * - then the global catalog servers, and site-specific domain 427a8a68f5SJulian Pullen * controllers and global catalog servers. 437a8a68f5SJulian Pullen * 447a8a68f5SJulian Pullen * The API does not require it be called in the same order because there 457a8a68f5SJulian Pullen * may be other discovery mechanisms in the future, and exposing 467a8a68f5SJulian Pullen * ordering requirements of the current mechanism now can create trouble 477a8a68f5SJulian Pullen * down the line. Also, this makes the API easier to use now, which 487a8a68f5SJulian Pullen * means less work to do some day when we make this a public API. 497a8a68f5SJulian Pullen * 507a8a68f5SJulian Pullen * Domain discovery is done by res_nsearch() of the DNS SRV RR name for 517a8a68f5SJulian Pullen * domain controllers. As long as the joined domain appears in the DNS 527a8a68f5SJulian Pullen * resolver's search list then we'll find it. 537a8a68f5SJulian Pullen * 547a8a68f5SJulian Pullen * Domain controller discovery is a matter of formatting the DNS SRV RR 557a8a68f5SJulian Pullen * FQDN for domain controllers and doing a lookup for them. Knowledge 567a8a68f5SJulian Pullen * of the domain name is not fundamentally required, but we separate the 577a8a68f5SJulian Pullen * two processes, which in practice can lead to one more DNS lookup than 587a8a68f5SJulian Pullen * is strictly required. 597a8a68f5SJulian Pullen * 607a8a68f5SJulian Pullen * Forest and site name discovery require an LDAP search of the AD 617a8a68f5SJulian Pullen * "configuration partition" at a domain controller for the joined 627a8a68f5SJulian Pullen * domain. Forest and site name discovery depend on knowing the joined 637a8a68f5SJulian Pullen * domain name and domain controllers for that domain. 647a8a68f5SJulian Pullen * 657a8a68f5SJulian Pullen * Global catalog server discovery requires knowledge of the forest 667a8a68f5SJulian Pullen * name in order to format the DNS SRV RR FQDN to lookup. Site-specific 677a8a68f5SJulian Pullen * domain controller discovery depends on knowing the site name (and, 687a8a68f5SJulian Pullen * therefore, joined domain, ...). Site-specific global catalog server 697a8a68f5SJulian Pullen * discovery depends on knowledge of the forest and site names, which 707a8a68f5SJulian Pullen * depend on... 717a8a68f5SJulian Pullen * 727a8a68f5SJulian Pullen * All the work of discovering particular items is done by functions 737a8a68f5SJulian Pullen * named validate_<item>(). Each such function calls validate_<item>() 747a8a68f5SJulian Pullen * for any items that it depends on. 757a8a68f5SJulian Pullen * 767a8a68f5SJulian Pullen * This API is not thread-safe. 777a8a68f5SJulian Pullen */ 787a8a68f5SJulian Pullen 797a8a68f5SJulian Pullen 807a8a68f5SJulian Pullen #include <stdio.h> 817a8a68f5SJulian Pullen #include <string.h> 827a8a68f5SJulian Pullen #include <strings.h> 837a8a68f5SJulian Pullen #include <unistd.h> 847a8a68f5SJulian Pullen #include <assert.h> 857a8a68f5SJulian Pullen #include <stdlib.h> 867a8a68f5SJulian Pullen #include <net/if.h> 877a8a68f5SJulian Pullen #include <sys/types.h> 887a8a68f5SJulian Pullen #include <sys/socket.h> 897a8a68f5SJulian Pullen #include <sys/sockio.h> 907a8a68f5SJulian Pullen #include <netinet/in.h> 917a8a68f5SJulian Pullen #include <arpa/inet.h> 927a8a68f5SJulian Pullen #include <arpa/nameser.h> 937a8a68f5SJulian Pullen #include <resolv.h> 947a8a68f5SJulian Pullen #include <netdb.h> 957a8a68f5SJulian Pullen #include <ctype.h> 967a8a68f5SJulian Pullen #include <errno.h> 977a8a68f5SJulian Pullen #include <ldap.h> 98*b3700b07SGordon Ross #include <note.h> 997a8a68f5SJulian Pullen #include <sasl/sasl.h> 1007a8a68f5SJulian Pullen #include <sys/u8_textprep.h> 1017a8a68f5SJulian Pullen #include <syslog.h> 102*b3700b07SGordon Ross #include <uuid/uuid.h> 103*b3700b07SGordon Ross #include <ads/dsgetdc.h> 1047a8a68f5SJulian Pullen #include "adutils_impl.h" 105*b3700b07SGordon Ross #include "addisc_impl.h" 1067a8a68f5SJulian Pullen 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) 1177a8a68f5SJulian Pullen 1187a8a68f5SJulian Pullen 1197a8a68f5SJulian Pullen #define DNS_MAX_NAME NS_MAXDNAME 1207a8a68f5SJulian Pullen 121*b3700b07SGordon Ross #define GC_PORT 3268 1227a8a68f5SJulian Pullen 1237a8a68f5SJulian Pullen /* SRV RR names for various queries */ 1247a8a68f5SJulian Pullen #define LDAP_SRV_HEAD "_ldap._tcp." 1257a8a68f5SJulian Pullen #define SITE_SRV_MIDDLE "%s._sites." 1267a8a68f5SJulian Pullen #define GC_SRV_TAIL "gc._msdcs" 1277a8a68f5SJulian Pullen #define DC_SRV_TAIL "dc._msdcs" 1287a8a68f5SJulian Pullen #define ALL_GC_SRV_TAIL "_gc._tcp" 1297a8a68f5SJulian Pullen #define PDC_SRV "_ldap._tcp.pdc._msdcs.%s" 1307a8a68f5SJulian Pullen 1317a8a68f5SJulian Pullen /* A RR name for all GCs -- last resort this works */ 1327a8a68f5SJulian Pullen #define GC_ALL_A_NAME_FSTR "gc._msdcs.%s." 1337a8a68f5SJulian Pullen 1347a8a68f5SJulian Pullen 1357a8a68f5SJulian Pullen /* 1367a8a68f5SJulian Pullen * We try res_ninit() whenever we don't have one. res_ninit() fails if 1377a8a68f5SJulian Pullen * idmapd is running before the network is up! 1387a8a68f5SJulian Pullen */ 139*b3700b07SGordon Ross #define DO_RES_NINIT(ctx) \ 140*b3700b07SGordon Ross if (!(ctx)->res_ninitted) \ 141*b3700b07SGordon Ross (void) do_res_ninit(ctx) 142*b3700b07SGordon Ross 143*b3700b07SGordon Ross #define DO_GETNAMEINFO(b, l, s) \ 144*b3700b07SGordon Ross if (ad_disc_getnameinfo(b, l, s) != 0) \ 145*b3700b07SGordon Ross (void) strlcpy(b, "?", l) 146*b3700b07SGordon Ross 147*b3700b07SGordon Ross #define DEBUG1STATUS(ctx, ...) do { \ 148*b3700b07SGordon Ross if (DBG(DISC, 1)) \ 149*b3700b07SGordon Ross logger(LOG_DEBUG, __VA_ARGS__); \ 150*b3700b07SGordon Ross if (ctx->status_fp) { \ 151*b3700b07SGordon Ross (void) fprintf(ctx->status_fp, __VA_ARGS__); \ 152*b3700b07SGordon Ross (void) fprintf(ctx->status_fp, "\n"); \ 153*b3700b07SGordon Ross } \ 154*b3700b07SGordon Ross _NOTE(CONSTCOND) \ 155*b3700b07SGordon Ross } while (0) 1567a8a68f5SJulian Pullen 1577a8a68f5SJulian Pullen #define is_fixed(item) \ 1587a8a68f5SJulian Pullen ((item)->state == AD_STATE_FIXED) 1597a8a68f5SJulian Pullen 1607a8a68f5SJulian Pullen #define is_changed(item, num, param) \ 1617a8a68f5SJulian Pullen ((item)->param_version[num] != (param)->version) 1627a8a68f5SJulian Pullen 163*b3700b07SGordon Ross void * uuid_dup(void *); 164*b3700b07SGordon Ross 165*b3700b07SGordon Ross static ad_item_t *validate_SiteName(ad_disc_t ctx); 166*b3700b07SGordon Ross static ad_item_t *validate_PreferredDC(ad_disc_t ctx); 167*b3700b07SGordon Ross 1687a8a68f5SJulian Pullen /* 1697a8a68f5SJulian Pullen * Function definitions 1707a8a68f5SJulian Pullen */ 1717a8a68f5SJulian Pullen 1727a8a68f5SJulian Pullen 173*b3700b07SGordon Ross static int 174*b3700b07SGordon Ross do_res_ninit(ad_disc_t ctx) 175*b3700b07SGordon Ross { 176*b3700b07SGordon Ross int rc; 177*b3700b07SGordon Ross 178*b3700b07SGordon Ross rc = res_ninit(&ctx->res_state); 179*b3700b07SGordon Ross if (rc != 0) 180*b3700b07SGordon Ross return (rc); 181*b3700b07SGordon Ross ctx->res_ninitted = 1; 182*b3700b07SGordon Ross /* 183*b3700b07SGordon Ross * The SRV records returnd by AD can be larger than 512 bytes, 184*b3700b07SGordon Ross * so we'd like to use TCP for those searches. Unfortunately, 185*b3700b07SGordon Ross * the TCP connect timeout seen by the resolver is very long 186*b3700b07SGordon Ross * (more than a couple minutes) and we can't wait that long. 187*b3700b07SGordon Ross * Don't do use TCP until we can override the timeout. 188*b3700b07SGordon Ross * 189*b3700b07SGordon Ross * Note that some queries will try TCP anyway. 190*b3700b07SGordon Ross */ 191*b3700b07SGordon Ross #if 0 192*b3700b07SGordon Ross ctx->res_state.options |= RES_USEVC; 193*b3700b07SGordon Ross #endif 194*b3700b07SGordon Ross return (0); 195*b3700b07SGordon Ross } 196*b3700b07SGordon Ross 197*b3700b07SGordon Ross /* 198*b3700b07SGordon Ross * Private getnameinfo(3socket) variant tailored to our needs. 199*b3700b07SGordon Ross */ 200*b3700b07SGordon Ross int 201*b3700b07SGordon Ross ad_disc_getnameinfo(char *obuf, int olen, struct sockaddr_storage *ss) 202*b3700b07SGordon Ross { 203*b3700b07SGordon Ross struct sockaddr *sa; 204*b3700b07SGordon Ross int eai, slen; 205*b3700b07SGordon Ross 206*b3700b07SGordon Ross sa = (void *)ss; 207*b3700b07SGordon Ross switch (sa->sa_family) { 208*b3700b07SGordon Ross case AF_INET: 209*b3700b07SGordon Ross slen = sizeof (struct sockaddr_in); 210*b3700b07SGordon Ross break; 211*b3700b07SGordon Ross case AF_INET6: 212*b3700b07SGordon Ross slen = sizeof (struct sockaddr_in6); 213*b3700b07SGordon Ross break; 214*b3700b07SGordon Ross default: 215*b3700b07SGordon Ross return (EAI_FAMILY); 216*b3700b07SGordon Ross } 217*b3700b07SGordon Ross 218*b3700b07SGordon Ross eai = getnameinfo(sa, slen, obuf, olen, NULL, 0, NI_NUMERICHOST); 219*b3700b07SGordon Ross 220*b3700b07SGordon Ross return (eai); 221*b3700b07SGordon Ross } 2227a8a68f5SJulian Pullen 2237a8a68f5SJulian Pullen static void 2247a8a68f5SJulian Pullen update_version(ad_item_t *item, int num, ad_item_t *param) 2257a8a68f5SJulian Pullen { 2267a8a68f5SJulian Pullen item->param_version[num] = param->version; 2277a8a68f5SJulian Pullen } 2287a8a68f5SJulian Pullen 2297a8a68f5SJulian Pullen 2307a8a68f5SJulian Pullen 2317a8a68f5SJulian Pullen static boolean_t 2327a8a68f5SJulian Pullen is_valid(ad_item_t *item) 2337a8a68f5SJulian Pullen { 2347a8a68f5SJulian Pullen if (item->value != NULL) { 2357a8a68f5SJulian Pullen if (item->state == AD_STATE_FIXED) 2367a8a68f5SJulian Pullen return (B_TRUE); 2377a8a68f5SJulian Pullen if (item->state == AD_STATE_AUTO && 238c5866007SKeyur Desai (item->expires == 0 || item->expires > time(NULL))) 2397a8a68f5SJulian Pullen return (B_TRUE); 2407a8a68f5SJulian Pullen } 2417a8a68f5SJulian Pullen return (B_FALSE); 2427a8a68f5SJulian Pullen } 2437a8a68f5SJulian Pullen 2447a8a68f5SJulian Pullen 2457a8a68f5SJulian Pullen static void 2467a8a68f5SJulian Pullen update_item(ad_item_t *item, void *value, enum ad_item_state state, 2477a8a68f5SJulian Pullen uint32_t ttl) 2487a8a68f5SJulian Pullen { 2497a8a68f5SJulian Pullen if (item->value != NULL && value != NULL) { 2507a8a68f5SJulian Pullen if ((item->type == AD_STRING && 2517a8a68f5SJulian Pullen strcmp(item->value, value) != 0) || 252*b3700b07SGordon Ross (item->type == AD_UUID && 253*b3700b07SGordon Ross ad_disc_compare_uuid(item->value, value) != 0)|| 2547a8a68f5SJulian Pullen (item->type == AD_DIRECTORY && 2557a8a68f5SJulian Pullen ad_disc_compare_ds(item->value, value) != 0)|| 2567a8a68f5SJulian Pullen (item->type == AD_DOMAINS_IN_FOREST && 2577a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(item->value, value) != 0) || 2587a8a68f5SJulian Pullen (item->type == AD_TRUSTED_DOMAINS && 2597a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(item->value, value) != 0)) 2607a8a68f5SJulian Pullen item->version++; 2617a8a68f5SJulian Pullen } else if (item->value != value) 2627a8a68f5SJulian Pullen item->version++; 2637a8a68f5SJulian Pullen 2647a8a68f5SJulian Pullen if (item->value != NULL) 2657a8a68f5SJulian Pullen free(item->value); 2667a8a68f5SJulian Pullen 2677a8a68f5SJulian Pullen item->value = value; 2687a8a68f5SJulian Pullen item->state = state; 2697a8a68f5SJulian Pullen 2707a8a68f5SJulian Pullen if (ttl == 0) 271c5866007SKeyur Desai item->expires = 0; 2727a8a68f5SJulian Pullen else 273c5866007SKeyur Desai item->expires = time(NULL) + ttl; 2747a8a68f5SJulian Pullen } 2757a8a68f5SJulian Pullen 276*b3700b07SGordon Ross /* Compare UUIDs */ 277*b3700b07SGordon Ross int 278*b3700b07SGordon Ross ad_disc_compare_uuid(uuid_t *u1, uuid_t *u2) 279*b3700b07SGordon Ross { 280*b3700b07SGordon Ross int rc; 281*b3700b07SGordon Ross 282*b3700b07SGordon Ross rc = memcmp(u1, u2, UUID_LEN); 283*b3700b07SGordon Ross return (rc); 284*b3700b07SGordon Ross } 285*b3700b07SGordon Ross 286*b3700b07SGordon Ross void * 287*b3700b07SGordon Ross uuid_dup(void *src) 288*b3700b07SGordon Ross { 289*b3700b07SGordon Ross void *dst; 290*b3700b07SGordon Ross dst = malloc(UUID_LEN); 291*b3700b07SGordon Ross if (dst != NULL) 292*b3700b07SGordon Ross (void) memcpy(dst, src, UUID_LEN); 293*b3700b07SGordon Ross return (dst); 294*b3700b07SGordon Ross } 2957a8a68f5SJulian Pullen 2967a8a68f5SJulian Pullen /* Compare DS lists */ 2977a8a68f5SJulian Pullen int 298*b3700b07SGordon Ross ad_disc_compare_ds(ad_disc_ds_t *ds1, ad_disc_ds_t *ds2) 2997a8a68f5SJulian Pullen { 3007a8a68f5SJulian Pullen int i, j; 3017a8a68f5SJulian Pullen int num_ds1; 3027a8a68f5SJulian Pullen int num_ds2; 3037a8a68f5SJulian Pullen boolean_t match; 3047a8a68f5SJulian Pullen 3057a8a68f5SJulian Pullen for (i = 0; ds1[i].host[0] != '\0'; i++) 3067a8a68f5SJulian Pullen continue; 3077a8a68f5SJulian Pullen num_ds1 = i; 3087a8a68f5SJulian Pullen for (j = 0; ds2[j].host[0] != '\0'; j++) 3097a8a68f5SJulian Pullen continue; 3107a8a68f5SJulian Pullen num_ds2 = j; 3117a8a68f5SJulian Pullen if (num_ds1 != num_ds2) 3127a8a68f5SJulian Pullen return (1); 3137a8a68f5SJulian Pullen 3147a8a68f5SJulian Pullen for (i = 0; i < num_ds1; i++) { 3157a8a68f5SJulian Pullen match = B_FALSE; 3167a8a68f5SJulian 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; 3207a8a68f5SJulian Pullen break; 3217a8a68f5SJulian Pullen } 3227a8a68f5SJulian Pullen } 3237a8a68f5SJulian Pullen if (!match) 3247a8a68f5SJulian Pullen return (1); 3257a8a68f5SJulian Pullen } 3267a8a68f5SJulian Pullen return (0); 3277a8a68f5SJulian Pullen } 3287a8a68f5SJulian Pullen 3297a8a68f5SJulian Pullen 3307a8a68f5SJulian Pullen /* Copy a list of DSs */ 331*b3700b07SGordon Ross static ad_disc_ds_t * 332*b3700b07SGordon Ross ds_dup(const ad_disc_ds_t *srv) 3337a8a68f5SJulian Pullen { 3347a8a68f5SJulian Pullen int i; 3357a8a68f5SJulian Pullen int size; 336*b3700b07SGordon Ross ad_disc_ds_t *new = NULL; 3377a8a68f5SJulian Pullen 3387a8a68f5SJulian Pullen for (i = 0; srv[i].host[0] != '\0'; i++) 3397a8a68f5SJulian Pullen continue; 3407a8a68f5SJulian Pullen 341*b3700b07SGordon Ross size = (i + 1) * sizeof (ad_disc_ds_t); 3427a8a68f5SJulian Pullen new = malloc(size); 3437a8a68f5SJulian Pullen if (new != NULL) 344148c5f43SAlan Wright (void) memcpy(new, srv, size); 3457a8a68f5SJulian Pullen return (new); 3467a8a68f5SJulian Pullen } 3477a8a68f5SJulian Pullen 3487a8a68f5SJulian Pullen 3497a8a68f5SJulian Pullen int 3507a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1, 3517a8a68f5SJulian Pullen ad_disc_trusteddomains_t *td2) 3527a8a68f5SJulian Pullen { 3537a8a68f5SJulian Pullen int i, j; 3547a8a68f5SJulian Pullen int num_td1; 3557a8a68f5SJulian Pullen int num_td2; 3567a8a68f5SJulian Pullen boolean_t match; 3577a8a68f5SJulian Pullen 3587a8a68f5SJulian Pullen for (i = 0; td1[i].domain[0] != '\0'; i++) 3597a8a68f5SJulian Pullen continue; 3607a8a68f5SJulian Pullen num_td1 = i; 3617a8a68f5SJulian Pullen 3627a8a68f5SJulian Pullen for (j = 0; td2[j].domain[0] != '\0'; j++) 3637a8a68f5SJulian Pullen continue; 3647a8a68f5SJulian Pullen num_td2 = j; 3657a8a68f5SJulian Pullen 3667a8a68f5SJulian Pullen if (num_td1 != num_td2) 3677a8a68f5SJulian Pullen return (1); 3687a8a68f5SJulian Pullen 3697a8a68f5SJulian Pullen for (i = 0; i < num_td1; i++) { 3707a8a68f5SJulian Pullen match = B_FALSE; 3717a8a68f5SJulian Pullen for (j = 0; j < num_td2; j++) { 3721fcced4cSJordan Brown if (domain_eq(td1[i].domain, td2[j].domain)) { 3737a8a68f5SJulian Pullen match = B_TRUE; 3747a8a68f5SJulian Pullen break; 3757a8a68f5SJulian Pullen } 3767a8a68f5SJulian Pullen } 3777a8a68f5SJulian Pullen if (!match) 3787a8a68f5SJulian Pullen return (1); 3797a8a68f5SJulian Pullen } 3807a8a68f5SJulian Pullen return (0); 3817a8a68f5SJulian Pullen } 3827a8a68f5SJulian Pullen 3837a8a68f5SJulian Pullen 3847a8a68f5SJulian Pullen 3857a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */ 3867a8a68f5SJulian Pullen static ad_disc_trusteddomains_t * 3877a8a68f5SJulian Pullen td_dup(const ad_disc_trusteddomains_t *td) 3887a8a68f5SJulian Pullen { 3897a8a68f5SJulian Pullen int i; 3907a8a68f5SJulian Pullen int size; 3917a8a68f5SJulian Pullen ad_disc_trusteddomains_t *new = NULL; 3927a8a68f5SJulian Pullen 3937a8a68f5SJulian Pullen for (i = 0; td[i].domain[0] != '\0'; i++) 3947a8a68f5SJulian Pullen continue; 3957a8a68f5SJulian Pullen 3967a8a68f5SJulian Pullen size = (i + 1) * sizeof (ad_disc_trusteddomains_t); 3977a8a68f5SJulian Pullen new = malloc(size); 3987a8a68f5SJulian Pullen if (new != NULL) 399148c5f43SAlan Wright (void) memcpy(new, td, size); 4007a8a68f5SJulian Pullen return (new); 4017a8a68f5SJulian Pullen } 4027a8a68f5SJulian Pullen 4037a8a68f5SJulian Pullen 4047a8a68f5SJulian Pullen 4057a8a68f5SJulian Pullen int 4067a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1, 4077a8a68f5SJulian Pullen ad_disc_domainsinforest_t *df2) 4087a8a68f5SJulian Pullen { 4097a8a68f5SJulian Pullen int i, j; 4107a8a68f5SJulian Pullen int num_df1; 4117a8a68f5SJulian Pullen int num_df2; 4127a8a68f5SJulian Pullen boolean_t match; 4137a8a68f5SJulian Pullen 4147a8a68f5SJulian Pullen for (i = 0; df1[i].domain[0] != '\0'; i++) 4157a8a68f5SJulian Pullen continue; 4167a8a68f5SJulian Pullen num_df1 = i; 4177a8a68f5SJulian Pullen 4187a8a68f5SJulian Pullen for (j = 0; df2[j].domain[0] != '\0'; j++) 4197a8a68f5SJulian Pullen continue; 4207a8a68f5SJulian Pullen num_df2 = j; 4217a8a68f5SJulian Pullen 4227a8a68f5SJulian Pullen if (num_df1 != num_df2) 4237a8a68f5SJulian Pullen return (1); 4247a8a68f5SJulian Pullen 4257a8a68f5SJulian Pullen for (i = 0; i < num_df1; i++) { 4267a8a68f5SJulian Pullen match = B_FALSE; 4277a8a68f5SJulian 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; 4317a8a68f5SJulian Pullen break; 4327a8a68f5SJulian Pullen } 4337a8a68f5SJulian Pullen } 4347a8a68f5SJulian Pullen if (!match) 4357a8a68f5SJulian Pullen return (1); 4367a8a68f5SJulian Pullen } 4377a8a68f5SJulian Pullen return (0); 4387a8a68f5SJulian Pullen } 4397a8a68f5SJulian Pullen 4407a8a68f5SJulian Pullen 4417a8a68f5SJulian Pullen 4427a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */ 4437a8a68f5SJulian Pullen static ad_disc_domainsinforest_t * 4447a8a68f5SJulian Pullen df_dup(const ad_disc_domainsinforest_t *df) 4457a8a68f5SJulian Pullen { 4467a8a68f5SJulian Pullen int i; 4477a8a68f5SJulian Pullen int size; 4487a8a68f5SJulian Pullen ad_disc_domainsinforest_t *new = NULL; 4497a8a68f5SJulian Pullen 4507a8a68f5SJulian Pullen for (i = 0; df[i].domain[0] != '\0'; i++) 4517a8a68f5SJulian Pullen continue; 4527a8a68f5SJulian Pullen 4537a8a68f5SJulian Pullen size = (i + 1) * sizeof (ad_disc_domainsinforest_t); 4547a8a68f5SJulian Pullen new = malloc(size); 4557a8a68f5SJulian Pullen if (new != NULL) 456148c5f43SAlan Wright (void) memcpy(new, df, size); 4577a8a68f5SJulian Pullen return (new); 4587a8a68f5SJulian Pullen } 4597a8a68f5SJulian Pullen 4607a8a68f5SJulian Pullen 4617a8a68f5SJulian Pullen 4627a8a68f5SJulian Pullen 4637a8a68f5SJulian Pullen 4647a8a68f5SJulian Pullen /* 4657a8a68f5SJulian Pullen * Returns an array of IPv4 address/prefix length 4667a8a68f5SJulian Pullen * The last subnet is NULL 4677a8a68f5SJulian Pullen */ 4687a8a68f5SJulian Pullen static ad_subnet_t * 4697a8a68f5SJulian Pullen find_subnets() 4707a8a68f5SJulian Pullen { 4717a8a68f5SJulian Pullen int sock, n, i; 4727a8a68f5SJulian Pullen struct lifconf lifc; 4737a8a68f5SJulian Pullen struct lifreq lifr, *lifrp; 4747a8a68f5SJulian Pullen struct lifnum lifn; 4757a8a68f5SJulian Pullen uint32_t prefix_len; 4767a8a68f5SJulian Pullen char *s; 4777a8a68f5SJulian Pullen ad_subnet_t *results; 4787a8a68f5SJulian Pullen 4797a8a68f5SJulian Pullen lifrp = &lifr; 4807a8a68f5SJulian Pullen 4817a8a68f5SJulian Pullen if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 4827a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to open IPv4 socket for " 4837a8a68f5SJulian Pullen "listing network interfaces (%s)", strerror(errno)); 4847a8a68f5SJulian Pullen return (NULL); 4857a8a68f5SJulian Pullen } 4867a8a68f5SJulian Pullen 4877a8a68f5SJulian Pullen lifn.lifn_family = AF_INET; 4887a8a68f5SJulian Pullen lifn.lifn_flags = 0; 4897a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 4907a8a68f5SJulian Pullen logger(LOG_ERR, 4917a8a68f5SJulian Pullen "Failed to find the number of network interfaces (%s)", 4927a8a68f5SJulian Pullen strerror(errno)); 493148c5f43SAlan Wright (void) close(sock); 4947a8a68f5SJulian Pullen return (NULL); 4957a8a68f5SJulian Pullen } 4967a8a68f5SJulian Pullen 4977a8a68f5SJulian Pullen if (lifn.lifn_count < 1) { 4987a8a68f5SJulian Pullen logger(LOG_ERR, "No IPv4 network interfaces found"); 499148c5f43SAlan Wright (void) close(sock); 5007a8a68f5SJulian Pullen return (NULL); 5017a8a68f5SJulian Pullen } 5027a8a68f5SJulian Pullen 5037a8a68f5SJulian Pullen lifc.lifc_family = AF_INET; 5047a8a68f5SJulian Pullen lifc.lifc_flags = 0; 5057a8a68f5SJulian Pullen lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 5067a8a68f5SJulian Pullen lifc.lifc_buf = malloc(lifc.lifc_len); 5077a8a68f5SJulian Pullen 5087a8a68f5SJulian Pullen if (lifc.lifc_buf == NULL) { 5097a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 510148c5f43SAlan Wright (void) close(sock); 5117a8a68f5SJulian Pullen return (NULL); 5127a8a68f5SJulian Pullen } 5137a8a68f5SJulian Pullen 5147a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 5157a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to list network interfaces (%s)", 5167a8a68f5SJulian Pullen strerror(errno)); 5177a8a68f5SJulian Pullen free(lifc.lifc_buf); 518148c5f43SAlan Wright (void) close(sock); 5197a8a68f5SJulian Pullen return (NULL); 5207a8a68f5SJulian Pullen } 5217a8a68f5SJulian Pullen 5227a8a68f5SJulian Pullen n = lifc.lifc_len / (int)sizeof (struct lifreq); 5237a8a68f5SJulian Pullen 5247a8a68f5SJulian Pullen if ((results = calloc(n + 1, sizeof (ad_subnet_t))) == NULL) { 5257a8a68f5SJulian Pullen free(lifc.lifc_buf); 526148c5f43SAlan Wright (void) close(sock); 5277a8a68f5SJulian Pullen return (NULL); 5287a8a68f5SJulian Pullen } 5297a8a68f5SJulian Pullen 5307a8a68f5SJulian Pullen for (i = 0, lifrp = lifc.lifc_req; i < n; i++, lifrp++) { 5317a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFFLAGS, lifrp) < 0) 5327a8a68f5SJulian Pullen continue; 5337a8a68f5SJulian Pullen 5347a8a68f5SJulian Pullen if ((lifrp->lifr_flags & IFF_UP) == 0) 5357a8a68f5SJulian Pullen continue; 5367a8a68f5SJulian Pullen 5377a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFSUBNET, lifrp) < 0) 5387a8a68f5SJulian Pullen continue; 5397a8a68f5SJulian Pullen 5407a8a68f5SJulian Pullen prefix_len = lifrp->lifr_addrlen; 5417a8a68f5SJulian Pullen 5427a8a68f5SJulian Pullen s = inet_ntoa(((struct sockaddr_in *) 5437a8a68f5SJulian Pullen &lifrp->lifr_addr)->sin_addr); 5447a8a68f5SJulian Pullen 5457a8a68f5SJulian Pullen (void) snprintf(results[i].subnet, sizeof (ad_subnet_t), 5467a8a68f5SJulian Pullen "%s/%d", s, prefix_len); 5477a8a68f5SJulian Pullen } 5487a8a68f5SJulian Pullen 5497a8a68f5SJulian Pullen free(lifc.lifc_buf); 550148c5f43SAlan Wright (void) close(sock); 5517a8a68f5SJulian Pullen 5527a8a68f5SJulian Pullen return (results); 5537a8a68f5SJulian Pullen } 5547a8a68f5SJulian Pullen 5557a8a68f5SJulian Pullen static int 5567a8a68f5SJulian Pullen cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2) 5577a8a68f5SJulian Pullen { 5587a8a68f5SJulian Pullen int num_subnets1; 5597a8a68f5SJulian Pullen int num_subnets2; 5607a8a68f5SJulian Pullen boolean_t matched; 5617a8a68f5SJulian Pullen int i, j; 5627a8a68f5SJulian Pullen 5637a8a68f5SJulian Pullen for (i = 0; subnets1[i].subnet[0] != '\0'; i++) 5647a8a68f5SJulian Pullen continue; 5657a8a68f5SJulian Pullen num_subnets1 = i; 5667a8a68f5SJulian Pullen 5677a8a68f5SJulian Pullen for (i = 0; subnets2[i].subnet[0] != '\0'; i++) 5687a8a68f5SJulian Pullen continue; 5697a8a68f5SJulian Pullen num_subnets2 = i; 5707a8a68f5SJulian Pullen 5717a8a68f5SJulian Pullen if (num_subnets1 != num_subnets2) 5727a8a68f5SJulian Pullen return (1); 5737a8a68f5SJulian Pullen 5747a8a68f5SJulian Pullen for (i = 0; i < num_subnets1; i++) { 5757a8a68f5SJulian Pullen matched = B_FALSE; 5767a8a68f5SJulian Pullen for (j = 0; j < num_subnets2; j++) { 5777a8a68f5SJulian Pullen if (strcmp(subnets1[i].subnet, 5787a8a68f5SJulian Pullen subnets2[j].subnet) == 0) { 5797a8a68f5SJulian Pullen matched = B_TRUE; 5807a8a68f5SJulian Pullen break; 5817a8a68f5SJulian Pullen } 5827a8a68f5SJulian Pullen } 5837a8a68f5SJulian Pullen if (!matched) 5847a8a68f5SJulian Pullen return (1); 5857a8a68f5SJulian Pullen } 5867a8a68f5SJulian Pullen return (0); 5877a8a68f5SJulian Pullen } 5887a8a68f5SJulian Pullen 5897a8a68f5SJulian Pullen 5907a8a68f5SJulian Pullen 5917a8a68f5SJulian Pullen 5927a8a68f5SJulian Pullen /* Convert a DN's DC components into a DNS domainname */ 5937a8a68f5SJulian Pullen char * 5947a8a68f5SJulian Pullen DN_to_DNS(const char *dn_name) 5957a8a68f5SJulian Pullen { 5967a8a68f5SJulian Pullen char dns[DNS_MAX_NAME]; 5977a8a68f5SJulian Pullen char *dns_name; 5987a8a68f5SJulian Pullen int i, j; 5997a8a68f5SJulian Pullen int num = 0; 6007a8a68f5SJulian Pullen 6017a8a68f5SJulian Pullen j = 0; 6027a8a68f5SJulian Pullen i = 0; 6037a8a68f5SJulian Pullen 6047a8a68f5SJulian Pullen if (dn_name == NULL) 6057a8a68f5SJulian Pullen return (NULL); 6067a8a68f5SJulian Pullen /* 6077a8a68f5SJulian Pullen * Find all DC=<value> and form DNS name of the 6087a8a68f5SJulian Pullen * form <value1>.<value2>... 6097a8a68f5SJulian Pullen */ 6107a8a68f5SJulian Pullen while (dn_name[i] != '\0') { 6117a8a68f5SJulian Pullen if (strncasecmp(&dn_name[i], "DC=", 3) == 0) { 6127a8a68f5SJulian Pullen i += 3; 6137a8a68f5SJulian Pullen if (dn_name[i] != '\0' && num > 0) 6147a8a68f5SJulian Pullen dns[j++] = '.'; 6157a8a68f5SJulian Pullen while (dn_name[i] != '\0' && 6167a8a68f5SJulian Pullen dn_name[i] != ',' && dn_name[i] != '+') 6177a8a68f5SJulian Pullen dns[j++] = dn_name[i++]; 6187a8a68f5SJulian Pullen num++; 6197a8a68f5SJulian Pullen } else { 6207a8a68f5SJulian Pullen /* Skip attr=value as it is not DC= */ 6217a8a68f5SJulian Pullen while (dn_name[i] != '\0' && 6227a8a68f5SJulian Pullen dn_name[i] != ',' && dn_name[i] != '+') 6237a8a68f5SJulian Pullen i++; 6247a8a68f5SJulian Pullen } 6257a8a68f5SJulian Pullen /* Skip over separator ',' or '+' */ 6267a8a68f5SJulian Pullen if (dn_name[i] != '\0') i++; 6277a8a68f5SJulian Pullen } 6287a8a68f5SJulian Pullen dns[j] = '\0'; 6297a8a68f5SJulian Pullen dns_name = malloc(j + 1); 6307a8a68f5SJulian Pullen if (dns_name != NULL) 6317a8a68f5SJulian Pullen (void) strlcpy(dns_name, dns, j + 1); 6327a8a68f5SJulian Pullen return (dns_name); 6337a8a68f5SJulian Pullen } 6347a8a68f5SJulian Pullen 6357a8a68f5SJulian Pullen 6367a8a68f5SJulian Pullen /* 6377a8a68f5SJulian Pullen * A utility function to bind to a Directory server 6387a8a68f5SJulian Pullen */ 6397a8a68f5SJulian Pullen 640c5866007SKeyur Desai static 641c5866007SKeyur Desai LDAP * 642*b3700b07SGordon Ross ldap_lookup_init(ad_disc_ds_t *ds) 6437a8a68f5SJulian Pullen { 6447a8a68f5SJulian Pullen int i; 6457a8a68f5SJulian Pullen int rc, ldversion; 6467a8a68f5SJulian Pullen int zero = 0; 6477a8a68f5SJulian Pullen int timeoutms = 5 * 1000; 6487a8a68f5SJulian Pullen char *saslmech = "GSSAPI"; 6497a8a68f5SJulian Pullen uint32_t saslflags = LDAP_SASL_INTERACTIVE; 6507a8a68f5SJulian Pullen LDAP *ld = NULL; 6517a8a68f5SJulian Pullen 6527a8a68f5SJulian Pullen for (i = 0; ds[i].host[0] != '\0'; i++) { 653*b3700b07SGordon Ross if (DBG(LDAP, 2)) { 654*b3700b07SGordon Ross logger(LOG_DEBUG, "adutils: ldap_lookup_init, host %s", 655*b3700b07SGordon Ross ds[i].host); 656*b3700b07SGordon Ross } 657*b3700b07SGordon Ross 6587a8a68f5SJulian Pullen ld = ldap_init(ds[i].host, ds[i].port); 6597a8a68f5SJulian 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)", 6637a8a68f5SJulian Pullen ds[i].host, ds[i].port, 6647a8a68f5SJulian Pullen strerror(errno)); 665148c5f43SAlan Wright } 6667a8a68f5SJulian Pullen continue; 6677a8a68f5SJulian Pullen } 6687a8a68f5SJulian Pullen 6697a8a68f5SJulian Pullen ldversion = LDAP_VERSION3; 6707a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 6717a8a68f5SJulian Pullen &ldversion); 6727a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, 6737a8a68f5SJulian Pullen LDAP_OPT_OFF); 6747a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 6757a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 6767a8a68f5SJulian Pullen /* setup TCP/IP connect timeout */ 6777a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 6787a8a68f5SJulian Pullen &timeoutms); 6797a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_RESTART, 6807a8a68f5SJulian Pullen LDAP_OPT_ON); 6817a8a68f5SJulian 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 6907a8a68f5SJulian Pullen rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */, 6917a8a68f5SJulian Pullen saslmech, NULL, NULL, saslflags, &saslcallback, 6927a8a68f5SJulian Pullen NULL /* defaults */); 6937a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) 6947a8a68f5SJulian Pullen break; 6957a8a68f5SJulian Pullen 696148c5f43SAlan Wright if (DBG(LDAP, 0)) { 697148c5f43SAlan Wright logger(LOG_INFO, "LDAP: %s:%d: %s", 6987a8a68f5SJulian Pullen ds[i].host, ds[i].port, ldap_err2string(rc)); 699148c5f43SAlan Wright ldap_perror(ld, ds[i].host); 700148c5f43SAlan Wright } 7017a8a68f5SJulian Pullen (void) ldap_unbind(ld); 7027a8a68f5SJulian Pullen ld = NULL; 7037a8a68f5SJulian Pullen } 7047a8a68f5SJulian Pullen return (ld); 7057a8a68f5SJulian Pullen } 7067a8a68f5SJulian Pullen 7077a8a68f5SJulian Pullen 7087a8a68f5SJulian Pullen 7097a8a68f5SJulian Pullen /* 7107a8a68f5SJulian Pullen * Lookup the trusted domains in the global catalog. 7117a8a68f5SJulian Pullen * 7127a8a68f5SJulian Pullen * Returns: 7137a8a68f5SJulian Pullen * array of trusted domains which is terminated by 7147a8a68f5SJulian Pullen * an empty trusted domain. 7157a8a68f5SJulian Pullen * NULL an error occured 7167a8a68f5SJulian Pullen */ 7177a8a68f5SJulian Pullen ad_disc_trusteddomains_t * 718*b3700b07SGordon Ross ldap_lookup_trusted_domains(LDAP **ld, ad_disc_ds_t *globalCatalog, 7197a8a68f5SJulian Pullen char *base_dn) 7207a8a68f5SJulian Pullen { 7217a8a68f5SJulian Pullen int scope = LDAP_SCOPE_SUBTREE; 7227a8a68f5SJulian Pullen char *attrs[3]; 7237a8a68f5SJulian Pullen int rc; 7247a8a68f5SJulian Pullen LDAPMessage *results = NULL; 7257a8a68f5SJulian Pullen LDAPMessage *entry; 7267a8a68f5SJulian Pullen char *filter; 7277a8a68f5SJulian Pullen char **partner = NULL; 7287a8a68f5SJulian Pullen char **direction = NULL; 7297a8a68f5SJulian Pullen int num = 0; 7307a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 7317a8a68f5SJulian Pullen 732148c5f43SAlan Wright if (DBG(DISC, 1)) 733148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for trusted domains..."); 7347a8a68f5SJulian Pullen 7357a8a68f5SJulian Pullen if (*ld == NULL) 7367a8a68f5SJulian Pullen *ld = ldap_lookup_init(globalCatalog); 7377a8a68f5SJulian Pullen 738*b3700b07SGordon Ross if (*ld == NULL) { 739*b3700b07SGordon Ross logger(LOG_ERR, "adutils: ldap_lookup_init failed"); 7407a8a68f5SJulian Pullen return (NULL); 741*b3700b07SGordon Ross } 7427a8a68f5SJulian Pullen 7437a8a68f5SJulian Pullen attrs[0] = "trustPartner"; 7447a8a68f5SJulian Pullen attrs[1] = "trustDirection"; 7457a8a68f5SJulian Pullen attrs[2] = NULL; 7467a8a68f5SJulian 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 */ 7537a8a68f5SJulian Pullen filter = "(&(objectclass=trustedDomain)" 754148c5f43SAlan Wright "(|(trustDirection=3)(trustDirection=2)))"; 7557a8a68f5SJulian Pullen 7567a8a68f5SJulian 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:"); 7597a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) { 7607a8a68f5SJulian Pullen for (entry = ldap_first_entry(*ld, results); 7617a8a68f5SJulian Pullen entry != NULL; entry = ldap_next_entry(*ld, entry)) { 7627a8a68f5SJulian Pullen partner = ldap_get_values(*ld, entry, "trustPartner"); 7637a8a68f5SJulian Pullen direction = ldap_get_values( 7647a8a68f5SJulian Pullen *ld, entry, "trustDirection"); 7657a8a68f5SJulian Pullen 7667a8a68f5SJulian 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 } 7717a8a68f5SJulian Pullen num++; 772c5866007SKeyur Desai void *tmp = realloc(trusted_domains, 7737a8a68f5SJulian Pullen (num + 1) * 7747a8a68f5SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 775c5866007SKeyur Desai if (tmp == NULL) { 776c5866007SKeyur Desai free(trusted_domains); 7777a8a68f5SJulian Pullen ldap_value_free(partner); 7787a8a68f5SJulian Pullen ldap_value_free(direction); 779148c5f43SAlan Wright (void) ldap_msgfree(results); 7807a8a68f5SJulian Pullen return (NULL); 7817a8a68f5SJulian Pullen } 782c5866007SKeyur Desai trusted_domains = tmp; 7837a8a68f5SJulian Pullen /* Last element should be zero */ 784148c5f43SAlan Wright (void) memset(&trusted_domains[num], 0, 7857a8a68f5SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 786148c5f43SAlan Wright (void) strcpy(trusted_domains[num - 1].domain, 7877a8a68f5SJulian Pullen partner[0]); 7887a8a68f5SJulian Pullen trusted_domains[num - 1].direction = 7897a8a68f5SJulian Pullen atoi(direction[0]); 7907a8a68f5SJulian Pullen } 7917a8a68f5SJulian Pullen if (partner != NULL) 7927a8a68f5SJulian Pullen ldap_value_free(partner); 7937a8a68f5SJulian Pullen if (direction != NULL) 7947a8a68f5SJulian Pullen ldap_value_free(direction); 7957a8a68f5SJulian Pullen } 7967a8a68f5SJulian Pullen } else if (rc == LDAP_NO_RESULTS_RETURNED) { 7977a8a68f5SJulian Pullen /* This is not an error - return empty trusted domain */ 7987a8a68f5SJulian Pullen trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t)); 799148c5f43SAlan Wright if (DBG(DISC, 1)) 800148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 801*b3700b07SGordon Ross } else { 802*b3700b07SGordon Ross if (DBG(DISC, 1)) 803*b3700b07SGordon Ross logger(LOG_DEBUG, " rc=%d", rc); 8047a8a68f5SJulian Pullen } 8057a8a68f5SJulian Pullen if (results != NULL) 806148c5f43SAlan Wright (void) ldap_msgfree(results); 8077a8a68f5SJulian Pullen 8087a8a68f5SJulian Pullen return (trusted_domains); 8097a8a68f5SJulian Pullen } 8107a8a68f5SJulian Pullen 8117a8a68f5SJulian Pullen 8127a8a68f5SJulian Pullen /* 8137a8a68f5SJulian Pullen * This functions finds all the domains in a forest. 8147a8a68f5SJulian Pullen */ 8157a8a68f5SJulian Pullen ad_disc_domainsinforest_t * 816*b3700b07SGordon Ross ldap_lookup_domains_in_forest(LDAP **ld, ad_disc_ds_t *globalCatalogs) 8177a8a68f5SJulian Pullen { 818928e1f97SJordan Brown static char *attrs[] = { 819928e1f97SJordan Brown "objectSid", 820928e1f97SJordan Brown NULL, 821928e1f97SJordan Brown }; 8227a8a68f5SJulian Pullen int rc; 8237a8a68f5SJulian Pullen LDAPMessage *result = NULL; 8247a8a68f5SJulian Pullen LDAPMessage *entry; 825928e1f97SJordan Brown int ndomains = 0; 826928e1f97SJordan Brown int nresults; 8277a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains = NULL; 8287a8a68f5SJulian Pullen 829*b3700b07SGordon Ross if (DBG(DISC, 1)) 830148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for domains in forest..."); 831148c5f43SAlan Wright 8327a8a68f5SJulian Pullen if (*ld == NULL) 8337a8a68f5SJulian Pullen *ld = ldap_lookup_init(globalCatalogs); 8347a8a68f5SJulian Pullen 835*b3700b07SGordon Ross if (*ld == NULL) { 836*b3700b07SGordon Ross logger(LOG_ERR, "adutils: ldap_lookup_init failed"); 8377a8a68f5SJulian Pullen return (NULL); 838*b3700b07SGordon Ross } 8397a8a68f5SJulian Pullen 8407a8a68f5SJulian Pullen /* Find domains */ 841928e1f97SJordan Brown rc = ldap_search_s(*ld, "", LDAP_SCOPE_SUBTREE, 842928e1f97SJordan Brown "(objectClass=Domain)", attrs, 0, &result); 843*b3700b07SGordon Ross if (rc != LDAP_SUCCESS) { 844*b3700b07SGordon Ross logger(LOG_ERR, "adutils: ldap_search, rc=%d", rc); 845*b3700b07SGordon Ross goto err; 846*b3700b07SGordon 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)); 852*b3700b07SGordon Ross if (domains == NULL) { 853*b3700b07SGordon Ross if (DBG(DISC, 1)) 854*b3700b07SGordon Ross logger(LOG_DEBUG, " (nomem)"); 855928e1f97SJordan Brown goto err; 856*b3700b07SGordon 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; 864928e1f97SJordan Brown char *name; 865bbf6f00cSJordan Brown char *dn; 866928e1f97SJordan Brown 8677a8a68f5SJulian Pullen sid_ber = ldap_get_values_len(*ld, entry, 8687a8a68f5SJulian Pullen "objectSid"); 869928e1f97SJordan Brown if (sid_ber == NULL) 870928e1f97SJordan Brown continue; 8717a8a68f5SJulian Pullen 872928e1f97SJordan Brown rc = adutils_getsid(sid_ber[0], &sid); 8737a8a68f5SJulian Pullen ldap_value_free_len(sid_ber); 874928e1f97SJordan Brown if (rc < 0) 875928e1f97SJordan Brown goto err; 8767a8a68f5SJulian Pullen 877928e1f97SJordan Brown if ((sid_str = adutils_sid2txt(&sid)) == NULL) 878928e1f97SJordan Brown goto err; 879928e1f97SJordan Brown 880148c5f43SAlan Wright (void) strcpy(domains[ndomains].sid, sid_str); 8817a8a68f5SJulian Pullen free(sid_str); 8827a8a68f5SJulian Pullen 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); 8907a8a68f5SJulian Pullen free(name); 891928e1f97SJordan Brown 892148c5f43SAlan Wright if (DBG(DISC, 1)) 893148c5f43SAlan Wright logger(LOG_DEBUG, " %s", domains[ndomains].domain); 894928e1f97SJordan Brown 895928e1f97SJordan Brown ndomains++; 8967a8a68f5SJulian Pullen } 897928e1f97SJordan Brown 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; 906928e1f97SJordan Brown tmp = realloc(domains, (ndomains + 1) * sizeof (*domains)); 907928e1f97SJordan Brown if (tmp == NULL) 908928e1f97SJordan Brown goto err; 909928e1f97SJordan Brown domains = tmp; 9107a8a68f5SJulian Pullen } 911928e1f97SJordan Brown 9127a8a68f5SJulian Pullen if (result != NULL) 913148c5f43SAlan Wright (void) ldap_msgfree(result); 9147a8a68f5SJulian Pullen 9157a8a68f5SJulian 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); 9227a8a68f5SJulian Pullen } 9237a8a68f5SJulian Pullen 9247a8a68f5SJulian Pullen 9257a8a68f5SJulian Pullen ad_disc_t 9267a8a68f5SJulian Pullen ad_disc_init(void) 9277a8a68f5SJulian Pullen { 9287a8a68f5SJulian Pullen struct ad_disc *ctx; 9297a8a68f5SJulian Pullen ctx = calloc(1, sizeof (struct ad_disc)); 9307a8a68f5SJulian Pullen if (ctx != NULL) 9317a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 9327a8a68f5SJulian Pullen 9337a8a68f5SJulian Pullen ctx->domain_name.type = AD_STRING; 934*b3700b07SGordon Ross ctx->domain_guid.type = AD_UUID; 9357a8a68f5SJulian Pullen ctx->domain_controller.type = AD_DIRECTORY; 936*b3700b07SGordon Ross ctx->preferred_dc.type = AD_DIRECTORY; 9377a8a68f5SJulian Pullen ctx->site_name.type = AD_STRING; 9387a8a68f5SJulian Pullen ctx->forest_name.type = AD_STRING; 9397a8a68f5SJulian Pullen ctx->global_catalog.type = AD_DIRECTORY; 9407a8a68f5SJulian Pullen ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST; 9417a8a68f5SJulian Pullen ctx->trusted_domains.type = AD_TRUSTED_DOMAINS; 9427a8a68f5SJulian Pullen /* Site specific versions */ 9437a8a68f5SJulian Pullen ctx->site_domain_controller.type = AD_DIRECTORY; 9447a8a68f5SJulian Pullen ctx->site_global_catalog.type = AD_DIRECTORY; 9457a8a68f5SJulian Pullen return (ctx); 9467a8a68f5SJulian Pullen } 9477a8a68f5SJulian Pullen 9487a8a68f5SJulian Pullen void 9497a8a68f5SJulian Pullen ad_disc_fini(ad_disc_t ctx) 9507a8a68f5SJulian Pullen { 9517a8a68f5SJulian Pullen if (ctx == NULL) 9527a8a68f5SJulian Pullen return; 9537a8a68f5SJulian Pullen 9547a8a68f5SJulian Pullen if (ctx->res_ninitted) 9557a8a68f5SJulian Pullen res_ndestroy(&ctx->res_state); 9567a8a68f5SJulian Pullen 9577a8a68f5SJulian Pullen if (ctx->subnets != NULL) 9587a8a68f5SJulian Pullen free(ctx->subnets); 9597a8a68f5SJulian Pullen 9607a8a68f5SJulian Pullen if (ctx->domain_name.value != NULL) 9617a8a68f5SJulian Pullen free(ctx->domain_name.value); 9627a8a68f5SJulian Pullen 963*b3700b07SGordon Ross if (ctx->domain_guid.value != NULL) 964*b3700b07SGordon Ross free(ctx->domain_guid.value); 965*b3700b07SGordon Ross 9667a8a68f5SJulian Pullen if (ctx->domain_controller.value != NULL) 9677a8a68f5SJulian Pullen free(ctx->domain_controller.value); 9687a8a68f5SJulian Pullen 969*b3700b07SGordon Ross if (ctx->preferred_dc.value != NULL) 970*b3700b07SGordon Ross free(ctx->preferred_dc.value); 971*b3700b07SGordon Ross 9727a8a68f5SJulian Pullen if (ctx->site_name.value != NULL) 9737a8a68f5SJulian Pullen free(ctx->site_name.value); 9747a8a68f5SJulian Pullen 9757a8a68f5SJulian Pullen if (ctx->forest_name.value != NULL) 9767a8a68f5SJulian Pullen free(ctx->forest_name.value); 9777a8a68f5SJulian Pullen 9787a8a68f5SJulian Pullen if (ctx->global_catalog.value != NULL) 9797a8a68f5SJulian Pullen free(ctx->global_catalog.value); 9807a8a68f5SJulian Pullen 9817a8a68f5SJulian Pullen if (ctx->domains_in_forest.value != NULL) 9827a8a68f5SJulian Pullen free(ctx->domains_in_forest.value); 9837a8a68f5SJulian Pullen 9847a8a68f5SJulian Pullen if (ctx->trusted_domains.value != NULL) 9857a8a68f5SJulian Pullen free(ctx->trusted_domains.value); 9867a8a68f5SJulian Pullen 9877a8a68f5SJulian Pullen /* Site specific versions */ 9887a8a68f5SJulian Pullen if (ctx->site_domain_controller.value != NULL) 9897a8a68f5SJulian Pullen free(ctx->site_domain_controller.value); 9907a8a68f5SJulian Pullen 9917a8a68f5SJulian Pullen if (ctx->site_global_catalog.value != NULL) 9927a8a68f5SJulian Pullen free(ctx->site_global_catalog.value); 9937a8a68f5SJulian Pullen 9947a8a68f5SJulian Pullen free(ctx); 9957a8a68f5SJulian Pullen } 9967a8a68f5SJulian Pullen 9977a8a68f5SJulian Pullen void 9987a8a68f5SJulian Pullen ad_disc_refresh(ad_disc_t ctx) 9997a8a68f5SJulian Pullen { 1000*b3700b07SGordon Ross if (ctx->res_ninitted) { 10017a8a68f5SJulian Pullen res_ndestroy(&ctx->res_state); 1002*b3700b07SGordon Ross ctx->res_ninitted = 0; 1003*b3700b07SGordon Ross } 10047a8a68f5SJulian Pullen (void) memset(&ctx->res_state, 0, sizeof (ctx->res_state)); 1005*b3700b07SGordon Ross DO_RES_NINIT(ctx); 10067a8a68f5SJulian Pullen 10077a8a68f5SJulian Pullen if (ctx->domain_name.state == AD_STATE_AUTO) 10087a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 10097a8a68f5SJulian Pullen 1010*b3700b07SGordon Ross if (ctx->domain_guid.state == AD_STATE_AUTO) 1011*b3700b07SGordon Ross ctx->domain_guid.state = AD_STATE_INVALID; 1012*b3700b07SGordon Ross 10137a8a68f5SJulian Pullen if (ctx->domain_controller.state == AD_STATE_AUTO) 10147a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 10157a8a68f5SJulian Pullen 1016*b3700b07SGordon Ross if (ctx->preferred_dc.state == AD_STATE_AUTO) 1017*b3700b07SGordon Ross ctx->preferred_dc.state = AD_STATE_INVALID; 1018*b3700b07SGordon Ross 10197a8a68f5SJulian Pullen if (ctx->site_name.state == AD_STATE_AUTO) 10207a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 10217a8a68f5SJulian Pullen 10227a8a68f5SJulian Pullen if (ctx->forest_name.state == AD_STATE_AUTO) 10237a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 10247a8a68f5SJulian Pullen 10257a8a68f5SJulian Pullen if (ctx->global_catalog.state == AD_STATE_AUTO) 10267a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 10277a8a68f5SJulian Pullen 10287a8a68f5SJulian Pullen if (ctx->domains_in_forest.state == AD_STATE_AUTO) 10297a8a68f5SJulian Pullen ctx->domains_in_forest.state = AD_STATE_INVALID; 10307a8a68f5SJulian Pullen 10317a8a68f5SJulian Pullen if (ctx->trusted_domains.state == AD_STATE_AUTO) 10327a8a68f5SJulian Pullen ctx->trusted_domains.state = AD_STATE_INVALID; 10337a8a68f5SJulian Pullen 10347a8a68f5SJulian Pullen if (ctx->site_domain_controller.state == AD_STATE_AUTO) 10357a8a68f5SJulian Pullen ctx->site_domain_controller.state = AD_STATE_INVALID; 10367a8a68f5SJulian Pullen 10377a8a68f5SJulian Pullen if (ctx->site_global_catalog.state == AD_STATE_AUTO) 10387a8a68f5SJulian Pullen ctx->site_global_catalog.state = AD_STATE_INVALID; 10397a8a68f5SJulian Pullen } 10407a8a68f5SJulian Pullen 10417a8a68f5SJulian Pullen 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 1058*b3700b07SGordon Ross static void 1059*b3700b07SGordon Ross log_cds(ad_disc_t ctx, ad_disc_cds_t *cds) 1060*b3700b07SGordon Ross { 1061*b3700b07SGordon Ross char buf[INET6_ADDRSTRLEN]; 1062*b3700b07SGordon Ross struct addrinfo *ai; 1063*b3700b07SGordon Ross 1064*b3700b07SGordon Ross if (!DBG(DISC, 1) && ctx->status_fp == NULL) 1065*b3700b07SGordon Ross return; 1066*b3700b07SGordon Ross 1067*b3700b07SGordon Ross DEBUG1STATUS(ctx, "Candidate servers:"); 1068*b3700b07SGordon Ross if (cds->cds_ds.host[0] == '\0') { 1069*b3700b07SGordon Ross DEBUG1STATUS(ctx, " (empty list)"); 1070*b3700b07SGordon Ross return; 1071*b3700b07SGordon Ross } 1072*b3700b07SGordon Ross 1073*b3700b07SGordon Ross while (cds->cds_ds.host[0] != '\0') { 1074*b3700b07SGordon Ross 1075*b3700b07SGordon Ross DEBUG1STATUS(ctx, " %s p=%d w=%d", 1076*b3700b07SGordon Ross cds->cds_ds.host, 1077*b3700b07SGordon Ross cds->cds_ds.priority, 1078*b3700b07SGordon Ross cds->cds_ds.weight); 1079*b3700b07SGordon Ross 1080*b3700b07SGordon Ross ai = cds->cds_ai; 1081*b3700b07SGordon Ross if (ai == NULL) { 1082*b3700b07SGordon Ross DEBUG1STATUS(ctx, " (no address)"); 1083*b3700b07SGordon Ross } 1084*b3700b07SGordon Ross while (ai != NULL) { 1085*b3700b07SGordon Ross int eai; 1086*b3700b07SGordon Ross 1087*b3700b07SGordon Ross eai = getnameinfo(ai->ai_addr, ai->ai_addrlen, 1088*b3700b07SGordon Ross buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); 1089*b3700b07SGordon Ross if (eai != 0) 1090*b3700b07SGordon Ross (void) strlcpy(buf, "?", sizeof (buf)); 1091*b3700b07SGordon Ross 1092*b3700b07SGordon Ross DEBUG1STATUS(ctx, " %s", buf); 1093*b3700b07SGordon Ross ai = ai->ai_next; 1094*b3700b07SGordon Ross } 1095*b3700b07SGordon Ross cds++; 1096*b3700b07SGordon Ross } 1097*b3700b07SGordon Ross } 1098*b3700b07SGordon Ross 1099*b3700b07SGordon Ross static void 1100*b3700b07SGordon Ross log_ds(ad_disc_t ctx, ad_disc_ds_t *ds) 1101*b3700b07SGordon Ross { 1102*b3700b07SGordon Ross char buf[INET6_ADDRSTRLEN]; 1103*b3700b07SGordon Ross 1104*b3700b07SGordon Ross if (!DBG(DISC, 1) && ctx->status_fp == NULL) 1105*b3700b07SGordon Ross return; 1106*b3700b07SGordon Ross 1107*b3700b07SGordon Ross DEBUG1STATUS(ctx, "Responding servers:"); 1108*b3700b07SGordon Ross if (ds->host[0] == '\0') { 1109*b3700b07SGordon Ross DEBUG1STATUS(ctx, " (empty list)"); 1110*b3700b07SGordon Ross return; 1111*b3700b07SGordon Ross } 1112*b3700b07SGordon Ross 1113*b3700b07SGordon Ross while (ds->host[0] != '\0') { 1114*b3700b07SGordon Ross 1115*b3700b07SGordon Ross DEBUG1STATUS(ctx, " %s", ds->host); 1116*b3700b07SGordon Ross DO_GETNAMEINFO(buf, sizeof (buf), &ds->addr); 1117*b3700b07SGordon Ross DEBUG1STATUS(ctx, " %s", buf); 1118*b3700b07SGordon Ross 1119*b3700b07SGordon Ross ds++; 1120*b3700b07SGordon Ross } 1121*b3700b07SGordon Ross } 11227a8a68f5SJulian Pullen 11237a8a68f5SJulian Pullen /* Discover joined Active Directory domainName */ 11247a8a68f5SJulian Pullen static ad_item_t * 11257a8a68f5SJulian Pullen validate_DomainName(ad_disc_t ctx) 11267a8a68f5SJulian Pullen { 11277a8a68f5SJulian Pullen char *dname, *srvname; 1128*b3700b07SGordon Ross int len, rc; 11297a8a68f5SJulian Pullen 11307a8a68f5SJulian Pullen if (is_valid(&ctx->domain_name)) 11317a8a68f5SJulian Pullen return (&ctx->domain_name); 11327a8a68f5SJulian Pullen 11337a8a68f5SJulian Pullen 11347a8a68f5SJulian Pullen /* Try to find our domain by searching for DCs for it */ 11357a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1136*b3700b07SGordon Ross if (DBG(DISC, 1)) 1137148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for our AD domain name..."); 1138*b3700b07SGordon Ross rc = srv_getdom(&ctx->res_state, 1139*b3700b07SGordon Ross LDAP_SRV_HEAD DC_SRV_TAIL, &srvname); 11407a8a68f5SJulian Pullen 11417a8a68f5SJulian Pullen /* 11427a8a68f5SJulian Pullen * If we can't find DCs by via res_nsearch() then there's no 11437a8a68f5SJulian Pullen * point in trying anything else to discover the AD domain name. 11447a8a68f5SJulian Pullen */ 1145*b3700b07SGordon Ross if (rc < 0) { 1146148c5f43SAlan Wright if (DBG(DISC, 1)) 1147148c5f43SAlan Wright logger(LOG_DEBUG, "Can't find our domain name."); 11487a8a68f5SJulian Pullen return (NULL); 1149148c5f43SAlan Wright } 11507a8a68f5SJulian Pullen 11517a8a68f5SJulian Pullen /* 11527a8a68f5SJulian Pullen * We have the FQDN of the SRV RR name, so now we extract the 11537a8a68f5SJulian Pullen * domainname suffix from it. 11547a8a68f5SJulian Pullen */ 11557a8a68f5SJulian Pullen dname = strdup(srvname + strlen(LDAP_SRV_HEAD DC_SRV_TAIL) + 11567a8a68f5SJulian Pullen 1 /* for the dot between RR name and domainname */); 11577a8a68f5SJulian Pullen 11587a8a68f5SJulian Pullen free(srvname); 11597a8a68f5SJulian Pullen 11607a8a68f5SJulian Pullen if (dname == NULL) { 11617a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 11627a8a68f5SJulian Pullen return (NULL); 11637a8a68f5SJulian Pullen } 11647a8a68f5SJulian Pullen 11657a8a68f5SJulian Pullen /* Eat any trailing dot */ 1166928e1f97SJordan Brown len = strlen(dname); 1167928e1f97SJordan Brown if (len > 0 && dname[len - 1] == '.') 1168928e1f97SJordan Brown dname[len - 1] = '\0'; 11697a8a68f5SJulian Pullen 1170148c5f43SAlan Wright if (DBG(DISC, 1)) 1171148c5f43SAlan Wright logger(LOG_DEBUG, "Our domain name: %s", dname); 1172*b3700b07SGordon Ross 1173*b3700b07SGordon Ross /* 1174*b3700b07SGordon Ross * There is no "time to live" on the discovered domain, 1175*b3700b07SGordon Ross * so passing zero as TTL here, making it non-expiring. 1176*b3700b07SGordon Ross * Note that current consumers do not auto-discover the 1177*b3700b07SGordon Ross * domain name, though a future installer could. 1178*b3700b07SGordon Ross */ 1179*b3700b07SGordon Ross update_item(&ctx->domain_name, dname, AD_STATE_AUTO, 0); 11807a8a68f5SJulian Pullen 11817a8a68f5SJulian Pullen return (&ctx->domain_name); 11827a8a68f5SJulian Pullen } 11837a8a68f5SJulian Pullen 11847a8a68f5SJulian Pullen 11857a8a68f5SJulian Pullen char * 11867a8a68f5SJulian Pullen ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered) 11877a8a68f5SJulian Pullen { 11887a8a68f5SJulian Pullen char *domain_name = NULL; 11897a8a68f5SJulian Pullen ad_item_t *domain_name_item; 11907a8a68f5SJulian Pullen 11917a8a68f5SJulian Pullen domain_name_item = validate_DomainName(ctx); 11927a8a68f5SJulian Pullen 11937a8a68f5SJulian Pullen if (domain_name_item) { 11947a8a68f5SJulian Pullen domain_name = strdup(domain_name_item->value); 11957a8a68f5SJulian Pullen if (auto_discovered != NULL) 11967a8a68f5SJulian Pullen *auto_discovered = 11977a8a68f5SJulian Pullen (domain_name_item->state == AD_STATE_AUTO); 11987a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 11997a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 12007a8a68f5SJulian Pullen 12017a8a68f5SJulian Pullen return (domain_name); 12027a8a68f5SJulian Pullen } 12037a8a68f5SJulian Pullen 12047a8a68f5SJulian Pullen 12057a8a68f5SJulian Pullen /* Discover domain controllers */ 12067a8a68f5SJulian Pullen static ad_item_t * 12077a8a68f5SJulian Pullen validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) 12087a8a68f5SJulian Pullen { 1209*b3700b07SGordon Ross ad_disc_ds_t *dc = NULL; 1210*b3700b07SGordon Ross ad_disc_cds_t *cdc = NULL; 12117a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 12127a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 12137a8a68f5SJulian Pullen ad_item_t *domain_name_item; 1214*b3700b07SGordon Ross char *domain_name; 12157a8a68f5SJulian Pullen ad_item_t *site_name_item = NULL; 1216*b3700b07SGordon Ross char *site_name; 1217*b3700b07SGordon Ross ad_item_t *prefer_dc_item; 1218*b3700b07SGordon Ross ad_disc_ds_t *prefer_dc = NULL; 12197a8a68f5SJulian Pullen 12207a8a68f5SJulian Pullen /* If the values is fixed there will not be a site specific version */ 12217a8a68f5SJulian Pullen if (is_fixed(&ctx->domain_controller)) 12227a8a68f5SJulian Pullen return (&ctx->domain_controller); 12237a8a68f5SJulian Pullen 12247a8a68f5SJulian Pullen domain_name_item = validate_DomainName(ctx); 12257a8a68f5SJulian Pullen if (domain_name_item == NULL) 12267a8a68f5SJulian Pullen return (NULL); 1227*b3700b07SGordon Ross domain_name = (char *)domain_name_item->value; 1228*b3700b07SGordon Ross 1229*b3700b07SGordon Ross /* Get (optional) preferred DC. */ 1230*b3700b07SGordon Ross prefer_dc_item = validate_PreferredDC(ctx); 1231*b3700b07SGordon Ross if (prefer_dc_item != NULL) 1232*b3700b07SGordon Ross prefer_dc = prefer_dc_item->value; 12337a8a68f5SJulian Pullen 12347a8a68f5SJulian Pullen if (req == AD_DISC_GLOBAL) 12357a8a68f5SJulian Pullen validate_global = B_TRUE; 12367a8a68f5SJulian Pullen else { 1237*b3700b07SGordon Ross if (is_fixed(&ctx->site_name)) 12387a8a68f5SJulian Pullen validate_site = B_TRUE; 12397a8a68f5SJulian Pullen else if (req == AD_DISC_PREFER_SITE) 12407a8a68f5SJulian Pullen validate_global = B_TRUE; 12417a8a68f5SJulian Pullen } 12427a8a68f5SJulian Pullen 12437a8a68f5SJulian Pullen if (validate_global) { 12447a8a68f5SJulian Pullen if (!is_valid(&ctx->domain_controller) || 12457a8a68f5SJulian Pullen is_changed(&ctx->domain_controller, PARAM1, 12467a8a68f5SJulian Pullen domain_name_item)) { 1247*b3700b07SGordon Ross 12487a8a68f5SJulian Pullen /* 12497a8a68f5SJulian Pullen * Lookup DNS SRV RR named 12507a8a68f5SJulian Pullen * _ldap._tcp.dc._msdcs.<DomainName> 12517a8a68f5SJulian Pullen */ 1252*b3700b07SGordon Ross DEBUG1STATUS(ctx, "DNS SRV query, dom=%s", 1253*b3700b07SGordon Ross domain_name); 12547a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1255*b3700b07SGordon Ross cdc = srv_query(&ctx->res_state, 12567a8a68f5SJulian Pullen LDAP_SRV_HEAD DC_SRV_TAIL, 1257*b3700b07SGordon Ross domain_name, prefer_dc); 12587a8a68f5SJulian Pullen 1259*b3700b07SGordon Ross if (cdc == NULL) { 1260*b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no DNS response)"); 12617a8a68f5SJulian Pullen return (NULL); 1262148c5f43SAlan Wright } 1263*b3700b07SGordon Ross log_cds(ctx, cdc); 1264148c5f43SAlan Wright 1265*b3700b07SGordon Ross /* 1266*b3700b07SGordon Ross * Filter out unresponsive servers, and 1267*b3700b07SGordon Ross * save the domain info we get back. 1268*b3700b07SGordon Ross */ 1269*b3700b07SGordon Ross dc = ldap_ping( 1270*b3700b07SGordon Ross ctx, 1271*b3700b07SGordon Ross cdc, 1272*b3700b07SGordon Ross domain_name, 1273*b3700b07SGordon Ross DS_DS_FLAG); 1274*b3700b07SGordon Ross srv_free(cdc); 1275*b3700b07SGordon Ross cdc = NULL; 1276148c5f43SAlan Wright 1277*b3700b07SGordon Ross if (dc == NULL) { 1278*b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no LDAP response)"); 1279*b3700b07SGordon Ross return (NULL); 1280148c5f43SAlan Wright } 1281*b3700b07SGordon Ross log_ds(ctx, dc); 12827a8a68f5SJulian Pullen 1283*b3700b07SGordon Ross update_item(&ctx->domain_controller, dc, 1284*b3700b07SGordon Ross AD_STATE_AUTO, dc->ttl); 12857a8a68f5SJulian Pullen update_version(&ctx->domain_controller, PARAM1, 12867a8a68f5SJulian Pullen domain_name_item); 12877a8a68f5SJulian Pullen } 12887a8a68f5SJulian Pullen return (&ctx->domain_controller); 12897a8a68f5SJulian Pullen } 12907a8a68f5SJulian Pullen 12917a8a68f5SJulian Pullen if (validate_site) { 1292*b3700b07SGordon Ross site_name_item = &ctx->site_name; 1293*b3700b07SGordon Ross site_name = (char *)site_name_item->value; 1294*b3700b07SGordon Ross 12957a8a68f5SJulian Pullen if (!is_valid(&ctx->site_domain_controller) || 12967a8a68f5SJulian Pullen is_changed(&ctx->site_domain_controller, PARAM1, 12977a8a68f5SJulian Pullen domain_name_item) || 12987a8a68f5SJulian Pullen is_changed(&ctx->site_domain_controller, PARAM2, 12997a8a68f5SJulian Pullen site_name_item)) { 13007a8a68f5SJulian Pullen char rr_name[DNS_MAX_NAME]; 1301*b3700b07SGordon Ross 13027a8a68f5SJulian Pullen /* 13037a8a68f5SJulian Pullen * Lookup DNS SRV RR named 13047a8a68f5SJulian Pullen * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName> 13057a8a68f5SJulian Pullen */ 1306*b3700b07SGordon Ross DEBUG1STATUS(ctx, "DNS SRV query, dom=%s, site=%s", 1307*b3700b07SGordon Ross domain_name, site_name); 13087a8a68f5SJulian Pullen (void) snprintf(rr_name, sizeof (rr_name), 13097a8a68f5SJulian Pullen LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, 1310*b3700b07SGordon Ross site_name); 13117a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1312*b3700b07SGordon Ross cdc = srv_query(&ctx->res_state, rr_name, 1313*b3700b07SGordon Ross domain_name, prefer_dc); 1314*b3700b07SGordon Ross 1315*b3700b07SGordon Ross if (cdc == NULL) { 1316*b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no DNS response)"); 13177a8a68f5SJulian Pullen return (NULL); 1318148c5f43SAlan Wright } 1319*b3700b07SGordon Ross log_cds(ctx, cdc); 1320148c5f43SAlan Wright 1321*b3700b07SGordon Ross /* 1322*b3700b07SGordon Ross * Filter out unresponsive servers, and 1323*b3700b07SGordon Ross * save the domain info we get back. 1324*b3700b07SGordon Ross */ 1325*b3700b07SGordon Ross dc = ldap_ping( 1326*b3700b07SGordon Ross ctx, 1327*b3700b07SGordon Ross cdc, 1328*b3700b07SGordon Ross domain_name, 1329*b3700b07SGordon Ross DS_DS_FLAG); 1330*b3700b07SGordon Ross srv_free(cdc); 1331*b3700b07SGordon Ross cdc = NULL; 1332148c5f43SAlan Wright 1333*b3700b07SGordon Ross if (dc == NULL) { 1334*b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no LDAP response)"); 1335*b3700b07SGordon Ross return (NULL); 1336148c5f43SAlan Wright } 1337*b3700b07SGordon Ross log_ds(ctx, dc); 13387a8a68f5SJulian Pullen 1339*b3700b07SGordon Ross update_item(&ctx->site_domain_controller, dc, 1340*b3700b07SGordon Ross AD_STATE_AUTO, dc->ttl); 13417a8a68f5SJulian Pullen update_version(&ctx->site_domain_controller, PARAM1, 13427a8a68f5SJulian Pullen domain_name_item); 13437a8a68f5SJulian Pullen update_version(&ctx->site_domain_controller, PARAM2, 13447a8a68f5SJulian Pullen site_name_item); 13457a8a68f5SJulian Pullen } 13467a8a68f5SJulian Pullen return (&ctx->site_domain_controller); 13477a8a68f5SJulian Pullen } 13487a8a68f5SJulian Pullen return (NULL); 13497a8a68f5SJulian Pullen } 13507a8a68f5SJulian Pullen 1351*b3700b07SGordon Ross ad_disc_ds_t * 13527a8a68f5SJulian Pullen ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, 13537a8a68f5SJulian Pullen boolean_t *auto_discovered) 13547a8a68f5SJulian Pullen { 13557a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 1356*b3700b07SGordon Ross ad_disc_ds_t *domain_controller = NULL; 13577a8a68f5SJulian Pullen 13587a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, req); 13597a8a68f5SJulian Pullen 13607a8a68f5SJulian Pullen if (domain_controller_item != NULL) { 13617a8a68f5SJulian Pullen domain_controller = ds_dup(domain_controller_item->value); 13627a8a68f5SJulian Pullen if (auto_discovered != NULL) 13637a8a68f5SJulian Pullen *auto_discovered = 13647a8a68f5SJulian Pullen (domain_controller_item->state == AD_STATE_AUTO); 13657a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 13667a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 13677a8a68f5SJulian Pullen 13687a8a68f5SJulian Pullen return (domain_controller); 13697a8a68f5SJulian Pullen } 13707a8a68f5SJulian Pullen 13717a8a68f5SJulian Pullen 1372*b3700b07SGordon Ross /* 1373*b3700b07SGordon Ross * Discover the Domain GUID 1374*b3700b07SGordon Ross * This info comes from validate_DomainController() 1375*b3700b07SGordon Ross */ 1376*b3700b07SGordon Ross static ad_item_t * 1377*b3700b07SGordon Ross validate_DomainGUID(ad_disc_t ctx) 1378*b3700b07SGordon Ross { 1379*b3700b07SGordon Ross ad_item_t *domain_controller_item; 1380*b3700b07SGordon Ross 1381*b3700b07SGordon Ross if (is_fixed(&ctx->domain_guid)) 1382*b3700b07SGordon Ross return (&ctx->domain_guid); 1383*b3700b07SGordon Ross 1384*b3700b07SGordon Ross domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1385*b3700b07SGordon Ross if (domain_controller_item == NULL) 1386*b3700b07SGordon Ross return (NULL); 1387*b3700b07SGordon Ross 1388*b3700b07SGordon Ross if (!is_valid(&ctx->domain_guid)) 1389*b3700b07SGordon Ross return (NULL); 1390*b3700b07SGordon Ross 1391*b3700b07SGordon Ross return (&ctx->domain_guid); 1392*b3700b07SGordon Ross } 1393*b3700b07SGordon Ross 1394*b3700b07SGordon Ross 1395*b3700b07SGordon Ross uchar_t * 1396*b3700b07SGordon Ross ad_disc_get_DomainGUID(ad_disc_t ctx, boolean_t *auto_discovered) 1397*b3700b07SGordon Ross { 1398*b3700b07SGordon Ross ad_item_t *domain_guid_item; 1399*b3700b07SGordon Ross uchar_t *domain_guid = NULL; 1400*b3700b07SGordon Ross 1401*b3700b07SGordon Ross domain_guid_item = validate_DomainGUID(ctx); 1402*b3700b07SGordon Ross if (domain_guid_item != NULL) { 1403*b3700b07SGordon Ross domain_guid = uuid_dup(domain_guid_item->value); 1404*b3700b07SGordon Ross if (auto_discovered != NULL) 1405*b3700b07SGordon Ross *auto_discovered = 1406*b3700b07SGordon Ross (domain_guid_item->state == AD_STATE_AUTO); 1407*b3700b07SGordon Ross } else if (auto_discovered != NULL) 1408*b3700b07SGordon Ross *auto_discovered = B_FALSE; 1409*b3700b07SGordon Ross 1410*b3700b07SGordon Ross return (domain_guid); 1411*b3700b07SGordon Ross } 1412*b3700b07SGordon Ross 1413*b3700b07SGordon Ross 1414*b3700b07SGordon Ross /* 1415*b3700b07SGordon Ross * Discover site name (for multi-homed systems the first one found wins) 1416*b3700b07SGordon Ross * This info comes from validate_DomainController() 1417*b3700b07SGordon Ross */ 14187a8a68f5SJulian Pullen static ad_item_t * 14197a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx) 14207a8a68f5SJulian Pullen { 14217a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 14227a8a68f5SJulian Pullen 14237a8a68f5SJulian Pullen if (is_fixed(&ctx->site_name)) 14247a8a68f5SJulian Pullen return (&ctx->site_name); 14257a8a68f5SJulian Pullen 14267a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 14277a8a68f5SJulian Pullen if (domain_controller_item == NULL) 14287a8a68f5SJulian Pullen return (NULL); 14297a8a68f5SJulian Pullen 1430*b3700b07SGordon Ross if (!is_valid(&ctx->site_name)) 14317a8a68f5SJulian Pullen return (NULL); 14327a8a68f5SJulian Pullen 14337a8a68f5SJulian Pullen return (&ctx->site_name); 14347a8a68f5SJulian Pullen } 14357a8a68f5SJulian Pullen 14367a8a68f5SJulian Pullen 14377a8a68f5SJulian Pullen char * 14387a8a68f5SJulian Pullen ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered) 14397a8a68f5SJulian Pullen { 14407a8a68f5SJulian Pullen ad_item_t *site_name_item; 14417a8a68f5SJulian Pullen char *site_name = NULL; 14427a8a68f5SJulian Pullen 14437a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 14447a8a68f5SJulian Pullen if (site_name_item != NULL) { 14457a8a68f5SJulian Pullen site_name = strdup(site_name_item->value); 14467a8a68f5SJulian Pullen if (auto_discovered != NULL) 14477a8a68f5SJulian Pullen *auto_discovered = 14487a8a68f5SJulian Pullen (site_name_item->state == AD_STATE_AUTO); 14497a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 14507a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 14517a8a68f5SJulian Pullen 14527a8a68f5SJulian Pullen return (site_name); 14537a8a68f5SJulian Pullen } 14547a8a68f5SJulian Pullen 14557a8a68f5SJulian Pullen 14567a8a68f5SJulian Pullen 1457*b3700b07SGordon Ross /* 1458*b3700b07SGordon Ross * Discover forest name 1459*b3700b07SGordon Ross * This info comes from validate_DomainController() 1460*b3700b07SGordon Ross */ 14617a8a68f5SJulian Pullen static ad_item_t * 14627a8a68f5SJulian Pullen validate_ForestName(ad_disc_t ctx) 14637a8a68f5SJulian Pullen { 14647a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 14657a8a68f5SJulian Pullen 14667a8a68f5SJulian Pullen if (is_fixed(&ctx->forest_name)) 14677a8a68f5SJulian Pullen return (&ctx->forest_name); 1468*b3700b07SGordon Ross 14697a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 14707a8a68f5SJulian Pullen if (domain_controller_item == NULL) 14717a8a68f5SJulian Pullen return (NULL); 14727a8a68f5SJulian Pullen 1473*b3700b07SGordon Ross if (!is_valid(&ctx->forest_name)) 14747a8a68f5SJulian Pullen return (NULL); 1475148c5f43SAlan Wright 14767a8a68f5SJulian Pullen return (&ctx->forest_name); 14777a8a68f5SJulian Pullen } 14787a8a68f5SJulian Pullen 14797a8a68f5SJulian Pullen 14807a8a68f5SJulian Pullen char * 14817a8a68f5SJulian Pullen ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered) 14827a8a68f5SJulian Pullen { 14837a8a68f5SJulian Pullen ad_item_t *forest_name_item; 14847a8a68f5SJulian Pullen char *forest_name = NULL; 14857a8a68f5SJulian Pullen 14867a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 14877a8a68f5SJulian Pullen 14887a8a68f5SJulian Pullen if (forest_name_item != NULL) { 14897a8a68f5SJulian Pullen forest_name = strdup(forest_name_item->value); 14907a8a68f5SJulian Pullen if (auto_discovered != NULL) 14917a8a68f5SJulian Pullen *auto_discovered = 14927a8a68f5SJulian Pullen (forest_name_item->state == AD_STATE_AUTO); 14937a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 14947a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 14957a8a68f5SJulian Pullen 14967a8a68f5SJulian Pullen return (forest_name); 14977a8a68f5SJulian Pullen } 14987a8a68f5SJulian Pullen 14997a8a68f5SJulian Pullen 15007a8a68f5SJulian Pullen /* Discover global catalog servers */ 15017a8a68f5SJulian Pullen static ad_item_t * 15027a8a68f5SJulian Pullen validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) 15037a8a68f5SJulian Pullen { 1504*b3700b07SGordon Ross ad_disc_ds_t *gc = NULL; 1505*b3700b07SGordon Ross ad_disc_cds_t *cgc = NULL; 15067a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 15077a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 1508*b3700b07SGordon Ross ad_item_t *dc_item; 15097a8a68f5SJulian Pullen ad_item_t *forest_name_item; 15107a8a68f5SJulian Pullen ad_item_t *site_name_item; 1511*b3700b07SGordon Ross char *forest_name; 1512*b3700b07SGordon Ross char *site_name; 15137a8a68f5SJulian Pullen 15147a8a68f5SJulian Pullen /* If the values is fixed there will not be a site specific version */ 15157a8a68f5SJulian Pullen if (is_fixed(&ctx->global_catalog)) 15167a8a68f5SJulian Pullen return (&ctx->global_catalog); 15177a8a68f5SJulian Pullen 15187a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 15197a8a68f5SJulian Pullen if (forest_name_item == NULL) 15207a8a68f5SJulian Pullen return (NULL); 1521*b3700b07SGordon Ross forest_name = (char *)forest_name_item->value; 15227a8a68f5SJulian Pullen 15237a8a68f5SJulian Pullen if (req == AD_DISC_GLOBAL) 15247a8a68f5SJulian Pullen validate_global = B_TRUE; 15257a8a68f5SJulian Pullen else { 1526*b3700b07SGordon Ross if (is_fixed(&ctx->site_name)) 15277a8a68f5SJulian Pullen validate_site = B_TRUE; 15287a8a68f5SJulian Pullen else if (req == AD_DISC_PREFER_SITE) 15297a8a68f5SJulian Pullen validate_global = B_TRUE; 15307a8a68f5SJulian Pullen } 15317a8a68f5SJulian Pullen 15327a8a68f5SJulian Pullen if (validate_global) { 15337a8a68f5SJulian Pullen if (!is_valid(&ctx->global_catalog) || 15347a8a68f5SJulian Pullen is_changed(&ctx->global_catalog, PARAM1, 15357a8a68f5SJulian Pullen forest_name_item)) { 1536*b3700b07SGordon Ross 15377a8a68f5SJulian Pullen /* 1538*b3700b07SGordon Ross * See if our DC is also a GC. 1539*b3700b07SGordon Ross */ 1540*b3700b07SGordon Ross dc_item = validate_DomainController(ctx, req); 1541*b3700b07SGordon Ross if (dc_item != NULL) { 1542*b3700b07SGordon Ross ad_disc_ds_t *ds = dc_item->value; 1543*b3700b07SGordon Ross if ((ds->flags & DS_GC_FLAG) != 0) { 1544*b3700b07SGordon Ross DEBUG1STATUS(ctx, 1545*b3700b07SGordon Ross "DC is also a GC for %s", 1546*b3700b07SGordon Ross forest_name); 1547*b3700b07SGordon Ross gc = ds_dup(ds); 1548*b3700b07SGordon Ross if (gc != NULL) { 1549*b3700b07SGordon Ross gc->port = GC_PORT; 1550*b3700b07SGordon Ross goto update_global; 1551*b3700b07SGordon Ross } 1552*b3700b07SGordon Ross } 1553*b3700b07SGordon Ross } 1554*b3700b07SGordon Ross 1555*b3700b07SGordon Ross /* 1556*b3700b07SGordon Ross * Lookup DNS SRV RR named: 15577a8a68f5SJulian Pullen * _ldap._tcp.gc._msdcs.<ForestName> 15587a8a68f5SJulian Pullen */ 1559*b3700b07SGordon Ross DEBUG1STATUS(ctx, "DNS SRV query, forest=%s", 1560*b3700b07SGordon Ross forest_name); 15617a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1562*b3700b07SGordon Ross cgc = srv_query(&ctx->res_state, 15637a8a68f5SJulian Pullen LDAP_SRV_HEAD GC_SRV_TAIL, 1564*b3700b07SGordon Ross forest_name, NULL); 15657a8a68f5SJulian Pullen 1566*b3700b07SGordon Ross if (cgc == NULL) { 1567*b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no DNS response)"); 15687a8a68f5SJulian Pullen return (NULL); 1569148c5f43SAlan Wright } 1570*b3700b07SGordon Ross log_cds(ctx, cgc); 1571148c5f43SAlan Wright 1572*b3700b07SGordon Ross /* 1573*b3700b07SGordon Ross * Filter out unresponsive servers, and 1574*b3700b07SGordon Ross * save the domain info we get back. 1575*b3700b07SGordon Ross */ 1576*b3700b07SGordon Ross gc = ldap_ping( 1577*b3700b07SGordon Ross NULL, 1578*b3700b07SGordon Ross cgc, 1579*b3700b07SGordon Ross forest_name, 1580*b3700b07SGordon Ross DS_GC_FLAG); 1581*b3700b07SGordon Ross srv_free(cgc); 1582*b3700b07SGordon Ross cgc = NULL; 15837a8a68f5SJulian Pullen 1584*b3700b07SGordon Ross if (gc == NULL) { 1585*b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no LDAP response)"); 1586*b3700b07SGordon Ross return (NULL); 1587*b3700b07SGordon Ross } 1588*b3700b07SGordon Ross log_ds(ctx, gc); 1589*b3700b07SGordon Ross 1590*b3700b07SGordon Ross update_global: 1591*b3700b07SGordon Ross update_item(&ctx->global_catalog, gc, 1592*b3700b07SGordon Ross AD_STATE_AUTO, gc->ttl); 15937a8a68f5SJulian Pullen update_version(&ctx->global_catalog, PARAM1, 15947a8a68f5SJulian Pullen forest_name_item); 15957a8a68f5SJulian Pullen } 15967a8a68f5SJulian Pullen return (&ctx->global_catalog); 15977a8a68f5SJulian Pullen } 15987a8a68f5SJulian Pullen 15997a8a68f5SJulian Pullen if (validate_site) { 1600*b3700b07SGordon Ross site_name_item = &ctx->site_name; 1601*b3700b07SGordon Ross site_name = (char *)site_name_item->value; 1602*b3700b07SGordon Ross 16037a8a68f5SJulian Pullen if (!is_valid(&ctx->site_global_catalog) || 16047a8a68f5SJulian Pullen is_changed(&ctx->site_global_catalog, PARAM1, 16057a8a68f5SJulian Pullen forest_name_item) || 16067a8a68f5SJulian Pullen is_changed(&ctx->site_global_catalog, PARAM2, 16077a8a68f5SJulian Pullen site_name_item)) { 16087a8a68f5SJulian Pullen char rr_name[DNS_MAX_NAME]; 16097a8a68f5SJulian Pullen 16107a8a68f5SJulian Pullen /* 1611*b3700b07SGordon Ross * See if our DC is also a GC. 1612*b3700b07SGordon Ross */ 1613*b3700b07SGordon Ross dc_item = validate_DomainController(ctx, req); 1614*b3700b07SGordon Ross if (dc_item != NULL) { 1615*b3700b07SGordon Ross ad_disc_ds_t *ds = dc_item->value; 1616*b3700b07SGordon Ross if ((ds->flags & DS_GC_FLAG) != 0) { 1617*b3700b07SGordon Ross DEBUG1STATUS(ctx, 1618*b3700b07SGordon Ross "DC is also a GC for %s in %s", 1619*b3700b07SGordon Ross forest_name, site_name); 1620*b3700b07SGordon Ross gc = ds_dup(ds); 1621*b3700b07SGordon Ross if (gc != NULL) { 1622*b3700b07SGordon Ross gc->port = GC_PORT; 1623*b3700b07SGordon Ross goto update_site; 1624*b3700b07SGordon Ross } 1625*b3700b07SGordon Ross } 1626*b3700b07SGordon Ross } 1627*b3700b07SGordon Ross 1628*b3700b07SGordon Ross /* 16297a8a68f5SJulian Pullen * Lookup DNS SRV RR named: 16307a8a68f5SJulian Pullen * _ldap._tcp.<siteName>._sites.gc. 16317a8a68f5SJulian Pullen * _msdcs.<ForestName> 16327a8a68f5SJulian Pullen */ 1633*b3700b07SGordon Ross DEBUG1STATUS(ctx, "DNS SRV query, forest=%s, site=%s", 1634*b3700b07SGordon Ross forest_name, site_name); 1635*b3700b07SGordon Ross (void) snprintf(rr_name, sizeof (rr_name), 16367a8a68f5SJulian Pullen LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, 1637*b3700b07SGordon Ross site_name); 16387a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1639*b3700b07SGordon Ross cgc = srv_query(&ctx->res_state, rr_name, 1640*b3700b07SGordon Ross forest_name, NULL); 16417a8a68f5SJulian Pullen 1642*b3700b07SGordon Ross if (cgc == NULL) { 1643*b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no DNS response)"); 16447a8a68f5SJulian Pullen return (NULL); 1645148c5f43SAlan Wright } 1646*b3700b07SGordon Ross log_cds(ctx, cgc); 1647148c5f43SAlan Wright 1648*b3700b07SGordon Ross /* 1649*b3700b07SGordon Ross * Filter out unresponsive servers, and 1650*b3700b07SGordon Ross * save the domain info we get back. 1651*b3700b07SGordon Ross */ 1652*b3700b07SGordon Ross gc = ldap_ping( 1653*b3700b07SGordon Ross NULL, 1654*b3700b07SGordon Ross cgc, 1655*b3700b07SGordon Ross forest_name, 1656*b3700b07SGordon Ross DS_GC_FLAG); 1657*b3700b07SGordon Ross srv_free(cgc); 1658*b3700b07SGordon Ross cgc = NULL; 1659148c5f43SAlan Wright 1660*b3700b07SGordon Ross if (gc == NULL) { 1661*b3700b07SGordon Ross DEBUG1STATUS(ctx, "(no LDAP response)"); 1662*b3700b07SGordon Ross return (NULL); 1663*b3700b07SGordon Ross } 1664*b3700b07SGordon Ross log_ds(ctx, gc); 1665*b3700b07SGordon Ross 1666*b3700b07SGordon Ross update_site: 1667*b3700b07SGordon Ross update_item(&ctx->site_global_catalog, gc, 1668*b3700b07SGordon Ross AD_STATE_AUTO, gc->ttl); 16697a8a68f5SJulian Pullen update_version(&ctx->site_global_catalog, PARAM1, 16707a8a68f5SJulian Pullen forest_name_item); 16717a8a68f5SJulian Pullen update_version(&ctx->site_global_catalog, PARAM2, 16727a8a68f5SJulian Pullen site_name_item); 16737a8a68f5SJulian Pullen } 16747a8a68f5SJulian Pullen return (&ctx->site_global_catalog); 16757a8a68f5SJulian Pullen } 16767a8a68f5SJulian Pullen return (NULL); 16777a8a68f5SJulian Pullen } 16787a8a68f5SJulian Pullen 16797a8a68f5SJulian Pullen 1680*b3700b07SGordon Ross ad_disc_ds_t * 16817a8a68f5SJulian Pullen ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, 16827a8a68f5SJulian Pullen boolean_t *auto_discovered) 16837a8a68f5SJulian Pullen { 1684*b3700b07SGordon Ross ad_disc_ds_t *global_catalog = NULL; 16857a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 16867a8a68f5SJulian Pullen 16877a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, req); 16887a8a68f5SJulian Pullen 16897a8a68f5SJulian Pullen if (global_catalog_item != NULL) { 16907a8a68f5SJulian Pullen global_catalog = ds_dup(global_catalog_item->value); 16917a8a68f5SJulian Pullen if (auto_discovered != NULL) 16927a8a68f5SJulian Pullen *auto_discovered = 16937a8a68f5SJulian Pullen (global_catalog_item->state == AD_STATE_AUTO); 16947a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 16957a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 16967a8a68f5SJulian Pullen 16977a8a68f5SJulian Pullen return (global_catalog); 16987a8a68f5SJulian Pullen } 16997a8a68f5SJulian Pullen 17007a8a68f5SJulian Pullen 17017a8a68f5SJulian Pullen static ad_item_t * 17027a8a68f5SJulian Pullen validate_TrustedDomains(ad_disc_t ctx) 17037a8a68f5SJulian Pullen { 17047a8a68f5SJulian Pullen LDAP *ld = NULL; 17057a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 17067a8a68f5SJulian Pullen ad_item_t *forest_name_item; 17077a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains; 17087a8a68f5SJulian Pullen char *dn = NULL; 17097a8a68f5SJulian Pullen char *forest_name_dn; 17107a8a68f5SJulian Pullen int len; 17117a8a68f5SJulian Pullen int num_parts; 17127a8a68f5SJulian Pullen 17137a8a68f5SJulian Pullen if (is_fixed(&ctx->trusted_domains)) 17147a8a68f5SJulian Pullen return (&ctx->trusted_domains); 17157a8a68f5SJulian Pullen 17167a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 17177a8a68f5SJulian Pullen if (global_catalog_item == NULL) 17187a8a68f5SJulian Pullen return (NULL); 17197a8a68f5SJulian Pullen 17207a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 17217a8a68f5SJulian Pullen if (forest_name_item == NULL) 17227a8a68f5SJulian Pullen return (NULL); 17237a8a68f5SJulian Pullen 17247a8a68f5SJulian Pullen if (!is_valid(&ctx->trusted_domains) || 17257a8a68f5SJulian Pullen is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) || 17267a8a68f5SJulian Pullen is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) { 17277a8a68f5SJulian Pullen 17287a8a68f5SJulian Pullen forest_name_dn = ldap_dns_to_dn(forest_name_item->value, 17297a8a68f5SJulian Pullen &num_parts); 17307a8a68f5SJulian Pullen if (forest_name_dn == NULL) 17317a8a68f5SJulian Pullen return (NULL); 17327a8a68f5SJulian Pullen 17337a8a68f5SJulian Pullen len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1; 17347a8a68f5SJulian Pullen dn = malloc(len); 17357a8a68f5SJulian Pullen if (dn == NULL) { 17367a8a68f5SJulian Pullen free(forest_name_dn); 17377a8a68f5SJulian Pullen return (NULL); 17387a8a68f5SJulian Pullen } 17397a8a68f5SJulian Pullen (void) snprintf(dn, len, "CN=System,%s", forest_name_dn); 17407a8a68f5SJulian Pullen free(forest_name_dn); 17417a8a68f5SJulian Pullen 17427a8a68f5SJulian Pullen trusted_domains = ldap_lookup_trusted_domains( 17437a8a68f5SJulian Pullen &ld, global_catalog_item->value, dn); 17447a8a68f5SJulian Pullen 17457a8a68f5SJulian Pullen if (ld != NULL) 17467a8a68f5SJulian Pullen (void) ldap_unbind(ld); 17477a8a68f5SJulian Pullen free(dn); 17487a8a68f5SJulian Pullen 17497a8a68f5SJulian Pullen if (trusted_domains == NULL) 17507a8a68f5SJulian Pullen return (NULL); 17517a8a68f5SJulian Pullen 17527a8a68f5SJulian Pullen update_item(&ctx->trusted_domains, trusted_domains, 17537a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 17547a8a68f5SJulian Pullen update_version(&ctx->trusted_domains, PARAM1, 17557a8a68f5SJulian Pullen global_catalog_item); 17567a8a68f5SJulian Pullen update_version(&ctx->trusted_domains, PARAM2, 17577a8a68f5SJulian Pullen forest_name_item); 17587a8a68f5SJulian Pullen } 17597a8a68f5SJulian Pullen 17607a8a68f5SJulian Pullen return (&ctx->trusted_domains); 17617a8a68f5SJulian Pullen } 17627a8a68f5SJulian Pullen 17637a8a68f5SJulian Pullen 17647a8a68f5SJulian Pullen ad_disc_trusteddomains_t * 17657a8a68f5SJulian Pullen ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered) 17667a8a68f5SJulian Pullen { 17677a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 17687a8a68f5SJulian Pullen ad_item_t *trusted_domains_item; 17697a8a68f5SJulian Pullen 17707a8a68f5SJulian Pullen trusted_domains_item = validate_TrustedDomains(ctx); 17717a8a68f5SJulian Pullen 17727a8a68f5SJulian Pullen if (trusted_domains_item != NULL) { 17737a8a68f5SJulian Pullen trusted_domains = td_dup(trusted_domains_item->value); 17747a8a68f5SJulian Pullen if (auto_discovered != NULL) 17757a8a68f5SJulian Pullen *auto_discovered = 17767a8a68f5SJulian Pullen (trusted_domains_item->state == AD_STATE_AUTO); 17777a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 17787a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 17797a8a68f5SJulian Pullen 17807a8a68f5SJulian Pullen return (trusted_domains); 17817a8a68f5SJulian Pullen } 17827a8a68f5SJulian Pullen 17837a8a68f5SJulian Pullen 17847a8a68f5SJulian Pullen static ad_item_t * 17857a8a68f5SJulian Pullen validate_DomainsInForest(ad_disc_t ctx) 17867a8a68f5SJulian Pullen { 17877a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 17887a8a68f5SJulian Pullen LDAP *ld = NULL; 17897a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest; 17907a8a68f5SJulian Pullen 17917a8a68f5SJulian Pullen if (is_fixed(&ctx->domains_in_forest)) 17927a8a68f5SJulian Pullen return (&ctx->domains_in_forest); 17937a8a68f5SJulian Pullen 17947a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 17957a8a68f5SJulian Pullen if (global_catalog_item == NULL) 17967a8a68f5SJulian Pullen return (NULL); 17977a8a68f5SJulian Pullen 17987a8a68f5SJulian Pullen if (!is_valid(&ctx->domains_in_forest) || 17997a8a68f5SJulian Pullen is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) { 18007a8a68f5SJulian Pullen 18017a8a68f5SJulian Pullen domains_in_forest = ldap_lookup_domains_in_forest( 18027a8a68f5SJulian Pullen &ld, global_catalog_item->value); 18037a8a68f5SJulian Pullen 18047a8a68f5SJulian Pullen if (ld != NULL) 18057a8a68f5SJulian Pullen (void) ldap_unbind(ld); 18067a8a68f5SJulian Pullen 18077a8a68f5SJulian Pullen if (domains_in_forest == NULL) 18087a8a68f5SJulian Pullen return (NULL); 18097a8a68f5SJulian Pullen 18107a8a68f5SJulian Pullen update_item(&ctx->domains_in_forest, domains_in_forest, 18117a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 18127a8a68f5SJulian Pullen update_version(&ctx->domains_in_forest, PARAM1, 18137a8a68f5SJulian Pullen global_catalog_item); 18147a8a68f5SJulian Pullen } 18157a8a68f5SJulian Pullen return (&ctx->domains_in_forest); 18167a8a68f5SJulian Pullen } 18177a8a68f5SJulian Pullen 18187a8a68f5SJulian Pullen 18197a8a68f5SJulian Pullen ad_disc_domainsinforest_t * 18207a8a68f5SJulian Pullen ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered) 18217a8a68f5SJulian Pullen { 18227a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest = NULL; 18237a8a68f5SJulian Pullen ad_item_t *domains_in_forest_item; 18247a8a68f5SJulian Pullen 18257a8a68f5SJulian Pullen domains_in_forest_item = validate_DomainsInForest(ctx); 18267a8a68f5SJulian Pullen 18277a8a68f5SJulian Pullen if (domains_in_forest_item != NULL) { 18287a8a68f5SJulian Pullen domains_in_forest = df_dup(domains_in_forest_item->value); 18297a8a68f5SJulian Pullen if (auto_discovered != NULL) 18307a8a68f5SJulian Pullen *auto_discovered = 18317a8a68f5SJulian Pullen (domains_in_forest_item->state == AD_STATE_AUTO); 18327a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 18337a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 18347a8a68f5SJulian Pullen 18357a8a68f5SJulian Pullen return (domains_in_forest); 18367a8a68f5SJulian Pullen } 18377a8a68f5SJulian Pullen 1838*b3700b07SGordon Ross static ad_item_t * 1839*b3700b07SGordon Ross validate_PreferredDC(ad_disc_t ctx) 1840*b3700b07SGordon Ross { 1841*b3700b07SGordon Ross if (is_valid(&ctx->preferred_dc)) 1842*b3700b07SGordon Ross return (&ctx->preferred_dc); 1843*b3700b07SGordon Ross 1844*b3700b07SGordon Ross return (NULL); 1845*b3700b07SGordon Ross } 1846*b3700b07SGordon Ross 1847*b3700b07SGordon Ross ad_disc_ds_t * 1848*b3700b07SGordon Ross ad_disc_get_PreferredDC(ad_disc_t ctx, boolean_t *auto_discovered) 1849*b3700b07SGordon Ross { 1850*b3700b07SGordon Ross ad_disc_ds_t *preferred_dc = NULL; 1851*b3700b07SGordon Ross ad_item_t *preferred_dc_item; 1852*b3700b07SGordon Ross 1853*b3700b07SGordon Ross preferred_dc_item = validate_PreferredDC(ctx); 1854*b3700b07SGordon Ross 1855*b3700b07SGordon Ross if (preferred_dc_item != NULL) { 1856*b3700b07SGordon Ross preferred_dc = ds_dup(preferred_dc_item->value); 1857*b3700b07SGordon Ross if (auto_discovered != NULL) 1858*b3700b07SGordon Ross *auto_discovered = 1859*b3700b07SGordon Ross (preferred_dc_item->state == AD_STATE_AUTO); 1860*b3700b07SGordon Ross } else if (auto_discovered != NULL) 1861*b3700b07SGordon Ross *auto_discovered = B_FALSE; 1862*b3700b07SGordon Ross 1863*b3700b07SGordon Ross return (preferred_dc); 1864*b3700b07SGordon Ross } 18657a8a68f5SJulian Pullen 18667a8a68f5SJulian Pullen 18677a8a68f5SJulian Pullen 18687a8a68f5SJulian Pullen int 18697a8a68f5SJulian Pullen ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) 18707a8a68f5SJulian Pullen { 18717a8a68f5SJulian Pullen char *domain_name = NULL; 18727a8a68f5SJulian Pullen if (domainName != NULL) { 18737a8a68f5SJulian Pullen domain_name = strdup(domainName); 18747a8a68f5SJulian Pullen if (domain_name == NULL) 18757a8a68f5SJulian Pullen return (-1); 18767a8a68f5SJulian Pullen update_item(&ctx->domain_name, domain_name, 18777a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 18787a8a68f5SJulian Pullen } else if (ctx->domain_name.state == AD_STATE_FIXED) 18797a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 18807a8a68f5SJulian Pullen return (0); 18817a8a68f5SJulian Pullen } 18827a8a68f5SJulian Pullen 1883*b3700b07SGordon Ross int 1884*b3700b07SGordon Ross ad_disc_set_DomainGUID(ad_disc_t ctx, uchar_t *u) 1885*b3700b07SGordon Ross { 1886*b3700b07SGordon Ross char *domain_guid = NULL; 1887*b3700b07SGordon Ross if (u != NULL) { 1888*b3700b07SGordon Ross domain_guid = uuid_dup(u); 1889*b3700b07SGordon Ross if (domain_guid == NULL) 1890*b3700b07SGordon Ross return (-1); 1891*b3700b07SGordon Ross update_item(&ctx->domain_guid, domain_guid, 1892*b3700b07SGordon Ross AD_STATE_FIXED, 0); 1893*b3700b07SGordon Ross } else if (ctx->domain_guid.state == AD_STATE_FIXED) 1894*b3700b07SGordon Ross ctx->domain_guid.state = AD_STATE_INVALID; 1895*b3700b07SGordon Ross return (0); 1896*b3700b07SGordon Ross } 1897*b3700b07SGordon Ross 1898*b3700b07SGordon Ross void 1899*b3700b07SGordon Ross auto_set_DomainGUID(ad_disc_t ctx, uchar_t *u) 1900*b3700b07SGordon Ross { 1901*b3700b07SGordon Ross char *domain_guid = NULL; 1902*b3700b07SGordon Ross 1903*b3700b07SGordon Ross if (is_fixed(&ctx->domain_guid)) 1904*b3700b07SGordon Ross return; 1905*b3700b07SGordon Ross 1906*b3700b07SGordon Ross domain_guid = uuid_dup(u); 1907*b3700b07SGordon Ross if (domain_guid == NULL) 1908*b3700b07SGordon Ross return; 1909*b3700b07SGordon Ross update_item(&ctx->domain_guid, domain_guid, AD_STATE_AUTO, 0); 1910*b3700b07SGordon Ross } 19117a8a68f5SJulian Pullen 19127a8a68f5SJulian Pullen int 19137a8a68f5SJulian Pullen ad_disc_set_DomainController(ad_disc_t ctx, 1914*b3700b07SGordon Ross const ad_disc_ds_t *domainController) 19157a8a68f5SJulian Pullen { 1916*b3700b07SGordon Ross ad_disc_ds_t *domain_controller = NULL; 19177a8a68f5SJulian Pullen if (domainController != NULL) { 19187a8a68f5SJulian Pullen domain_controller = ds_dup(domainController); 19197a8a68f5SJulian Pullen if (domain_controller == NULL) 19207a8a68f5SJulian Pullen return (-1); 19217a8a68f5SJulian Pullen update_item(&ctx->domain_controller, domain_controller, 19227a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 19237a8a68f5SJulian Pullen } else if (ctx->domain_controller.state == AD_STATE_FIXED) 19247a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 19257a8a68f5SJulian Pullen return (0); 19267a8a68f5SJulian Pullen } 19277a8a68f5SJulian Pullen 19287a8a68f5SJulian Pullen int 19297a8a68f5SJulian Pullen ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) 19307a8a68f5SJulian Pullen { 19317a8a68f5SJulian Pullen char *site_name = NULL; 19327a8a68f5SJulian Pullen if (siteName != NULL) { 19337a8a68f5SJulian Pullen site_name = strdup(siteName); 19347a8a68f5SJulian Pullen if (site_name == NULL) 19357a8a68f5SJulian Pullen return (-1); 19367a8a68f5SJulian Pullen update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0); 19377a8a68f5SJulian Pullen } else if (ctx->site_name.state == AD_STATE_FIXED) 19387a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 19397a8a68f5SJulian Pullen return (0); 19407a8a68f5SJulian Pullen } 19417a8a68f5SJulian Pullen 1942*b3700b07SGordon Ross void 1943*b3700b07SGordon Ross auto_set_SiteName(ad_disc_t ctx, char *siteName) 1944*b3700b07SGordon Ross { 1945*b3700b07SGordon Ross char *site_name = NULL; 1946*b3700b07SGordon Ross 1947*b3700b07SGordon Ross if (is_fixed(&ctx->site_name)) 1948*b3700b07SGordon Ross return; 1949*b3700b07SGordon Ross 1950*b3700b07SGordon Ross site_name = strdup(siteName); 1951*b3700b07SGordon Ross if (site_name == NULL) 1952*b3700b07SGordon Ross return; 1953*b3700b07SGordon Ross update_item(&ctx->site_name, site_name, AD_STATE_AUTO, 0); 1954*b3700b07SGordon Ross } 1955*b3700b07SGordon Ross 19567a8a68f5SJulian Pullen int 19577a8a68f5SJulian Pullen ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) 19587a8a68f5SJulian Pullen { 19597a8a68f5SJulian Pullen char *forest_name = NULL; 19607a8a68f5SJulian Pullen if (forestName != NULL) { 19617a8a68f5SJulian Pullen forest_name = strdup(forestName); 19627a8a68f5SJulian Pullen if (forest_name == NULL) 19637a8a68f5SJulian Pullen return (-1); 19647a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, 19657a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 19667a8a68f5SJulian Pullen } else if (ctx->forest_name.state == AD_STATE_FIXED) 19677a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 19687a8a68f5SJulian Pullen return (0); 19697a8a68f5SJulian Pullen } 19707a8a68f5SJulian Pullen 1971*b3700b07SGordon Ross void 1972*b3700b07SGordon Ross auto_set_ForestName(ad_disc_t ctx, char *forestName) 1973*b3700b07SGordon Ross { 1974*b3700b07SGordon Ross char *forest_name = NULL; 1975*b3700b07SGordon Ross 1976*b3700b07SGordon Ross if (is_fixed(&ctx->forest_name)) 1977*b3700b07SGordon Ross return; 1978*b3700b07SGordon Ross 1979*b3700b07SGordon Ross forest_name = strdup(forestName); 1980*b3700b07SGordon Ross if (forest_name == NULL) 1981*b3700b07SGordon Ross return; 1982*b3700b07SGordon Ross update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); 1983*b3700b07SGordon Ross } 1984*b3700b07SGordon Ross 19857a8a68f5SJulian Pullen int 19867a8a68f5SJulian Pullen ad_disc_set_GlobalCatalog(ad_disc_t ctx, 1987*b3700b07SGordon Ross const ad_disc_ds_t *globalCatalog) 19887a8a68f5SJulian Pullen { 1989*b3700b07SGordon Ross ad_disc_ds_t *global_catalog = NULL; 19907a8a68f5SJulian Pullen if (globalCatalog != NULL) { 19917a8a68f5SJulian Pullen global_catalog = ds_dup(globalCatalog); 19927a8a68f5SJulian Pullen if (global_catalog == NULL) 19937a8a68f5SJulian Pullen return (-1); 19947a8a68f5SJulian Pullen update_item(&ctx->global_catalog, global_catalog, 19957a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 19967a8a68f5SJulian Pullen } else if (ctx->global_catalog.state == AD_STATE_FIXED) 19977a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 19987a8a68f5SJulian Pullen return (0); 19997a8a68f5SJulian Pullen } 20007a8a68f5SJulian Pullen 2001*b3700b07SGordon Ross int 2002*b3700b07SGordon Ross ad_disc_set_PreferredDC(ad_disc_t ctx, const ad_disc_ds_t *pref_dc) 2003*b3700b07SGordon Ross { 2004*b3700b07SGordon Ross ad_disc_ds_t *new_pref_dc = NULL; 2005*b3700b07SGordon Ross if (pref_dc != NULL) { 2006*b3700b07SGordon Ross new_pref_dc = ds_dup(pref_dc); 2007*b3700b07SGordon Ross if (new_pref_dc == NULL) 2008*b3700b07SGordon Ross return (-1); 2009*b3700b07SGordon Ross update_item(&ctx->preferred_dc, new_pref_dc, 2010*b3700b07SGordon Ross AD_STATE_FIXED, 0); 2011*b3700b07SGordon Ross } else if (ctx->preferred_dc.state == AD_STATE_FIXED) 2012*b3700b07SGordon Ross ctx->preferred_dc.state = AD_STATE_INVALID; 2013*b3700b07SGordon Ross return (0); 2014*b3700b07SGordon Ross } 2015*b3700b07SGordon Ross 2016*b3700b07SGordon Ross void 2017*b3700b07SGordon Ross ad_disc_set_StatusFP(ad_disc_t ctx, struct __FILE_TAG *fp) 2018*b3700b07SGordon Ross { 2019*b3700b07SGordon Ross ctx->status_fp = fp; 2020*b3700b07SGordon Ross } 2021*b3700b07SGordon Ross 20227a8a68f5SJulian Pullen 20237a8a68f5SJulian Pullen int 20247a8a68f5SJulian Pullen ad_disc_unset(ad_disc_t ctx) 20257a8a68f5SJulian Pullen { 20267a8a68f5SJulian Pullen if (ctx->domain_name.state == AD_STATE_FIXED) 20277a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 20287a8a68f5SJulian Pullen 20297a8a68f5SJulian Pullen if (ctx->domain_controller.state == AD_STATE_FIXED) 20307a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 20317a8a68f5SJulian Pullen 2032*b3700b07SGordon Ross if (ctx->preferred_dc.state == AD_STATE_FIXED) 2033*b3700b07SGordon Ross ctx->preferred_dc.state = AD_STATE_INVALID; 2034*b3700b07SGordon Ross 20357a8a68f5SJulian Pullen if (ctx->site_name.state == AD_STATE_FIXED) 20367a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 20377a8a68f5SJulian Pullen 20387a8a68f5SJulian Pullen if (ctx->forest_name.state == AD_STATE_FIXED) 20397a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 20407a8a68f5SJulian Pullen 20417a8a68f5SJulian Pullen if (ctx->global_catalog.state == AD_STATE_FIXED) 20427a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 20437a8a68f5SJulian Pullen 20447a8a68f5SJulian Pullen return (0); 20457a8a68f5SJulian Pullen } 20467a8a68f5SJulian Pullen 20477a8a68f5SJulian Pullen /* 20487a8a68f5SJulian Pullen * ad_disc_get_TTL 20497a8a68f5SJulian Pullen * 20507a8a68f5SJulian Pullen * This routines the time to live for AD 20517a8a68f5SJulian Pullen * auto discovered items. 20527a8a68f5SJulian Pullen * 20537a8a68f5SJulian Pullen * Returns: 20547a8a68f5SJulian Pullen * -1 if there are no TTL items 20557a8a68f5SJulian Pullen * 0 if there are expired items 20567a8a68f5SJulian Pullen * else the number of seconds 20577a8a68f5SJulian Pullen * 20587a8a68f5SJulian Pullen * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it 20597a8a68f5SJulian Pullen * is positive -- min() greater than zero. 20607a8a68f5SJulian Pullen */ 20617a8a68f5SJulian Pullen #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \ 20627a8a68f5SJulian Pullen (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x)))) 20637a8a68f5SJulian Pullen int 20647a8a68f5SJulian Pullen ad_disc_get_TTL(ad_disc_t ctx) 20657a8a68f5SJulian Pullen { 2066c5866007SKeyur Desai time_t expires; 20677a8a68f5SJulian Pullen int ttl; 20687a8a68f5SJulian Pullen 2069c5866007SKeyur Desai expires = MIN_GT_ZERO(ctx->domain_controller.expires, 2070c5866007SKeyur Desai ctx->global_catalog.expires); 2071c5866007SKeyur Desai expires = MIN_GT_ZERO(expires, ctx->site_domain_controller.expires); 2072c5866007SKeyur Desai expires = MIN_GT_ZERO(expires, ctx->site_global_catalog.expires); 20737a8a68f5SJulian Pullen 2074c5866007SKeyur Desai if (expires == -1) { 20757a8a68f5SJulian Pullen return (-1); 2076c5866007SKeyur Desai } 2077c5866007SKeyur Desai 2078c5866007SKeyur Desai if (ctx->expires_not_before != 0 && 2079c5866007SKeyur Desai expires < ctx->expires_not_before) { 2080c5866007SKeyur Desai expires = ctx->expires_not_before; 2081c5866007SKeyur Desai } 2082c5866007SKeyur Desai 2083c5866007SKeyur Desai if (ctx->expires_not_after != 0 && 2084c5866007SKeyur Desai expires > ctx->expires_not_after) { 2085c5866007SKeyur Desai expires = ctx->expires_not_after; 2086c5866007SKeyur Desai } 2087c5866007SKeyur Desai 2088c5866007SKeyur Desai ttl = expires - time(NULL); 2089c5866007SKeyur Desai 2090c5866007SKeyur Desai if (ttl < 0) { 20917a8a68f5SJulian Pullen return (0); 2092c5866007SKeyur Desai } 20937a8a68f5SJulian Pullen return (ttl); 20947a8a68f5SJulian Pullen } 20957a8a68f5SJulian Pullen 20967a8a68f5SJulian Pullen boolean_t 20977a8a68f5SJulian Pullen ad_disc_SubnetChanged(ad_disc_t ctx) 20987a8a68f5SJulian Pullen { 20997a8a68f5SJulian Pullen ad_subnet_t *subnets; 21007a8a68f5SJulian Pullen 21017a8a68f5SJulian Pullen if (ctx->subnets_changed || ctx->subnets == NULL) 21027a8a68f5SJulian Pullen return (B_TRUE); 21037a8a68f5SJulian Pullen 21047a8a68f5SJulian Pullen if ((subnets = find_subnets()) != NULL) { 21057a8a68f5SJulian Pullen if (cmpsubnets(subnets, ctx->subnets) != 0) 21067a8a68f5SJulian Pullen ctx->subnets_changed = B_TRUE; 21077a8a68f5SJulian Pullen free(subnets); 21087a8a68f5SJulian Pullen } 21097a8a68f5SJulian Pullen 21107a8a68f5SJulian Pullen return (ctx->subnets_changed); 21117a8a68f5SJulian Pullen } 2112