1*7a8a68f5SJulian Pullen /* 2*7a8a68f5SJulian Pullen * CDDL HEADER START 3*7a8a68f5SJulian Pullen * 4*7a8a68f5SJulian Pullen * The contents of this file are subject to the terms of the 5*7a8a68f5SJulian Pullen * Common Development and Distribution License (the "License"). 6*7a8a68f5SJulian Pullen * You may not use this file except in compliance with the License. 7*7a8a68f5SJulian Pullen * 8*7a8a68f5SJulian Pullen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7a8a68f5SJulian Pullen * or http://www.opensolaris.org/os/licensing. 10*7a8a68f5SJulian Pullen * See the License for the specific language governing permissions 11*7a8a68f5SJulian Pullen * and limitations under the License. 12*7a8a68f5SJulian Pullen * 13*7a8a68f5SJulian Pullen * When distributing Covered Code, include this CDDL HEADER in each 14*7a8a68f5SJulian Pullen * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7a8a68f5SJulian Pullen * If applicable, add the following below this CDDL HEADER, with the 16*7a8a68f5SJulian Pullen * fields enclosed by brackets "[]" replaced with your own identifying 17*7a8a68f5SJulian Pullen * information: Portions Copyright [yyyy] [name of copyright owner] 18*7a8a68f5SJulian Pullen * 19*7a8a68f5SJulian Pullen * CDDL HEADER END 20*7a8a68f5SJulian Pullen */ 21*7a8a68f5SJulian Pullen 22*7a8a68f5SJulian Pullen /* 23*7a8a68f5SJulian Pullen * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*7a8a68f5SJulian Pullen * Use is subject to license terms. 25*7a8a68f5SJulian Pullen */ 26*7a8a68f5SJulian Pullen 27*7a8a68f5SJulian Pullen /* 28*7a8a68f5SJulian Pullen * Active Directory Auto-Discovery. 29*7a8a68f5SJulian Pullen * 30*7a8a68f5SJulian Pullen * This [project private] API allows the caller to provide whatever 31*7a8a68f5SJulian Pullen * details it knows a priori (i.e., provided via configuration so as to 32*7a8a68f5SJulian Pullen * override auto-discovery) and in any order. Then the caller can ask 33*7a8a68f5SJulian Pullen * for any of the auto-discoverable parameters in any order. 34*7a8a68f5SJulian Pullen * 35*7a8a68f5SJulian Pullen * But there is an actual order in which discovery must be done. Given 36*7a8a68f5SJulian Pullen * the discovery mechanism implemented here, that order is: 37*7a8a68f5SJulian Pullen * 38*7a8a68f5SJulian Pullen * - the domain name joined must be discovered first 39*7a8a68f5SJulian Pullen * - then the domain controllers 40*7a8a68f5SJulian Pullen * - then the forest name and site name 41*7a8a68f5SJulian Pullen * - then the global catalog servers, and site-specific domain 42*7a8a68f5SJulian Pullen * controllers and global catalog servers. 43*7a8a68f5SJulian Pullen * 44*7a8a68f5SJulian Pullen * The API does not require it be called in the same order because there 45*7a8a68f5SJulian Pullen * may be other discovery mechanisms in the future, and exposing 46*7a8a68f5SJulian Pullen * ordering requirements of the current mechanism now can create trouble 47*7a8a68f5SJulian Pullen * down the line. Also, this makes the API easier to use now, which 48*7a8a68f5SJulian Pullen * means less work to do some day when we make this a public API. 49*7a8a68f5SJulian Pullen * 50*7a8a68f5SJulian Pullen * Domain discovery is done by res_nsearch() of the DNS SRV RR name for 51*7a8a68f5SJulian Pullen * domain controllers. As long as the joined domain appears in the DNS 52*7a8a68f5SJulian Pullen * resolver's search list then we'll find it. 53*7a8a68f5SJulian Pullen * 54*7a8a68f5SJulian Pullen * Domain controller discovery is a matter of formatting the DNS SRV RR 55*7a8a68f5SJulian Pullen * FQDN for domain controllers and doing a lookup for them. Knowledge 56*7a8a68f5SJulian Pullen * of the domain name is not fundamentally required, but we separate the 57*7a8a68f5SJulian Pullen * two processes, which in practice can lead to one more DNS lookup than 58*7a8a68f5SJulian Pullen * is strictly required. 59*7a8a68f5SJulian Pullen * 60*7a8a68f5SJulian Pullen * Forest and site name discovery require an LDAP search of the AD 61*7a8a68f5SJulian Pullen * "configuration partition" at a domain controller for the joined 62*7a8a68f5SJulian Pullen * domain. Forest and site name discovery depend on knowing the joined 63*7a8a68f5SJulian Pullen * domain name and domain controllers for that domain. 64*7a8a68f5SJulian Pullen * 65*7a8a68f5SJulian Pullen * Global catalog server discovery requires knowledge of the forest 66*7a8a68f5SJulian Pullen * name in order to format the DNS SRV RR FQDN to lookup. Site-specific 67*7a8a68f5SJulian Pullen * domain controller discovery depends on knowing the site name (and, 68*7a8a68f5SJulian Pullen * therefore, joined domain, ...). Site-specific global catalog server 69*7a8a68f5SJulian Pullen * discovery depends on knowledge of the forest and site names, which 70*7a8a68f5SJulian Pullen * depend on... 71*7a8a68f5SJulian Pullen * 72*7a8a68f5SJulian Pullen * All the work of discovering particular items is done by functions 73*7a8a68f5SJulian Pullen * named validate_<item>(). Each such function calls validate_<item>() 74*7a8a68f5SJulian Pullen * for any items that it depends on. 75*7a8a68f5SJulian Pullen * 76*7a8a68f5SJulian Pullen * This API is not thread-safe. 77*7a8a68f5SJulian Pullen */ 78*7a8a68f5SJulian Pullen 79*7a8a68f5SJulian Pullen 80*7a8a68f5SJulian Pullen #include <stdio.h> 81*7a8a68f5SJulian Pullen #include <string.h> 82*7a8a68f5SJulian Pullen #include <strings.h> 83*7a8a68f5SJulian Pullen #include <unistd.h> 84*7a8a68f5SJulian Pullen #include <assert.h> 85*7a8a68f5SJulian Pullen #include <stdlib.h> 86*7a8a68f5SJulian Pullen #include <net/if.h> 87*7a8a68f5SJulian Pullen #include <net/if.h> 88*7a8a68f5SJulian Pullen #include <sys/types.h> 89*7a8a68f5SJulian Pullen #include <sys/socket.h> 90*7a8a68f5SJulian Pullen #include <sys/sockio.h> 91*7a8a68f5SJulian Pullen #include <netinet/in.h> 92*7a8a68f5SJulian Pullen #include <netinet/in.h> 93*7a8a68f5SJulian Pullen #include <arpa/inet.h> 94*7a8a68f5SJulian Pullen #include <arpa/nameser.h> 95*7a8a68f5SJulian Pullen #include <resolv.h> 96*7a8a68f5SJulian Pullen #include <netdb.h> 97*7a8a68f5SJulian Pullen #include <ctype.h> 98*7a8a68f5SJulian Pullen #include <errno.h> 99*7a8a68f5SJulian Pullen #include <ldap.h> 100*7a8a68f5SJulian Pullen #include <sasl/sasl.h> 101*7a8a68f5SJulian Pullen #include <sys/u8_textprep.h> 102*7a8a68f5SJulian Pullen #include <syslog.h> 103*7a8a68f5SJulian Pullen #include "adutils_impl.h" 104*7a8a68f5SJulian Pullen #include "addisc.h" 105*7a8a68f5SJulian Pullen 106*7a8a68f5SJulian Pullen 107*7a8a68f5SJulian Pullen enum ad_item_state { 108*7a8a68f5SJulian Pullen AD_STATE_INVALID = 0, /* The value is not valid */ 109*7a8a68f5SJulian Pullen AD_STATE_FIXED, /* The value was fixed by caller */ 110*7a8a68f5SJulian Pullen AD_STATE_AUTO /* The value is auto discovered */ 111*7a8a68f5SJulian Pullen }; 112*7a8a68f5SJulian Pullen 113*7a8a68f5SJulian Pullen enum ad_data_type { 114*7a8a68f5SJulian Pullen AD_STRING = 123, 115*7a8a68f5SJulian Pullen AD_DIRECTORY, 116*7a8a68f5SJulian Pullen AD_DOMAINS_IN_FOREST, 117*7a8a68f5SJulian Pullen AD_TRUSTED_DOMAINS 118*7a8a68f5SJulian Pullen }; 119*7a8a68f5SJulian Pullen 120*7a8a68f5SJulian Pullen 121*7a8a68f5SJulian Pullen typedef struct ad_subnet { 122*7a8a68f5SJulian Pullen char subnet[24]; 123*7a8a68f5SJulian Pullen } ad_subnet_t; 124*7a8a68f5SJulian Pullen 125*7a8a68f5SJulian Pullen 126*7a8a68f5SJulian Pullen typedef struct ad_item { 127*7a8a68f5SJulian Pullen enum ad_item_state state; 128*7a8a68f5SJulian Pullen enum ad_data_type type; 129*7a8a68f5SJulian Pullen void *value; 130*7a8a68f5SJulian Pullen time_t ttl; 131*7a8a68f5SJulian Pullen unsigned int version; /* Version is only changed */ 132*7a8a68f5SJulian Pullen /* if the value changes */ 133*7a8a68f5SJulian Pullen #define PARAM1 0 134*7a8a68f5SJulian Pullen #define PARAM2 1 135*7a8a68f5SJulian Pullen int param_version[2]; 136*7a8a68f5SJulian Pullen /* These holds the version of */ 137*7a8a68f5SJulian Pullen /* dependents so that a dependent */ 138*7a8a68f5SJulian Pullen /* change can be detected */ 139*7a8a68f5SJulian Pullen } ad_item_t; 140*7a8a68f5SJulian Pullen 141*7a8a68f5SJulian Pullen typedef struct ad_disc { 142*7a8a68f5SJulian Pullen struct __res_state res_state; 143*7a8a68f5SJulian Pullen int res_ninitted; 144*7a8a68f5SJulian Pullen ad_subnet_t *subnets; 145*7a8a68f5SJulian Pullen boolean_t subnets_changed; 146*7a8a68f5SJulian Pullen time_t subnets_last_check; 147*7a8a68f5SJulian Pullen ad_item_t domain_name; /* DNS hostname string */ 148*7a8a68f5SJulian Pullen ad_item_t domain_controller; /* Directory hostname and */ 149*7a8a68f5SJulian Pullen /* port array */ 150*7a8a68f5SJulian Pullen ad_item_t site_name; /* String */ 151*7a8a68f5SJulian Pullen ad_item_t forest_name; /* DNS forestname string */ 152*7a8a68f5SJulian Pullen ad_item_t global_catalog; /* Directory hostname and */ 153*7a8a68f5SJulian Pullen /* port array */ 154*7a8a68f5SJulian Pullen ad_item_t domains_in_forest; /* DNS domainname and SID */ 155*7a8a68f5SJulian Pullen /* array */ 156*7a8a68f5SJulian Pullen ad_item_t trusted_domains; /* DNS domainname and trust */ 157*7a8a68f5SJulian Pullen /* direction array */ 158*7a8a68f5SJulian Pullen /* Site specfic versions */ 159*7a8a68f5SJulian Pullen ad_item_t site_domain_controller; /* Directory hostname and */ 160*7a8a68f5SJulian Pullen /* port array */ 161*7a8a68f5SJulian Pullen ad_item_t site_global_catalog; /* Directory hostname and */ 162*7a8a68f5SJulian Pullen /* port array */ 163*7a8a68f5SJulian Pullen } ad_disc; 164*7a8a68f5SJulian Pullen 165*7a8a68f5SJulian Pullen 166*7a8a68f5SJulian Pullen #define DNS_MAX_NAME NS_MAXDNAME 167*7a8a68f5SJulian Pullen 168*7a8a68f5SJulian Pullen 169*7a8a68f5SJulian Pullen /* SRV RR names for various queries */ 170*7a8a68f5SJulian Pullen #define LDAP_SRV_HEAD "_ldap._tcp." 171*7a8a68f5SJulian Pullen #define SITE_SRV_MIDDLE "%s._sites." 172*7a8a68f5SJulian Pullen #define GC_SRV_TAIL "gc._msdcs" 173*7a8a68f5SJulian Pullen #define DC_SRV_TAIL "dc._msdcs" 174*7a8a68f5SJulian Pullen #define ALL_GC_SRV_TAIL "_gc._tcp" 175*7a8a68f5SJulian Pullen #define PDC_SRV "_ldap._tcp.pdc._msdcs.%s" 176*7a8a68f5SJulian Pullen 177*7a8a68f5SJulian Pullen /* A RR name for all GCs -- last resort this works */ 178*7a8a68f5SJulian Pullen #define GC_ALL_A_NAME_FSTR "gc._msdcs.%s." 179*7a8a68f5SJulian Pullen 180*7a8a68f5SJulian Pullen 181*7a8a68f5SJulian Pullen /* 182*7a8a68f5SJulian Pullen * We try res_ninit() whenever we don't have one. res_ninit() fails if 183*7a8a68f5SJulian Pullen * idmapd is running before the network is up! 184*7a8a68f5SJulian Pullen */ 185*7a8a68f5SJulian Pullen #define DO_RES_NINIT(ctx) if (!(ctx)->res_ninitted) \ 186*7a8a68f5SJulian Pullen (ctx)->res_ninitted = (res_ninit(&ctx->res_state) != -1) 187*7a8a68f5SJulian Pullen 188*7a8a68f5SJulian Pullen #define is_fixed(item) \ 189*7a8a68f5SJulian Pullen ((item)->state == AD_STATE_FIXED) 190*7a8a68f5SJulian Pullen 191*7a8a68f5SJulian Pullen #define is_changed(item, num, param) \ 192*7a8a68f5SJulian Pullen ((item)->param_version[num] != (param)->version) 193*7a8a68f5SJulian Pullen 194*7a8a68f5SJulian Pullen /*LINTLIBRARY*/ 195*7a8a68f5SJulian Pullen 196*7a8a68f5SJulian Pullen /* 197*7a8a68f5SJulian Pullen * Function definitions 198*7a8a68f5SJulian Pullen */ 199*7a8a68f5SJulian Pullen static ad_item_t * 200*7a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx); 201*7a8a68f5SJulian Pullen 202*7a8a68f5SJulian Pullen 203*7a8a68f5SJulian Pullen 204*7a8a68f5SJulian Pullen static void 205*7a8a68f5SJulian Pullen update_version(ad_item_t *item, int num, ad_item_t *param) 206*7a8a68f5SJulian Pullen { 207*7a8a68f5SJulian Pullen item->param_version[num] = param->version; 208*7a8a68f5SJulian Pullen } 209*7a8a68f5SJulian Pullen 210*7a8a68f5SJulian Pullen 211*7a8a68f5SJulian Pullen 212*7a8a68f5SJulian Pullen static boolean_t 213*7a8a68f5SJulian Pullen is_valid(ad_item_t *item) 214*7a8a68f5SJulian Pullen { 215*7a8a68f5SJulian Pullen if (item->value != NULL) { 216*7a8a68f5SJulian Pullen if (item->state == AD_STATE_FIXED) 217*7a8a68f5SJulian Pullen return (B_TRUE); 218*7a8a68f5SJulian Pullen if (item->state == AD_STATE_AUTO && 219*7a8a68f5SJulian Pullen (item->ttl == 0 || item->ttl > time(NULL))) 220*7a8a68f5SJulian Pullen return (B_TRUE); 221*7a8a68f5SJulian Pullen } 222*7a8a68f5SJulian Pullen return (B_FALSE); 223*7a8a68f5SJulian Pullen } 224*7a8a68f5SJulian Pullen 225*7a8a68f5SJulian Pullen 226*7a8a68f5SJulian Pullen static void 227*7a8a68f5SJulian Pullen update_item(ad_item_t *item, void *value, enum ad_item_state state, 228*7a8a68f5SJulian Pullen uint32_t ttl) 229*7a8a68f5SJulian Pullen { 230*7a8a68f5SJulian Pullen if (item->value != NULL && value != NULL) { 231*7a8a68f5SJulian Pullen if ((item->type == AD_STRING && 232*7a8a68f5SJulian Pullen strcmp(item->value, value) != 0) || 233*7a8a68f5SJulian Pullen (item->type == AD_DIRECTORY && 234*7a8a68f5SJulian Pullen ad_disc_compare_ds(item->value, value) != 0)|| 235*7a8a68f5SJulian Pullen (item->type == AD_DOMAINS_IN_FOREST && 236*7a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(item->value, value) != 0) || 237*7a8a68f5SJulian Pullen (item->type == AD_TRUSTED_DOMAINS && 238*7a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(item->value, value) != 0)) 239*7a8a68f5SJulian Pullen item->version++; 240*7a8a68f5SJulian Pullen } else if (item->value != value) 241*7a8a68f5SJulian Pullen item->version++; 242*7a8a68f5SJulian Pullen 243*7a8a68f5SJulian Pullen if (item->value != NULL) 244*7a8a68f5SJulian Pullen free(item->value); 245*7a8a68f5SJulian Pullen 246*7a8a68f5SJulian Pullen item->value = value; 247*7a8a68f5SJulian Pullen item->state = state; 248*7a8a68f5SJulian Pullen 249*7a8a68f5SJulian Pullen if (ttl == 0) 250*7a8a68f5SJulian Pullen item->ttl = 0; 251*7a8a68f5SJulian Pullen else 252*7a8a68f5SJulian Pullen item->ttl = time(NULL) + ttl; 253*7a8a68f5SJulian Pullen } 254*7a8a68f5SJulian Pullen 255*7a8a68f5SJulian Pullen 256*7a8a68f5SJulian Pullen /* Compare DS lists */ 257*7a8a68f5SJulian Pullen int 258*7a8a68f5SJulian Pullen ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2) 259*7a8a68f5SJulian Pullen { 260*7a8a68f5SJulian Pullen int i, j; 261*7a8a68f5SJulian Pullen int num_ds1; 262*7a8a68f5SJulian Pullen int num_ds2; 263*7a8a68f5SJulian Pullen boolean_t match; 264*7a8a68f5SJulian Pullen 265*7a8a68f5SJulian Pullen for (i = 0; ds1[i].host[0] != '\0'; i++) 266*7a8a68f5SJulian Pullen continue; 267*7a8a68f5SJulian Pullen num_ds1 = i; 268*7a8a68f5SJulian Pullen for (j = 0; ds2[j].host[0] != '\0'; j++) 269*7a8a68f5SJulian Pullen continue; 270*7a8a68f5SJulian Pullen num_ds2 = j; 271*7a8a68f5SJulian Pullen if (num_ds1 != num_ds2) 272*7a8a68f5SJulian Pullen return (1); 273*7a8a68f5SJulian Pullen 274*7a8a68f5SJulian Pullen for (i = 0; i < num_ds1; i++) { 275*7a8a68f5SJulian Pullen match = B_FALSE; 276*7a8a68f5SJulian Pullen for (j = 0; j < num_ds2; j++) { 277*7a8a68f5SJulian Pullen if (strcmp(ds1[i].host, ds2[i].host) == 0 && 278*7a8a68f5SJulian Pullen ds1[i].port == ds2[i].port) { 279*7a8a68f5SJulian Pullen match = B_TRUE; 280*7a8a68f5SJulian Pullen break; 281*7a8a68f5SJulian Pullen } 282*7a8a68f5SJulian Pullen } 283*7a8a68f5SJulian Pullen if (!match) 284*7a8a68f5SJulian Pullen return (1); 285*7a8a68f5SJulian Pullen } 286*7a8a68f5SJulian Pullen return (0); 287*7a8a68f5SJulian Pullen } 288*7a8a68f5SJulian Pullen 289*7a8a68f5SJulian Pullen 290*7a8a68f5SJulian Pullen /* Copy a list of DSs */ 291*7a8a68f5SJulian Pullen static idmap_ad_disc_ds_t * 292*7a8a68f5SJulian Pullen ds_dup(const idmap_ad_disc_ds_t *srv) 293*7a8a68f5SJulian Pullen { 294*7a8a68f5SJulian Pullen int i; 295*7a8a68f5SJulian Pullen int size; 296*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *new = NULL; 297*7a8a68f5SJulian Pullen 298*7a8a68f5SJulian Pullen for (i = 0; srv[i].host[0] != '\0'; i++) 299*7a8a68f5SJulian Pullen continue; 300*7a8a68f5SJulian Pullen 301*7a8a68f5SJulian Pullen size = (i + 1) * sizeof (idmap_ad_disc_ds_t); 302*7a8a68f5SJulian Pullen new = malloc(size); 303*7a8a68f5SJulian Pullen if (new != NULL) 304*7a8a68f5SJulian Pullen memcpy(new, srv, size); 305*7a8a68f5SJulian Pullen return (new); 306*7a8a68f5SJulian Pullen } 307*7a8a68f5SJulian Pullen 308*7a8a68f5SJulian Pullen 309*7a8a68f5SJulian Pullen int 310*7a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1, 311*7a8a68f5SJulian Pullen ad_disc_trusteddomains_t *td2) 312*7a8a68f5SJulian Pullen { 313*7a8a68f5SJulian Pullen int i, j; 314*7a8a68f5SJulian Pullen int num_td1; 315*7a8a68f5SJulian Pullen int num_td2; 316*7a8a68f5SJulian Pullen boolean_t match; 317*7a8a68f5SJulian Pullen int err; 318*7a8a68f5SJulian Pullen 319*7a8a68f5SJulian Pullen for (i = 0; td1[i].domain[0] != '\0'; i++) 320*7a8a68f5SJulian Pullen continue; 321*7a8a68f5SJulian Pullen num_td1 = i; 322*7a8a68f5SJulian Pullen 323*7a8a68f5SJulian Pullen for (j = 0; td2[j].domain[0] != '\0'; j++) 324*7a8a68f5SJulian Pullen continue; 325*7a8a68f5SJulian Pullen num_td2 = j; 326*7a8a68f5SJulian Pullen 327*7a8a68f5SJulian Pullen if (num_td1 != num_td2) 328*7a8a68f5SJulian Pullen return (1); 329*7a8a68f5SJulian Pullen 330*7a8a68f5SJulian Pullen for (i = 0; i < num_td1; i++) { 331*7a8a68f5SJulian Pullen match = B_FALSE; 332*7a8a68f5SJulian Pullen for (j = 0; j < num_td2; j++) { 333*7a8a68f5SJulian Pullen if (u8_strcmp(td1[i].domain, td2[i].domain, 0, 334*7a8a68f5SJulian Pullen U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && 335*7a8a68f5SJulian Pullen err == 0) { 336*7a8a68f5SJulian Pullen match = B_TRUE; 337*7a8a68f5SJulian Pullen break; 338*7a8a68f5SJulian Pullen } 339*7a8a68f5SJulian Pullen } 340*7a8a68f5SJulian Pullen if (!match) 341*7a8a68f5SJulian Pullen return (1); 342*7a8a68f5SJulian Pullen } 343*7a8a68f5SJulian Pullen return (0); 344*7a8a68f5SJulian Pullen } 345*7a8a68f5SJulian Pullen 346*7a8a68f5SJulian Pullen 347*7a8a68f5SJulian Pullen 348*7a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */ 349*7a8a68f5SJulian Pullen static ad_disc_trusteddomains_t * 350*7a8a68f5SJulian Pullen td_dup(const ad_disc_trusteddomains_t *td) 351*7a8a68f5SJulian Pullen { 352*7a8a68f5SJulian Pullen int i; 353*7a8a68f5SJulian Pullen int size; 354*7a8a68f5SJulian Pullen ad_disc_trusteddomains_t *new = NULL; 355*7a8a68f5SJulian Pullen 356*7a8a68f5SJulian Pullen for (i = 0; td[i].domain[0] != '\0'; i++) 357*7a8a68f5SJulian Pullen continue; 358*7a8a68f5SJulian Pullen 359*7a8a68f5SJulian Pullen size = (i + 1) * sizeof (ad_disc_trusteddomains_t); 360*7a8a68f5SJulian Pullen new = malloc(size); 361*7a8a68f5SJulian Pullen if (new != NULL) 362*7a8a68f5SJulian Pullen memcpy(new, td, size); 363*7a8a68f5SJulian Pullen return (new); 364*7a8a68f5SJulian Pullen } 365*7a8a68f5SJulian Pullen 366*7a8a68f5SJulian Pullen 367*7a8a68f5SJulian Pullen 368*7a8a68f5SJulian Pullen int 369*7a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1, 370*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t *df2) 371*7a8a68f5SJulian Pullen { 372*7a8a68f5SJulian Pullen int i, j; 373*7a8a68f5SJulian Pullen int num_df1; 374*7a8a68f5SJulian Pullen int num_df2; 375*7a8a68f5SJulian Pullen boolean_t match; 376*7a8a68f5SJulian Pullen int err; 377*7a8a68f5SJulian Pullen 378*7a8a68f5SJulian Pullen for (i = 0; df1[i].domain[0] != '\0'; i++) 379*7a8a68f5SJulian Pullen continue; 380*7a8a68f5SJulian Pullen num_df1 = i; 381*7a8a68f5SJulian Pullen 382*7a8a68f5SJulian Pullen for (j = 0; df2[j].domain[0] != '\0'; j++) 383*7a8a68f5SJulian Pullen continue; 384*7a8a68f5SJulian Pullen num_df2 = j; 385*7a8a68f5SJulian Pullen 386*7a8a68f5SJulian Pullen if (num_df1 != num_df2) 387*7a8a68f5SJulian Pullen return (1); 388*7a8a68f5SJulian Pullen 389*7a8a68f5SJulian Pullen for (i = 0; i < num_df1; i++) { 390*7a8a68f5SJulian Pullen match = B_FALSE; 391*7a8a68f5SJulian Pullen for (j = 0; j < num_df2; j++) { 392*7a8a68f5SJulian Pullen if (u8_strcmp(df1[i].domain, df2[i].domain, 0, 393*7a8a68f5SJulian Pullen U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && 394*7a8a68f5SJulian Pullen err == 0 && 395*7a8a68f5SJulian Pullen strcmp(df1[i].sid, df2[i].sid) == 0) { 396*7a8a68f5SJulian Pullen match = B_TRUE; 397*7a8a68f5SJulian Pullen break; 398*7a8a68f5SJulian Pullen } 399*7a8a68f5SJulian Pullen } 400*7a8a68f5SJulian Pullen if (!match) 401*7a8a68f5SJulian Pullen return (1); 402*7a8a68f5SJulian Pullen } 403*7a8a68f5SJulian Pullen return (0); 404*7a8a68f5SJulian Pullen } 405*7a8a68f5SJulian Pullen 406*7a8a68f5SJulian Pullen 407*7a8a68f5SJulian Pullen 408*7a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */ 409*7a8a68f5SJulian Pullen static ad_disc_domainsinforest_t * 410*7a8a68f5SJulian Pullen df_dup(const ad_disc_domainsinforest_t *df) 411*7a8a68f5SJulian Pullen { 412*7a8a68f5SJulian Pullen int i; 413*7a8a68f5SJulian Pullen int size; 414*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t *new = NULL; 415*7a8a68f5SJulian Pullen 416*7a8a68f5SJulian Pullen for (i = 0; df[i].domain[0] != '\0'; i++) 417*7a8a68f5SJulian Pullen continue; 418*7a8a68f5SJulian Pullen 419*7a8a68f5SJulian Pullen size = (i + 1) * sizeof (ad_disc_domainsinforest_t); 420*7a8a68f5SJulian Pullen new = malloc(size); 421*7a8a68f5SJulian Pullen if (new != NULL) 422*7a8a68f5SJulian Pullen memcpy(new, df, size); 423*7a8a68f5SJulian Pullen return (new); 424*7a8a68f5SJulian Pullen } 425*7a8a68f5SJulian Pullen 426*7a8a68f5SJulian Pullen 427*7a8a68f5SJulian Pullen 428*7a8a68f5SJulian Pullen 429*7a8a68f5SJulian Pullen 430*7a8a68f5SJulian Pullen /* 431*7a8a68f5SJulian Pullen * Returns an array of IPv4 address/prefix length 432*7a8a68f5SJulian Pullen * The last subnet is NULL 433*7a8a68f5SJulian Pullen */ 434*7a8a68f5SJulian Pullen static ad_subnet_t * 435*7a8a68f5SJulian Pullen find_subnets() 436*7a8a68f5SJulian Pullen { 437*7a8a68f5SJulian Pullen int sock, n, i; 438*7a8a68f5SJulian Pullen struct lifconf lifc; 439*7a8a68f5SJulian Pullen struct lifreq lifr, *lifrp; 440*7a8a68f5SJulian Pullen struct lifnum lifn; 441*7a8a68f5SJulian Pullen uint32_t prefix_len; 442*7a8a68f5SJulian Pullen char *s; 443*7a8a68f5SJulian Pullen ad_subnet_t *results; 444*7a8a68f5SJulian Pullen 445*7a8a68f5SJulian Pullen lifrp = &lifr; 446*7a8a68f5SJulian Pullen 447*7a8a68f5SJulian Pullen if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 448*7a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to open IPv4 socket for " 449*7a8a68f5SJulian Pullen "listing network interfaces (%s)", strerror(errno)); 450*7a8a68f5SJulian Pullen return (NULL); 451*7a8a68f5SJulian Pullen } 452*7a8a68f5SJulian Pullen 453*7a8a68f5SJulian Pullen lifn.lifn_family = AF_INET; 454*7a8a68f5SJulian Pullen lifn.lifn_flags = 0; 455*7a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 456*7a8a68f5SJulian Pullen logger(LOG_ERR, 457*7a8a68f5SJulian Pullen "Failed to find the number of network interfaces (%s)", 458*7a8a68f5SJulian Pullen strerror(errno)); 459*7a8a68f5SJulian Pullen close(sock); 460*7a8a68f5SJulian Pullen return (NULL); 461*7a8a68f5SJulian Pullen } 462*7a8a68f5SJulian Pullen 463*7a8a68f5SJulian Pullen if (lifn.lifn_count < 1) { 464*7a8a68f5SJulian Pullen logger(LOG_ERR, "No IPv4 network interfaces found"); 465*7a8a68f5SJulian Pullen close(sock); 466*7a8a68f5SJulian Pullen return (NULL); 467*7a8a68f5SJulian Pullen } 468*7a8a68f5SJulian Pullen 469*7a8a68f5SJulian Pullen lifc.lifc_family = AF_INET; 470*7a8a68f5SJulian Pullen lifc.lifc_flags = 0; 471*7a8a68f5SJulian Pullen lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 472*7a8a68f5SJulian Pullen lifc.lifc_buf = malloc(lifc.lifc_len); 473*7a8a68f5SJulian Pullen 474*7a8a68f5SJulian Pullen if (lifc.lifc_buf == NULL) { 475*7a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 476*7a8a68f5SJulian Pullen close(sock); 477*7a8a68f5SJulian Pullen return (NULL); 478*7a8a68f5SJulian Pullen } 479*7a8a68f5SJulian Pullen 480*7a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 481*7a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to list network interfaces (%s)", 482*7a8a68f5SJulian Pullen strerror(errno)); 483*7a8a68f5SJulian Pullen free(lifc.lifc_buf); 484*7a8a68f5SJulian Pullen close(sock); 485*7a8a68f5SJulian Pullen return (NULL); 486*7a8a68f5SJulian Pullen } 487*7a8a68f5SJulian Pullen 488*7a8a68f5SJulian Pullen n = lifc.lifc_len / (int)sizeof (struct lifreq); 489*7a8a68f5SJulian Pullen 490*7a8a68f5SJulian Pullen if ((results = calloc(n + 1, sizeof (ad_subnet_t))) == NULL) { 491*7a8a68f5SJulian Pullen free(lifc.lifc_buf); 492*7a8a68f5SJulian Pullen close(sock); 493*7a8a68f5SJulian Pullen return (NULL); 494*7a8a68f5SJulian Pullen } 495*7a8a68f5SJulian Pullen 496*7a8a68f5SJulian Pullen for (i = 0, lifrp = lifc.lifc_req; i < n; i++, lifrp++) { 497*7a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFFLAGS, lifrp) < 0) 498*7a8a68f5SJulian Pullen continue; 499*7a8a68f5SJulian Pullen 500*7a8a68f5SJulian Pullen if ((lifrp->lifr_flags & IFF_UP) == 0) 501*7a8a68f5SJulian Pullen continue; 502*7a8a68f5SJulian Pullen 503*7a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFSUBNET, lifrp) < 0) 504*7a8a68f5SJulian Pullen continue; 505*7a8a68f5SJulian Pullen 506*7a8a68f5SJulian Pullen prefix_len = lifrp->lifr_addrlen; 507*7a8a68f5SJulian Pullen 508*7a8a68f5SJulian Pullen s = inet_ntoa(((struct sockaddr_in *) 509*7a8a68f5SJulian Pullen &lifrp->lifr_addr)->sin_addr); 510*7a8a68f5SJulian Pullen 511*7a8a68f5SJulian Pullen (void) snprintf(results[i].subnet, sizeof (ad_subnet_t), 512*7a8a68f5SJulian Pullen "%s/%d", s, prefix_len); 513*7a8a68f5SJulian Pullen } 514*7a8a68f5SJulian Pullen 515*7a8a68f5SJulian Pullen free(lifc.lifc_buf); 516*7a8a68f5SJulian Pullen close(sock); 517*7a8a68f5SJulian Pullen 518*7a8a68f5SJulian Pullen return (results); 519*7a8a68f5SJulian Pullen } 520*7a8a68f5SJulian Pullen 521*7a8a68f5SJulian Pullen static int 522*7a8a68f5SJulian Pullen cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2) 523*7a8a68f5SJulian Pullen { 524*7a8a68f5SJulian Pullen int num_subnets1; 525*7a8a68f5SJulian Pullen int num_subnets2; 526*7a8a68f5SJulian Pullen boolean_t matched; 527*7a8a68f5SJulian Pullen int i, j; 528*7a8a68f5SJulian Pullen 529*7a8a68f5SJulian Pullen for (i = 0; subnets1[i].subnet[0] != '\0'; i++) 530*7a8a68f5SJulian Pullen continue; 531*7a8a68f5SJulian Pullen num_subnets1 = i; 532*7a8a68f5SJulian Pullen 533*7a8a68f5SJulian Pullen for (i = 0; subnets2[i].subnet[0] != '\0'; i++) 534*7a8a68f5SJulian Pullen continue; 535*7a8a68f5SJulian Pullen num_subnets2 = i; 536*7a8a68f5SJulian Pullen 537*7a8a68f5SJulian Pullen if (num_subnets1 != num_subnets2) 538*7a8a68f5SJulian Pullen return (1); 539*7a8a68f5SJulian Pullen 540*7a8a68f5SJulian Pullen for (i = 0; i < num_subnets1; i++) { 541*7a8a68f5SJulian Pullen matched = B_FALSE; 542*7a8a68f5SJulian Pullen for (j = 0; j < num_subnets2; j++) { 543*7a8a68f5SJulian Pullen if (strcmp(subnets1[i].subnet, 544*7a8a68f5SJulian Pullen subnets2[j].subnet) == 0) { 545*7a8a68f5SJulian Pullen matched = B_TRUE; 546*7a8a68f5SJulian Pullen break; 547*7a8a68f5SJulian Pullen } 548*7a8a68f5SJulian Pullen } 549*7a8a68f5SJulian Pullen if (!matched) 550*7a8a68f5SJulian Pullen return (1); 551*7a8a68f5SJulian Pullen } 552*7a8a68f5SJulian Pullen return (0); 553*7a8a68f5SJulian Pullen } 554*7a8a68f5SJulian Pullen 555*7a8a68f5SJulian Pullen 556*7a8a68f5SJulian Pullen 557*7a8a68f5SJulian Pullen 558*7a8a68f5SJulian Pullen /* Convert a DN's DC components into a DNS domainname */ 559*7a8a68f5SJulian Pullen char * 560*7a8a68f5SJulian Pullen DN_to_DNS(const char *dn_name) 561*7a8a68f5SJulian Pullen { 562*7a8a68f5SJulian Pullen char dns[DNS_MAX_NAME]; 563*7a8a68f5SJulian Pullen char *dns_name; 564*7a8a68f5SJulian Pullen int i, j; 565*7a8a68f5SJulian Pullen int num = 0; 566*7a8a68f5SJulian Pullen 567*7a8a68f5SJulian Pullen j = 0; 568*7a8a68f5SJulian Pullen i = 0; 569*7a8a68f5SJulian Pullen 570*7a8a68f5SJulian Pullen if (dn_name == NULL) 571*7a8a68f5SJulian Pullen return (NULL); 572*7a8a68f5SJulian Pullen /* 573*7a8a68f5SJulian Pullen * Find all DC=<value> and form DNS name of the 574*7a8a68f5SJulian Pullen * form <value1>.<value2>... 575*7a8a68f5SJulian Pullen */ 576*7a8a68f5SJulian Pullen while (dn_name[i] != '\0') { 577*7a8a68f5SJulian Pullen if (strncasecmp(&dn_name[i], "DC=", 3) == 0) { 578*7a8a68f5SJulian Pullen i += 3; 579*7a8a68f5SJulian Pullen if (dn_name[i] != '\0' && num > 0) 580*7a8a68f5SJulian Pullen dns[j++] = '.'; 581*7a8a68f5SJulian Pullen while (dn_name[i] != '\0' && 582*7a8a68f5SJulian Pullen dn_name[i] != ',' && dn_name[i] != '+') 583*7a8a68f5SJulian Pullen dns[j++] = dn_name[i++]; 584*7a8a68f5SJulian Pullen num++; 585*7a8a68f5SJulian Pullen } else { 586*7a8a68f5SJulian Pullen /* Skip attr=value as it is not DC= */ 587*7a8a68f5SJulian Pullen while (dn_name[i] != '\0' && 588*7a8a68f5SJulian Pullen dn_name[i] != ',' && dn_name[i] != '+') 589*7a8a68f5SJulian Pullen i++; 590*7a8a68f5SJulian Pullen } 591*7a8a68f5SJulian Pullen /* Skip over separator ',' or '+' */ 592*7a8a68f5SJulian Pullen if (dn_name[i] != '\0') i++; 593*7a8a68f5SJulian Pullen } 594*7a8a68f5SJulian Pullen dns[j] = '\0'; 595*7a8a68f5SJulian Pullen dns_name = malloc(j + 1); 596*7a8a68f5SJulian Pullen if (dns_name != NULL) 597*7a8a68f5SJulian Pullen (void) strlcpy(dns_name, dns, j + 1); 598*7a8a68f5SJulian Pullen return (dns_name); 599*7a8a68f5SJulian Pullen } 600*7a8a68f5SJulian Pullen 601*7a8a68f5SJulian Pullen 602*7a8a68f5SJulian Pullen /* Format the DN of an AD LDAP subnet object for some subnet */ 603*7a8a68f5SJulian Pullen static char * 604*7a8a68f5SJulian Pullen subnet_to_DN(const char *subnet, const char *baseDN) 605*7a8a68f5SJulian Pullen { 606*7a8a68f5SJulian Pullen char *result; 607*7a8a68f5SJulian Pullen int len; 608*7a8a68f5SJulian Pullen 609*7a8a68f5SJulian Pullen len = snprintf(NULL, 0, 610*7a8a68f5SJulian Pullen "CN=%s,CN=Subnets,CN=Sites,%s", 611*7a8a68f5SJulian Pullen subnet, baseDN) + 1; 612*7a8a68f5SJulian Pullen 613*7a8a68f5SJulian Pullen result = malloc(len); 614*7a8a68f5SJulian Pullen if (result != NULL) 615*7a8a68f5SJulian Pullen (void) snprintf(result, len, 616*7a8a68f5SJulian Pullen "CN=%s,CN=Subnets,CN=Sites,%s", 617*7a8a68f5SJulian Pullen subnet, baseDN); 618*7a8a68f5SJulian Pullen return (result); 619*7a8a68f5SJulian Pullen } 620*7a8a68f5SJulian Pullen 621*7a8a68f5SJulian Pullen 622*7a8a68f5SJulian Pullen /* Make a list of subnet object DNs from a list of subnets */ 623*7a8a68f5SJulian Pullen static char ** 624*7a8a68f5SJulian Pullen subnets_to_DNs(ad_subnet_t *subnets, const char *base_dn) 625*7a8a68f5SJulian Pullen { 626*7a8a68f5SJulian Pullen char **results; 627*7a8a68f5SJulian Pullen int i, j; 628*7a8a68f5SJulian Pullen 629*7a8a68f5SJulian Pullen for (i = 0; subnets[i].subnet[0] != '\0'; i++) 630*7a8a68f5SJulian Pullen continue; 631*7a8a68f5SJulian Pullen 632*7a8a68f5SJulian Pullen results = calloc(i + 1, sizeof (char *)); 633*7a8a68f5SJulian Pullen if (results == NULL) 634*7a8a68f5SJulian Pullen return (NULL); 635*7a8a68f5SJulian Pullen 636*7a8a68f5SJulian Pullen for (i = 0; subnets[i].subnet[0] != '\0'; i++) { 637*7a8a68f5SJulian Pullen if ((results[i] = subnet_to_DN(subnets[i].subnet, base_dn)) 638*7a8a68f5SJulian Pullen == NULL) { 639*7a8a68f5SJulian Pullen for (j = 0; j < i; j++) 640*7a8a68f5SJulian Pullen free(results[j]); 641*7a8a68f5SJulian Pullen free(results); 642*7a8a68f5SJulian Pullen return (NULL); 643*7a8a68f5SJulian Pullen } 644*7a8a68f5SJulian Pullen } 645*7a8a68f5SJulian Pullen 646*7a8a68f5SJulian Pullen return (results); 647*7a8a68f5SJulian Pullen } 648*7a8a68f5SJulian Pullen 649*7a8a68f5SJulian Pullen 650*7a8a68f5SJulian Pullen /* Compare SRC RRs; used with qsort() */ 651*7a8a68f5SJulian Pullen static int 652*7a8a68f5SJulian Pullen srvcmp(idmap_ad_disc_ds_t *s1, idmap_ad_disc_ds_t *s2) 653*7a8a68f5SJulian Pullen { 654*7a8a68f5SJulian Pullen if (s1->priority < s2->priority) 655*7a8a68f5SJulian Pullen return (1); 656*7a8a68f5SJulian Pullen else if (s1->priority > s2->priority) 657*7a8a68f5SJulian Pullen return (-1); 658*7a8a68f5SJulian Pullen 659*7a8a68f5SJulian Pullen if (s1->weight < s2->weight) 660*7a8a68f5SJulian Pullen return (1); 661*7a8a68f5SJulian Pullen else if (s1->weight > s2->weight) 662*7a8a68f5SJulian Pullen return (-1); 663*7a8a68f5SJulian Pullen 664*7a8a68f5SJulian Pullen return (0); 665*7a8a68f5SJulian Pullen } 666*7a8a68f5SJulian Pullen 667*7a8a68f5SJulian Pullen 668*7a8a68f5SJulian Pullen /* 669*7a8a68f5SJulian Pullen * Query or search the SRV RRs for a given name. 670*7a8a68f5SJulian Pullen * 671*7a8a68f5SJulian Pullen * If name == NULL then search (as in res_nsearch(3RESOLV), honoring any 672*7a8a68f5SJulian Pullen * search list/option), else query (as in res_nquery(3RESOLV)). 673*7a8a68f5SJulian Pullen * 674*7a8a68f5SJulian Pullen * The output TTL will be the one of the SRV RR with the lowest TTL. 675*7a8a68f5SJulian Pullen */ 676*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t * 677*7a8a68f5SJulian Pullen srv_query(res_state state, const char *svc_name, const char *dname, 678*7a8a68f5SJulian Pullen char **rrname, uint32_t *ttl) 679*7a8a68f5SJulian Pullen { 680*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *srv; 681*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *srv_res; 682*7a8a68f5SJulian Pullen union { 683*7a8a68f5SJulian Pullen HEADER hdr; 684*7a8a68f5SJulian Pullen uchar_t buf[NS_MAXMSG]; 685*7a8a68f5SJulian Pullen } msg; 686*7a8a68f5SJulian Pullen int len, cnt, qdcount, ancount; 687*7a8a68f5SJulian Pullen uchar_t *ptr, *eom; 688*7a8a68f5SJulian Pullen uchar_t *end; 689*7a8a68f5SJulian Pullen uint16_t type; 690*7a8a68f5SJulian Pullen /* LINTED E_FUNC_SET_NOT_USED */ 691*7a8a68f5SJulian Pullen uint16_t class; 692*7a8a68f5SJulian Pullen uint32_t rttl; 693*7a8a68f5SJulian Pullen uint16_t size; 694*7a8a68f5SJulian Pullen char namebuf[NS_MAXDNAME]; 695*7a8a68f5SJulian Pullen 696*7a8a68f5SJulian Pullen if (state == NULL) 697*7a8a68f5SJulian Pullen return (NULL); 698*7a8a68f5SJulian Pullen 699*7a8a68f5SJulian Pullen /* Set negative result TTL */ 700*7a8a68f5SJulian Pullen *ttl = 5 * 60; 701*7a8a68f5SJulian Pullen 702*7a8a68f5SJulian Pullen /* 1. query necessary resource records */ 703*7a8a68f5SJulian Pullen 704*7a8a68f5SJulian Pullen /* Search, querydomain or query */ 705*7a8a68f5SJulian Pullen if (rrname != NULL) { 706*7a8a68f5SJulian Pullen *rrname = NULL; 707*7a8a68f5SJulian Pullen len = res_nsearch(state, svc_name, C_IN, T_SRV, 708*7a8a68f5SJulian Pullen msg.buf, sizeof (msg.buf)); 709*7a8a68f5SJulian Pullen logger(LOG_DEBUG, "Searching DNS for SRV RRs named '%s'", 710*7a8a68f5SJulian Pullen svc_name); 711*7a8a68f5SJulian Pullen if (len < 0) { 712*7a8a68f5SJulian Pullen logger(LOG_DEBUG, "DNS search for '%s' failed (%s)", 713*7a8a68f5SJulian Pullen svc_name, hstrerror(state->res_h_errno)); 714*7a8a68f5SJulian Pullen return (NULL); 715*7a8a68f5SJulian Pullen } 716*7a8a68f5SJulian Pullen } else if (dname != NULL) { 717*7a8a68f5SJulian Pullen len = res_nquerydomain(state, svc_name, dname, C_IN, T_SRV, 718*7a8a68f5SJulian Pullen msg.buf, sizeof (msg.buf)); 719*7a8a68f5SJulian Pullen logger(LOG_DEBUG, 720*7a8a68f5SJulian Pullen "Querying DNS for SRV RRs named '%s' for '%s' ", 721*7a8a68f5SJulian Pullen svc_name, dname); 722*7a8a68f5SJulian Pullen 723*7a8a68f5SJulian Pullen if (len < 0) { 724*7a8a68f5SJulian Pullen logger(LOG_DEBUG, 725*7a8a68f5SJulian Pullen "DNS query for '%s' for '%s' failed (%s)", 726*7a8a68f5SJulian Pullen svc_name, dname, hstrerror(state->res_h_errno)); 727*7a8a68f5SJulian Pullen return (NULL); 728*7a8a68f5SJulian Pullen } 729*7a8a68f5SJulian Pullen } 730*7a8a68f5SJulian Pullen 731*7a8a68f5SJulian Pullen if (len > sizeof (msg.buf)) { 732*7a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query %ib message doesn't fit" 733*7a8a68f5SJulian Pullen " into %ib buffer", 734*7a8a68f5SJulian Pullen len, sizeof (msg.buf)); 735*7a8a68f5SJulian Pullen return (NULL); 736*7a8a68f5SJulian Pullen } 737*7a8a68f5SJulian Pullen 738*7a8a68f5SJulian Pullen /* 2. parse the reply, skip header and question sections */ 739*7a8a68f5SJulian Pullen 740*7a8a68f5SJulian Pullen ptr = msg.buf + sizeof (msg.hdr); 741*7a8a68f5SJulian Pullen eom = msg.buf + len; 742*7a8a68f5SJulian Pullen qdcount = ntohs(msg.hdr.qdcount); 743*7a8a68f5SJulian Pullen ancount = ntohs(msg.hdr.ancount); 744*7a8a68f5SJulian Pullen 745*7a8a68f5SJulian Pullen for (cnt = qdcount; cnt > 0; --cnt) { 746*7a8a68f5SJulian Pullen if ((len = dn_skipname(ptr, eom)) < 0) { 747*7a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid message format"); 748*7a8a68f5SJulian Pullen return (NULL); 749*7a8a68f5SJulian Pullen } 750*7a8a68f5SJulian Pullen ptr += len + QFIXEDSZ; 751*7a8a68f5SJulian Pullen } 752*7a8a68f5SJulian Pullen 753*7a8a68f5SJulian Pullen /* 3. walk through the answer section */ 754*7a8a68f5SJulian Pullen 755*7a8a68f5SJulian Pullen srv_res = calloc(ancount + 1, sizeof (idmap_ad_disc_ds_t)); 756*7a8a68f5SJulian Pullen *ttl = (uint32_t)-1; 757*7a8a68f5SJulian Pullen 758*7a8a68f5SJulian Pullen for (srv = srv_res, cnt = ancount; 759*7a8a68f5SJulian Pullen cnt > 0; --cnt, srv++) { 760*7a8a68f5SJulian Pullen 761*7a8a68f5SJulian Pullen len = dn_expand(msg.buf, eom, ptr, namebuf, 762*7a8a68f5SJulian Pullen sizeof (namebuf)); 763*7a8a68f5SJulian Pullen if (len < 0) { 764*7a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid message format"); 765*7a8a68f5SJulian Pullen return (NULL); 766*7a8a68f5SJulian Pullen } 767*7a8a68f5SJulian Pullen if (rrname != NULL && *rrname == NULL) 768*7a8a68f5SJulian Pullen *rrname = strdup(namebuf); 769*7a8a68f5SJulian Pullen ptr += len; 770*7a8a68f5SJulian Pullen NS_GET16(type, ptr); 771*7a8a68f5SJulian Pullen NS_GET16(class, ptr); 772*7a8a68f5SJulian Pullen NS_GET32(rttl, ptr); 773*7a8a68f5SJulian Pullen NS_GET16(size, ptr); 774*7a8a68f5SJulian Pullen if ((end = ptr + size) > eom) { 775*7a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid message format"); 776*7a8a68f5SJulian Pullen return (NULL); 777*7a8a68f5SJulian Pullen } 778*7a8a68f5SJulian Pullen 779*7a8a68f5SJulian Pullen if (type != T_SRV) { 780*7a8a68f5SJulian Pullen ptr = end; 781*7a8a68f5SJulian Pullen continue; 782*7a8a68f5SJulian Pullen } 783*7a8a68f5SJulian Pullen 784*7a8a68f5SJulian Pullen NS_GET16(srv->priority, ptr); 785*7a8a68f5SJulian Pullen NS_GET16(srv->weight, ptr); 786*7a8a68f5SJulian Pullen NS_GET16(srv->port, ptr); 787*7a8a68f5SJulian Pullen len = dn_expand(msg.buf, eom, ptr, srv->host, 788*7a8a68f5SJulian Pullen sizeof (srv->host)); 789*7a8a68f5SJulian Pullen if (len < 0) { 790*7a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid SRV record"); 791*7a8a68f5SJulian Pullen return (NULL); 792*7a8a68f5SJulian Pullen } 793*7a8a68f5SJulian Pullen 794*7a8a68f5SJulian Pullen if (rttl < *ttl) 795*7a8a68f5SJulian Pullen *ttl = rttl; 796*7a8a68f5SJulian Pullen 797*7a8a68f5SJulian Pullen logger(LOG_DEBUG, "Found %s %d IN SRV [%d][%d] %s:%d", 798*7a8a68f5SJulian Pullen namebuf, rttl, srv->priority, srv->weight, srv->host, 799*7a8a68f5SJulian Pullen srv->port); 800*7a8a68f5SJulian Pullen 801*7a8a68f5SJulian Pullen /* 3. move ptr to the end of current record */ 802*7a8a68f5SJulian Pullen 803*7a8a68f5SJulian Pullen ptr = end; 804*7a8a68f5SJulian Pullen } 805*7a8a68f5SJulian Pullen 806*7a8a68f5SJulian Pullen if (ancount > 1) 807*7a8a68f5SJulian Pullen qsort(srv_res, ancount, sizeof (*srv_res), 808*7a8a68f5SJulian Pullen (int (*)(const void *, const void *))srvcmp); 809*7a8a68f5SJulian Pullen 810*7a8a68f5SJulian Pullen return (srv_res); 811*7a8a68f5SJulian Pullen } 812*7a8a68f5SJulian Pullen 813*7a8a68f5SJulian Pullen 814*7a8a68f5SJulian Pullen /* 815*7a8a68f5SJulian Pullen * A utility function to bind to a Directory server 816*7a8a68f5SJulian Pullen */ 817*7a8a68f5SJulian Pullen 818*7a8a68f5SJulian Pullen static LDAP* 819*7a8a68f5SJulian Pullen ldap_lookup_init(idmap_ad_disc_ds_t *ds) 820*7a8a68f5SJulian Pullen { 821*7a8a68f5SJulian Pullen int i; 822*7a8a68f5SJulian Pullen int rc, ldversion; 823*7a8a68f5SJulian Pullen int zero = 0; 824*7a8a68f5SJulian Pullen int timeoutms = 5 * 1000; 825*7a8a68f5SJulian Pullen char *saslmech = "GSSAPI"; 826*7a8a68f5SJulian Pullen uint32_t saslflags = LDAP_SASL_INTERACTIVE; 827*7a8a68f5SJulian Pullen LDAP *ld = NULL; 828*7a8a68f5SJulian Pullen 829*7a8a68f5SJulian Pullen for (i = 0; ds[i].host[0] != '\0'; i++) { 830*7a8a68f5SJulian Pullen ld = ldap_init(ds[i].host, ds[i].port); 831*7a8a68f5SJulian Pullen if (ld == NULL) { 832*7a8a68f5SJulian Pullen logger(LOG_DEBUG, "Couldn't connect to " 833*7a8a68f5SJulian Pullen "AD DC %s:%d (%s)", 834*7a8a68f5SJulian Pullen ds[i].host, ds[i].port, 835*7a8a68f5SJulian Pullen strerror(errno)); 836*7a8a68f5SJulian Pullen continue; 837*7a8a68f5SJulian Pullen } 838*7a8a68f5SJulian Pullen 839*7a8a68f5SJulian Pullen ldversion = LDAP_VERSION3; 840*7a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 841*7a8a68f5SJulian Pullen &ldversion); 842*7a8a68f5SJulian Pullen 843*7a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, 844*7a8a68f5SJulian Pullen LDAP_OPT_OFF); 845*7a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 846*7a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 847*7a8a68f5SJulian Pullen /* setup TCP/IP connect timeout */ 848*7a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 849*7a8a68f5SJulian Pullen &timeoutms); 850*7a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_RESTART, 851*7a8a68f5SJulian Pullen LDAP_OPT_ON); 852*7a8a68f5SJulian Pullen 853*7a8a68f5SJulian Pullen rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */, 854*7a8a68f5SJulian Pullen saslmech, NULL, NULL, saslflags, &saslcallback, 855*7a8a68f5SJulian Pullen NULL /* defaults */); 856*7a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) 857*7a8a68f5SJulian Pullen break; 858*7a8a68f5SJulian Pullen 859*7a8a68f5SJulian Pullen logger(LOG_INFO, "LDAP SASL bind to %s:%d failed (%s)", 860*7a8a68f5SJulian Pullen ds[i].host, ds[i].port, ldap_err2string(rc)); 861*7a8a68f5SJulian Pullen (void) ldap_unbind(ld); 862*7a8a68f5SJulian Pullen ld = NULL; 863*7a8a68f5SJulian Pullen } 864*7a8a68f5SJulian Pullen return (ld); 865*7a8a68f5SJulian Pullen } 866*7a8a68f5SJulian Pullen 867*7a8a68f5SJulian Pullen 868*7a8a68f5SJulian Pullen 869*7a8a68f5SJulian Pullen /* 870*7a8a68f5SJulian Pullen * A utility function to get the value of some attribute of one of one 871*7a8a68f5SJulian Pullen * or more AD LDAP objects named by the dn_list; first found one wins. 872*7a8a68f5SJulian Pullen */ 873*7a8a68f5SJulian Pullen static char * 874*7a8a68f5SJulian Pullen ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers, 875*7a8a68f5SJulian Pullen char **dn_list, char *attr) 876*7a8a68f5SJulian Pullen { 877*7a8a68f5SJulian Pullen int i; 878*7a8a68f5SJulian Pullen int rc; 879*7a8a68f5SJulian Pullen int scope = LDAP_SCOPE_BASE; 880*7a8a68f5SJulian Pullen char *attrs[2]; 881*7a8a68f5SJulian Pullen LDAPMessage *results = NULL; 882*7a8a68f5SJulian Pullen LDAPMessage *entry; 883*7a8a68f5SJulian Pullen char **values = NULL; 884*7a8a68f5SJulian Pullen char *val = NULL; 885*7a8a68f5SJulian Pullen 886*7a8a68f5SJulian Pullen attrs[0] = attr; 887*7a8a68f5SJulian Pullen attrs[1] = NULL; 888*7a8a68f5SJulian Pullen 889*7a8a68f5SJulian Pullen if (*ld == NULL) 890*7a8a68f5SJulian Pullen *ld = ldap_lookup_init(domainControllers); 891*7a8a68f5SJulian Pullen 892*7a8a68f5SJulian Pullen if (*ld == NULL) 893*7a8a68f5SJulian Pullen return (NULL); 894*7a8a68f5SJulian Pullen 895*7a8a68f5SJulian Pullen for (i = 0; dn_list[i] != NULL; i++) { 896*7a8a68f5SJulian Pullen rc = ldap_search_s(*ld, dn_list[i], scope, 897*7a8a68f5SJulian Pullen "(objectclass=*)", attrs, 0, &results); 898*7a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) { 899*7a8a68f5SJulian Pullen for (entry = ldap_first_entry(*ld, results); 900*7a8a68f5SJulian Pullen entry != NULL && values == NULL; 901*7a8a68f5SJulian Pullen entry = ldap_next_entry(*ld, entry)) { 902*7a8a68f5SJulian Pullen values = ldap_get_values( 903*7a8a68f5SJulian Pullen *ld, entry, attr); 904*7a8a68f5SJulian Pullen } 905*7a8a68f5SJulian Pullen 906*7a8a68f5SJulian Pullen if (values != NULL) { 907*7a8a68f5SJulian Pullen (void) ldap_msgfree(results); 908*7a8a68f5SJulian Pullen val = strdup(values[0]); 909*7a8a68f5SJulian Pullen ldap_value_free(values); 910*7a8a68f5SJulian Pullen return (val); 911*7a8a68f5SJulian Pullen } 912*7a8a68f5SJulian Pullen } 913*7a8a68f5SJulian Pullen if (results != NULL) { 914*7a8a68f5SJulian Pullen (void) ldap_msgfree(results); 915*7a8a68f5SJulian Pullen results = NULL; 916*7a8a68f5SJulian Pullen } 917*7a8a68f5SJulian Pullen } 918*7a8a68f5SJulian Pullen 919*7a8a68f5SJulian Pullen return (NULL); 920*7a8a68f5SJulian Pullen } 921*7a8a68f5SJulian Pullen 922*7a8a68f5SJulian Pullen 923*7a8a68f5SJulian Pullen /* 924*7a8a68f5SJulian Pullen * Lookup the trusted domains in the global catalog. 925*7a8a68f5SJulian Pullen * 926*7a8a68f5SJulian Pullen * Returns: 927*7a8a68f5SJulian Pullen * array of trusted domains which is terminated by 928*7a8a68f5SJulian Pullen * an empty trusted domain. 929*7a8a68f5SJulian Pullen * NULL an error occured 930*7a8a68f5SJulian Pullen */ 931*7a8a68f5SJulian Pullen ad_disc_trusteddomains_t * 932*7a8a68f5SJulian Pullen ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog, 933*7a8a68f5SJulian Pullen char *base_dn) 934*7a8a68f5SJulian Pullen { 935*7a8a68f5SJulian Pullen int scope = LDAP_SCOPE_SUBTREE; 936*7a8a68f5SJulian Pullen char *attrs[3]; 937*7a8a68f5SJulian Pullen int rc; 938*7a8a68f5SJulian Pullen LDAPMessage *results = NULL; 939*7a8a68f5SJulian Pullen LDAPMessage *entry; 940*7a8a68f5SJulian Pullen char *filter; 941*7a8a68f5SJulian Pullen char **partner = NULL; 942*7a8a68f5SJulian Pullen char **direction = NULL; 943*7a8a68f5SJulian Pullen int num = 0; 944*7a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 945*7a8a68f5SJulian Pullen 946*7a8a68f5SJulian Pullen 947*7a8a68f5SJulian Pullen if (*ld == NULL) 948*7a8a68f5SJulian Pullen *ld = ldap_lookup_init(globalCatalog); 949*7a8a68f5SJulian Pullen 950*7a8a68f5SJulian Pullen if (*ld == NULL) 951*7a8a68f5SJulian Pullen return (NULL); 952*7a8a68f5SJulian Pullen 953*7a8a68f5SJulian Pullen attrs[0] = "trustPartner"; 954*7a8a68f5SJulian Pullen attrs[1] = "trustDirection"; 955*7a8a68f5SJulian Pullen attrs[2] = NULL; 956*7a8a68f5SJulian Pullen 957*7a8a68f5SJulian Pullen /* trustDirection values - inbound = 1 and bidirectional = 3 */ 958*7a8a68f5SJulian Pullen filter = "(&(objectclass=trustedDomain)" 959*7a8a68f5SJulian Pullen "(|(trustDirection=3)(trustDirection=1)))"; 960*7a8a68f5SJulian Pullen 961*7a8a68f5SJulian Pullen rc = ldap_search_s(*ld, base_dn, scope, filter, attrs, 0, &results); 962*7a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) { 963*7a8a68f5SJulian Pullen for (entry = ldap_first_entry(*ld, results); 964*7a8a68f5SJulian Pullen entry != NULL; entry = ldap_next_entry(*ld, entry)) { 965*7a8a68f5SJulian Pullen partner = ldap_get_values(*ld, entry, "trustPartner"); 966*7a8a68f5SJulian Pullen direction = ldap_get_values( 967*7a8a68f5SJulian Pullen *ld, entry, "trustDirection"); 968*7a8a68f5SJulian Pullen 969*7a8a68f5SJulian Pullen if (partner != NULL && direction != NULL) { 970*7a8a68f5SJulian Pullen num++; 971*7a8a68f5SJulian Pullen trusted_domains = realloc(trusted_domains, 972*7a8a68f5SJulian Pullen (num + 1) * 973*7a8a68f5SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 974*7a8a68f5SJulian Pullen if (trusted_domains == NULL) { 975*7a8a68f5SJulian Pullen ldap_value_free(partner); 976*7a8a68f5SJulian Pullen ldap_value_free(direction); 977*7a8a68f5SJulian Pullen ldap_msgfree(results); 978*7a8a68f5SJulian Pullen return (NULL); 979*7a8a68f5SJulian Pullen } 980*7a8a68f5SJulian Pullen /* Last element should be zero */ 981*7a8a68f5SJulian Pullen memset(&trusted_domains[num], 0, 982*7a8a68f5SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 983*7a8a68f5SJulian Pullen strcpy(trusted_domains[num - 1].domain, 984*7a8a68f5SJulian Pullen partner[0]); 985*7a8a68f5SJulian Pullen trusted_domains[num - 1].direction = 986*7a8a68f5SJulian Pullen atoi(direction[0]); 987*7a8a68f5SJulian Pullen } 988*7a8a68f5SJulian Pullen if (partner != NULL) 989*7a8a68f5SJulian Pullen ldap_value_free(partner); 990*7a8a68f5SJulian Pullen if (direction != NULL) 991*7a8a68f5SJulian Pullen ldap_value_free(direction); 992*7a8a68f5SJulian Pullen } 993*7a8a68f5SJulian Pullen } else if (rc == LDAP_NO_RESULTS_RETURNED) { 994*7a8a68f5SJulian Pullen /* This is not an error - return empty trusted domain */ 995*7a8a68f5SJulian Pullen trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t)); 996*7a8a68f5SJulian Pullen } 997*7a8a68f5SJulian Pullen if (results != NULL) 998*7a8a68f5SJulian Pullen ldap_msgfree(results); 999*7a8a68f5SJulian Pullen 1000*7a8a68f5SJulian Pullen return (trusted_domains); 1001*7a8a68f5SJulian Pullen } 1002*7a8a68f5SJulian Pullen 1003*7a8a68f5SJulian Pullen 1004*7a8a68f5SJulian Pullen /* 1005*7a8a68f5SJulian Pullen * This functions finds all the domains in a forest. 1006*7a8a68f5SJulian Pullen * It first finds all the naming contexts by finding the 1007*7a8a68f5SJulian Pullen * root DSE attribute namingContext. For each naming context 1008*7a8a68f5SJulian Pullen * it performes an entry search looking for Domain object class 1009*7a8a68f5SJulian Pullen * returning the attribute objectSid. 1010*7a8a68f5SJulian Pullen */ 1011*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t * 1012*7a8a68f5SJulian Pullen ldap_lookup_domains_in_forest(LDAP **ld, idmap_ad_disc_ds_t *globalCatalogs) 1013*7a8a68f5SJulian Pullen { 1014*7a8a68f5SJulian Pullen int scope = LDAP_SCOPE_BASE; 1015*7a8a68f5SJulian Pullen char *attrs[2]; 1016*7a8a68f5SJulian Pullen char *root_attrs[2]; 1017*7a8a68f5SJulian Pullen int rc; 1018*7a8a68f5SJulian Pullen LDAPMessage *result = NULL; 1019*7a8a68f5SJulian Pullen LDAPMessage *entry; 1020*7a8a68f5SJulian Pullen char *filter; 1021*7a8a68f5SJulian Pullen char **nc = NULL; 1022*7a8a68f5SJulian Pullen struct berval **sid_ber; 1023*7a8a68f5SJulian Pullen int num = 0; 1024*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains = NULL; 1025*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t *tmp; 1026*7a8a68f5SJulian Pullen int i; 1027*7a8a68f5SJulian Pullen char *name; 1028*7a8a68f5SJulian Pullen adutils_sid_t sid; 1029*7a8a68f5SJulian Pullen char *sid_str; 1030*7a8a68f5SJulian Pullen 1031*7a8a68f5SJulian Pullen 1032*7a8a68f5SJulian Pullen if (*ld == NULL) 1033*7a8a68f5SJulian Pullen *ld = ldap_lookup_init(globalCatalogs); 1034*7a8a68f5SJulian Pullen 1035*7a8a68f5SJulian Pullen if (*ld == NULL) 1036*7a8a68f5SJulian Pullen return (NULL); 1037*7a8a68f5SJulian Pullen 1038*7a8a68f5SJulian Pullen root_attrs[0] = "namingContexts"; 1039*7a8a68f5SJulian Pullen root_attrs[1] = NULL; 1040*7a8a68f5SJulian Pullen 1041*7a8a68f5SJulian Pullen attrs[0] = "objectSid"; 1042*7a8a68f5SJulian Pullen attrs[1] = NULL; 1043*7a8a68f5SJulian Pullen 1044*7a8a68f5SJulian Pullen filter = "(objectclass=Domain)"; 1045*7a8a68f5SJulian Pullen 1046*7a8a68f5SJulian Pullen /* Find naming contexts */ 1047*7a8a68f5SJulian Pullen rc = ldap_search_s(*ld, LDAP_ROOT_DSE, scope, "(objectClass=*)", 1048*7a8a68f5SJulian Pullen root_attrs, 0, &result); 1049*7a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) { 1050*7a8a68f5SJulian Pullen entry = ldap_first_entry(*ld, result); 1051*7a8a68f5SJulian Pullen if (entry != NULL) { 1052*7a8a68f5SJulian Pullen nc = ldap_get_values(*ld, entry, "namingContexts"); 1053*7a8a68f5SJulian Pullen } 1054*7a8a68f5SJulian Pullen } 1055*7a8a68f5SJulian Pullen if (result != NULL) 1056*7a8a68f5SJulian Pullen ldap_msgfree(result); 1057*7a8a68f5SJulian Pullen if (nc == NULL) 1058*7a8a68f5SJulian Pullen return (NULL); 1059*7a8a68f5SJulian Pullen 1060*7a8a68f5SJulian Pullen /* Find domains */ 1061*7a8a68f5SJulian Pullen for (i = 0; nc[i] != NULL; i++) { 1062*7a8a68f5SJulian Pullen rc = ldap_search_s(*ld, nc[i], scope, filter, attrs, 0, 1063*7a8a68f5SJulian Pullen &result); 1064*7a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) { 1065*7a8a68f5SJulian Pullen entry = ldap_first_entry(*ld, result); 1066*7a8a68f5SJulian Pullen if (entry != NULL) { 1067*7a8a68f5SJulian Pullen sid_ber = ldap_get_values_len(*ld, entry, 1068*7a8a68f5SJulian Pullen "objectSid"); 1069*7a8a68f5SJulian Pullen if (sid_ber != NULL) { 1070*7a8a68f5SJulian Pullen num++; 1071*7a8a68f5SJulian Pullen tmp = realloc(domains, 1072*7a8a68f5SJulian Pullen (num + 1) * 1073*7a8a68f5SJulian Pullen sizeof (ad_disc_domainsinforest_t)); 1074*7a8a68f5SJulian Pullen if (tmp == NULL) { 1075*7a8a68f5SJulian Pullen if (domains != NULL) 1076*7a8a68f5SJulian Pullen free(domains); 1077*7a8a68f5SJulian Pullen ldap_value_free_len(sid_ber); 1078*7a8a68f5SJulian Pullen ldap_msgfree(result); 1079*7a8a68f5SJulian Pullen ldap_value_free(nc); 1080*7a8a68f5SJulian Pullen return (NULL); 1081*7a8a68f5SJulian Pullen } 1082*7a8a68f5SJulian Pullen domains = tmp; 1083*7a8a68f5SJulian Pullen memset(&domains[num], 0, 1084*7a8a68f5SJulian Pullen sizeof (ad_disc_domainsinforest_t)); 1085*7a8a68f5SJulian Pullen 1086*7a8a68f5SJulian Pullen if (adutils_getsid(sid_ber[0], &sid) 1087*7a8a68f5SJulian Pullen < 0) { 1088*7a8a68f5SJulian Pullen free(domains); 1089*7a8a68f5SJulian Pullen ldap_value_free_len(sid_ber); 1090*7a8a68f5SJulian Pullen ldap_msgfree(result); 1091*7a8a68f5SJulian Pullen ldap_value_free(nc); 1092*7a8a68f5SJulian Pullen return (NULL); 1093*7a8a68f5SJulian Pullen } 1094*7a8a68f5SJulian Pullen if ((sid_str = adutils_sid2txt(&sid)) 1095*7a8a68f5SJulian Pullen == NULL) { 1096*7a8a68f5SJulian Pullen free(domains); 1097*7a8a68f5SJulian Pullen ldap_value_free_len(sid_ber); 1098*7a8a68f5SJulian Pullen ldap_msgfree(result); 1099*7a8a68f5SJulian Pullen ldap_value_free(nc); 1100*7a8a68f5SJulian Pullen return (NULL); 1101*7a8a68f5SJulian Pullen } 1102*7a8a68f5SJulian Pullen 1103*7a8a68f5SJulian Pullen ldap_value_free_len(sid_ber); 1104*7a8a68f5SJulian Pullen strcpy(domains[num - 1].sid, sid_str); 1105*7a8a68f5SJulian Pullen free(sid_str); 1106*7a8a68f5SJulian Pullen 1107*7a8a68f5SJulian Pullen name = DN_to_DNS(nc[i]); 1108*7a8a68f5SJulian Pullen if (name == NULL) { 1109*7a8a68f5SJulian Pullen free(domains); 1110*7a8a68f5SJulian Pullen ldap_msgfree(result); 1111*7a8a68f5SJulian Pullen ldap_value_free(nc); 1112*7a8a68f5SJulian Pullen return (NULL); 1113*7a8a68f5SJulian Pullen } 1114*7a8a68f5SJulian Pullen strcpy(domains[num - 1].domain, name); 1115*7a8a68f5SJulian Pullen free(name); 1116*7a8a68f5SJulian Pullen } 1117*7a8a68f5SJulian Pullen } 1118*7a8a68f5SJulian Pullen } 1119*7a8a68f5SJulian Pullen if (result != NULL) 1120*7a8a68f5SJulian Pullen ldap_msgfree(result); 1121*7a8a68f5SJulian Pullen } 1122*7a8a68f5SJulian Pullen ldap_value_free(nc); 1123*7a8a68f5SJulian Pullen 1124*7a8a68f5SJulian Pullen return (domains); 1125*7a8a68f5SJulian Pullen } 1126*7a8a68f5SJulian Pullen 1127*7a8a68f5SJulian Pullen 1128*7a8a68f5SJulian Pullen ad_disc_t 1129*7a8a68f5SJulian Pullen ad_disc_init(void) 1130*7a8a68f5SJulian Pullen { 1131*7a8a68f5SJulian Pullen struct ad_disc *ctx; 1132*7a8a68f5SJulian Pullen ctx = calloc(1, sizeof (struct ad_disc)); 1133*7a8a68f5SJulian Pullen if (ctx != NULL) 1134*7a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1135*7a8a68f5SJulian Pullen 1136*7a8a68f5SJulian Pullen ctx->domain_name.type = AD_STRING; 1137*7a8a68f5SJulian Pullen ctx->domain_controller.type = AD_DIRECTORY; 1138*7a8a68f5SJulian Pullen ctx->site_name.type = AD_STRING; 1139*7a8a68f5SJulian Pullen ctx->forest_name.type = AD_STRING; 1140*7a8a68f5SJulian Pullen ctx->global_catalog.type = AD_DIRECTORY; 1141*7a8a68f5SJulian Pullen ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST; 1142*7a8a68f5SJulian Pullen ctx->trusted_domains.type = AD_TRUSTED_DOMAINS; 1143*7a8a68f5SJulian Pullen /* Site specific versions */ 1144*7a8a68f5SJulian Pullen ctx->site_domain_controller.type = AD_DIRECTORY; 1145*7a8a68f5SJulian Pullen ctx->site_global_catalog.type = AD_DIRECTORY; 1146*7a8a68f5SJulian Pullen return (ctx); 1147*7a8a68f5SJulian Pullen } 1148*7a8a68f5SJulian Pullen 1149*7a8a68f5SJulian Pullen 1150*7a8a68f5SJulian Pullen void 1151*7a8a68f5SJulian Pullen ad_disc_fini(ad_disc_t ctx) 1152*7a8a68f5SJulian Pullen { 1153*7a8a68f5SJulian Pullen if (ctx == NULL) 1154*7a8a68f5SJulian Pullen return; 1155*7a8a68f5SJulian Pullen 1156*7a8a68f5SJulian Pullen if (ctx->res_ninitted) 1157*7a8a68f5SJulian Pullen res_ndestroy(&ctx->res_state); 1158*7a8a68f5SJulian Pullen 1159*7a8a68f5SJulian Pullen if (ctx->subnets != NULL) 1160*7a8a68f5SJulian Pullen free(ctx->subnets); 1161*7a8a68f5SJulian Pullen 1162*7a8a68f5SJulian Pullen if (ctx->domain_name.value != NULL) 1163*7a8a68f5SJulian Pullen free(ctx->domain_name.value); 1164*7a8a68f5SJulian Pullen 1165*7a8a68f5SJulian Pullen if (ctx->domain_controller.value != NULL) 1166*7a8a68f5SJulian Pullen free(ctx->domain_controller.value); 1167*7a8a68f5SJulian Pullen 1168*7a8a68f5SJulian Pullen if (ctx->site_name.value != NULL) 1169*7a8a68f5SJulian Pullen free(ctx->site_name.value); 1170*7a8a68f5SJulian Pullen 1171*7a8a68f5SJulian Pullen if (ctx->forest_name.value != NULL) 1172*7a8a68f5SJulian Pullen free(ctx->forest_name.value); 1173*7a8a68f5SJulian Pullen 1174*7a8a68f5SJulian Pullen if (ctx->global_catalog.value != NULL) 1175*7a8a68f5SJulian Pullen free(ctx->global_catalog.value); 1176*7a8a68f5SJulian Pullen 1177*7a8a68f5SJulian Pullen if (ctx->domains_in_forest.value != NULL) 1178*7a8a68f5SJulian Pullen free(ctx->domains_in_forest.value); 1179*7a8a68f5SJulian Pullen 1180*7a8a68f5SJulian Pullen if (ctx->trusted_domains.value != NULL) 1181*7a8a68f5SJulian Pullen free(ctx->trusted_domains.value); 1182*7a8a68f5SJulian Pullen 1183*7a8a68f5SJulian Pullen /* Site specific versions */ 1184*7a8a68f5SJulian Pullen if (ctx->site_domain_controller.value != NULL) 1185*7a8a68f5SJulian Pullen free(ctx->site_domain_controller.value); 1186*7a8a68f5SJulian Pullen 1187*7a8a68f5SJulian Pullen if (ctx->site_global_catalog.value != NULL) 1188*7a8a68f5SJulian Pullen free(ctx->site_global_catalog.value); 1189*7a8a68f5SJulian Pullen 1190*7a8a68f5SJulian Pullen free(ctx); 1191*7a8a68f5SJulian Pullen } 1192*7a8a68f5SJulian Pullen 1193*7a8a68f5SJulian Pullen void 1194*7a8a68f5SJulian Pullen ad_disc_refresh(ad_disc_t ctx) 1195*7a8a68f5SJulian Pullen { 1196*7a8a68f5SJulian Pullen if (ctx->res_ninitted) 1197*7a8a68f5SJulian Pullen res_ndestroy(&ctx->res_state); 1198*7a8a68f5SJulian Pullen (void) memset(&ctx->res_state, 0, sizeof (ctx->res_state)); 1199*7a8a68f5SJulian Pullen ctx->res_ninitted = res_ninit(&ctx->res_state) != -1; 1200*7a8a68f5SJulian Pullen 1201*7a8a68f5SJulian Pullen if (ctx->domain_name.state == AD_STATE_AUTO) 1202*7a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 1203*7a8a68f5SJulian Pullen 1204*7a8a68f5SJulian Pullen if (ctx->domain_controller.state == AD_STATE_AUTO) 1205*7a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 1206*7a8a68f5SJulian Pullen 1207*7a8a68f5SJulian Pullen if (ctx->site_name.state == AD_STATE_AUTO) 1208*7a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 1209*7a8a68f5SJulian Pullen 1210*7a8a68f5SJulian Pullen if (ctx->forest_name.state == AD_STATE_AUTO) 1211*7a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 1212*7a8a68f5SJulian Pullen 1213*7a8a68f5SJulian Pullen if (ctx->global_catalog.state == AD_STATE_AUTO) 1214*7a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 1215*7a8a68f5SJulian Pullen 1216*7a8a68f5SJulian Pullen if (ctx->domains_in_forest.state == AD_STATE_AUTO) 1217*7a8a68f5SJulian Pullen ctx->domains_in_forest.state = AD_STATE_INVALID; 1218*7a8a68f5SJulian Pullen 1219*7a8a68f5SJulian Pullen if (ctx->trusted_domains.state == AD_STATE_AUTO) 1220*7a8a68f5SJulian Pullen ctx->trusted_domains.state = AD_STATE_INVALID; 1221*7a8a68f5SJulian Pullen 1222*7a8a68f5SJulian Pullen if (ctx->site_domain_controller.state == AD_STATE_AUTO) 1223*7a8a68f5SJulian Pullen ctx->site_domain_controller.state = AD_STATE_INVALID; 1224*7a8a68f5SJulian Pullen 1225*7a8a68f5SJulian Pullen if (ctx->site_global_catalog.state == AD_STATE_AUTO) 1226*7a8a68f5SJulian Pullen ctx->site_global_catalog.state = AD_STATE_INVALID; 1227*7a8a68f5SJulian Pullen } 1228*7a8a68f5SJulian Pullen 1229*7a8a68f5SJulian Pullen 1230*7a8a68f5SJulian Pullen 1231*7a8a68f5SJulian Pullen /* Discover joined Active Directory domainName */ 1232*7a8a68f5SJulian Pullen static ad_item_t * 1233*7a8a68f5SJulian Pullen validate_DomainName(ad_disc_t ctx) 1234*7a8a68f5SJulian Pullen { 1235*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 1236*7a8a68f5SJulian Pullen char *dname, *srvname; 1237*7a8a68f5SJulian Pullen uint32_t ttl = 0; 1238*7a8a68f5SJulian Pullen 1239*7a8a68f5SJulian Pullen if (is_valid(&ctx->domain_name)) 1240*7a8a68f5SJulian Pullen return (&ctx->domain_name); 1241*7a8a68f5SJulian Pullen 1242*7a8a68f5SJulian Pullen 1243*7a8a68f5SJulian Pullen /* Try to find our domain by searching for DCs for it */ 1244*7a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1245*7a8a68f5SJulian Pullen domain_controller = srv_query(&ctx->res_state, LDAP_SRV_HEAD 1246*7a8a68f5SJulian Pullen DC_SRV_TAIL, ctx->domain_name.value, &srvname, &ttl); 1247*7a8a68f5SJulian Pullen 1248*7a8a68f5SJulian Pullen /* 1249*7a8a68f5SJulian Pullen * If we can't find DCs by via res_nsearch() then there's no 1250*7a8a68f5SJulian Pullen * point in trying anything else to discover the AD domain name. 1251*7a8a68f5SJulian Pullen */ 1252*7a8a68f5SJulian Pullen if (domain_controller == NULL) 1253*7a8a68f5SJulian Pullen return (NULL); 1254*7a8a68f5SJulian Pullen 1255*7a8a68f5SJulian Pullen free(domain_controller); 1256*7a8a68f5SJulian Pullen /* 1257*7a8a68f5SJulian Pullen * We have the FQDN of the SRV RR name, so now we extract the 1258*7a8a68f5SJulian Pullen * domainname suffix from it. 1259*7a8a68f5SJulian Pullen */ 1260*7a8a68f5SJulian Pullen dname = strdup(srvname + strlen(LDAP_SRV_HEAD DC_SRV_TAIL) + 1261*7a8a68f5SJulian Pullen 1 /* for the dot between RR name and domainname */); 1262*7a8a68f5SJulian Pullen 1263*7a8a68f5SJulian Pullen free(srvname); 1264*7a8a68f5SJulian Pullen 1265*7a8a68f5SJulian Pullen if (dname == NULL) { 1266*7a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 1267*7a8a68f5SJulian Pullen return (NULL); 1268*7a8a68f5SJulian Pullen } 1269*7a8a68f5SJulian Pullen 1270*7a8a68f5SJulian Pullen /* Eat any trailing dot */ 1271*7a8a68f5SJulian Pullen if (*(dname + strlen(dname)) == '.') 1272*7a8a68f5SJulian Pullen *(dname + strlen(dname)) = '\0'; 1273*7a8a68f5SJulian Pullen 1274*7a8a68f5SJulian Pullen update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl); 1275*7a8a68f5SJulian Pullen 1276*7a8a68f5SJulian Pullen return (&ctx->domain_name); 1277*7a8a68f5SJulian Pullen } 1278*7a8a68f5SJulian Pullen 1279*7a8a68f5SJulian Pullen 1280*7a8a68f5SJulian Pullen char * 1281*7a8a68f5SJulian Pullen ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered) 1282*7a8a68f5SJulian Pullen { 1283*7a8a68f5SJulian Pullen char *domain_name = NULL; 1284*7a8a68f5SJulian Pullen ad_item_t *domain_name_item; 1285*7a8a68f5SJulian Pullen 1286*7a8a68f5SJulian Pullen domain_name_item = validate_DomainName(ctx); 1287*7a8a68f5SJulian Pullen 1288*7a8a68f5SJulian Pullen if (domain_name_item) { 1289*7a8a68f5SJulian Pullen domain_name = strdup(domain_name_item->value); 1290*7a8a68f5SJulian Pullen if (auto_discovered != NULL) 1291*7a8a68f5SJulian Pullen *auto_discovered = 1292*7a8a68f5SJulian Pullen (domain_name_item->state == AD_STATE_AUTO); 1293*7a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 1294*7a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1295*7a8a68f5SJulian Pullen 1296*7a8a68f5SJulian Pullen return (domain_name); 1297*7a8a68f5SJulian Pullen } 1298*7a8a68f5SJulian Pullen 1299*7a8a68f5SJulian Pullen 1300*7a8a68f5SJulian Pullen /* Discover domain controllers */ 1301*7a8a68f5SJulian Pullen static ad_item_t * 1302*7a8a68f5SJulian Pullen validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) 1303*7a8a68f5SJulian Pullen { 1304*7a8a68f5SJulian Pullen uint32_t ttl = 0; 1305*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 1306*7a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 1307*7a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 1308*7a8a68f5SJulian Pullen ad_item_t *domain_name_item; 1309*7a8a68f5SJulian Pullen ad_item_t *site_name_item = NULL; 1310*7a8a68f5SJulian Pullen 1311*7a8a68f5SJulian Pullen /* If the values is fixed there will not be a site specific version */ 1312*7a8a68f5SJulian Pullen if (is_fixed(&ctx->domain_controller)) 1313*7a8a68f5SJulian Pullen return (&ctx->domain_controller); 1314*7a8a68f5SJulian Pullen 1315*7a8a68f5SJulian Pullen domain_name_item = validate_DomainName(ctx); 1316*7a8a68f5SJulian Pullen if (domain_name_item == NULL) 1317*7a8a68f5SJulian Pullen return (NULL); 1318*7a8a68f5SJulian Pullen 1319*7a8a68f5SJulian Pullen if (req == AD_DISC_GLOBAL) 1320*7a8a68f5SJulian Pullen validate_global = B_TRUE; 1321*7a8a68f5SJulian Pullen else { 1322*7a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 1323*7a8a68f5SJulian Pullen if (site_name_item != NULL) 1324*7a8a68f5SJulian Pullen validate_site = B_TRUE; 1325*7a8a68f5SJulian Pullen else if (req == AD_DISC_PREFER_SITE) 1326*7a8a68f5SJulian Pullen validate_global = B_TRUE; 1327*7a8a68f5SJulian Pullen } 1328*7a8a68f5SJulian Pullen 1329*7a8a68f5SJulian Pullen if (validate_global) { 1330*7a8a68f5SJulian Pullen if (!is_valid(&ctx->domain_controller) || 1331*7a8a68f5SJulian Pullen is_changed(&ctx->domain_controller, PARAM1, 1332*7a8a68f5SJulian Pullen domain_name_item)) { 1333*7a8a68f5SJulian Pullen /* 1334*7a8a68f5SJulian Pullen * Lookup DNS SRV RR named 1335*7a8a68f5SJulian Pullen * _ldap._tcp.dc._msdcs.<DomainName> 1336*7a8a68f5SJulian Pullen */ 1337*7a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1338*7a8a68f5SJulian Pullen domain_controller = srv_query(&ctx->res_state, 1339*7a8a68f5SJulian Pullen LDAP_SRV_HEAD DC_SRV_TAIL, 1340*7a8a68f5SJulian Pullen domain_name_item->value, NULL, &ttl); 1341*7a8a68f5SJulian Pullen 1342*7a8a68f5SJulian Pullen if (domain_controller == NULL) 1343*7a8a68f5SJulian Pullen return (NULL); 1344*7a8a68f5SJulian Pullen 1345*7a8a68f5SJulian Pullen update_item(&ctx->domain_controller, domain_controller, 1346*7a8a68f5SJulian Pullen AD_STATE_AUTO, ttl); 1347*7a8a68f5SJulian Pullen update_version(&ctx->domain_controller, PARAM1, 1348*7a8a68f5SJulian Pullen domain_name_item); 1349*7a8a68f5SJulian Pullen } 1350*7a8a68f5SJulian Pullen return (&ctx->domain_controller); 1351*7a8a68f5SJulian Pullen } 1352*7a8a68f5SJulian Pullen 1353*7a8a68f5SJulian Pullen if (validate_site) { 1354*7a8a68f5SJulian Pullen if (!is_valid(&ctx->site_domain_controller) || 1355*7a8a68f5SJulian Pullen is_changed(&ctx->site_domain_controller, PARAM1, 1356*7a8a68f5SJulian Pullen domain_name_item) || 1357*7a8a68f5SJulian Pullen is_changed(&ctx->site_domain_controller, PARAM2, 1358*7a8a68f5SJulian Pullen site_name_item)) { 1359*7a8a68f5SJulian Pullen char rr_name[DNS_MAX_NAME]; 1360*7a8a68f5SJulian Pullen /* 1361*7a8a68f5SJulian Pullen * Lookup DNS SRV RR named 1362*7a8a68f5SJulian Pullen * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName> 1363*7a8a68f5SJulian Pullen */ 1364*7a8a68f5SJulian Pullen (void) snprintf(rr_name, sizeof (rr_name), 1365*7a8a68f5SJulian Pullen LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, 1366*7a8a68f5SJulian Pullen site_name_item->value); 1367*7a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1368*7a8a68f5SJulian Pullen domain_controller = srv_query(&ctx->res_state, rr_name, 1369*7a8a68f5SJulian Pullen domain_name_item->value, NULL, &ttl); 1370*7a8a68f5SJulian Pullen if (domain_controller == NULL) 1371*7a8a68f5SJulian Pullen return (NULL); 1372*7a8a68f5SJulian Pullen 1373*7a8a68f5SJulian Pullen update_item(&ctx->site_domain_controller, 1374*7a8a68f5SJulian Pullen domain_controller, AD_STATE_AUTO, ttl); 1375*7a8a68f5SJulian Pullen update_version(&ctx->site_domain_controller, PARAM1, 1376*7a8a68f5SJulian Pullen domain_name_item); 1377*7a8a68f5SJulian Pullen update_version(&ctx->site_domain_controller, PARAM2, 1378*7a8a68f5SJulian Pullen site_name_item); 1379*7a8a68f5SJulian Pullen } 1380*7a8a68f5SJulian Pullen return (&ctx->site_domain_controller); 1381*7a8a68f5SJulian Pullen } 1382*7a8a68f5SJulian Pullen return (NULL); 1383*7a8a68f5SJulian Pullen } 1384*7a8a68f5SJulian Pullen 1385*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t * 1386*7a8a68f5SJulian Pullen ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, 1387*7a8a68f5SJulian Pullen boolean_t *auto_discovered) 1388*7a8a68f5SJulian Pullen { 1389*7a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 1390*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 1391*7a8a68f5SJulian Pullen 1392*7a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, req); 1393*7a8a68f5SJulian Pullen 1394*7a8a68f5SJulian Pullen if (domain_controller_item != NULL) { 1395*7a8a68f5SJulian Pullen domain_controller = ds_dup(domain_controller_item->value); 1396*7a8a68f5SJulian Pullen if (auto_discovered != NULL) 1397*7a8a68f5SJulian Pullen *auto_discovered = 1398*7a8a68f5SJulian Pullen (domain_controller_item->state == AD_STATE_AUTO); 1399*7a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 1400*7a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1401*7a8a68f5SJulian Pullen 1402*7a8a68f5SJulian Pullen return (domain_controller); 1403*7a8a68f5SJulian Pullen } 1404*7a8a68f5SJulian Pullen 1405*7a8a68f5SJulian Pullen 1406*7a8a68f5SJulian Pullen /* Discover site name (for multi-homed systems the first one found wins) */ 1407*7a8a68f5SJulian Pullen static ad_item_t * 1408*7a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx) 1409*7a8a68f5SJulian Pullen { 1410*7a8a68f5SJulian Pullen LDAP *ld = NULL; 1411*7a8a68f5SJulian Pullen ad_subnet_t *subnets = NULL; 1412*7a8a68f5SJulian Pullen char **dn_subnets = NULL; 1413*7a8a68f5SJulian Pullen char *dn_root[2]; 1414*7a8a68f5SJulian Pullen char *config_naming_context = NULL; 1415*7a8a68f5SJulian Pullen char *site_object = NULL; 1416*7a8a68f5SJulian Pullen char *site_name = NULL; 1417*7a8a68f5SJulian Pullen char *forest_name; 1418*7a8a68f5SJulian Pullen int len; 1419*7a8a68f5SJulian Pullen int i; 1420*7a8a68f5SJulian Pullen boolean_t update_required = B_FALSE; 1421*7a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 1422*7a8a68f5SJulian Pullen 1423*7a8a68f5SJulian Pullen if (is_fixed(&ctx->site_name)) 1424*7a8a68f5SJulian Pullen return (&ctx->site_name); 1425*7a8a68f5SJulian Pullen 1426*7a8a68f5SJulian Pullen /* Can't rely on site-specific DCs */ 1427*7a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1428*7a8a68f5SJulian Pullen if (domain_controller_item == NULL) 1429*7a8a68f5SJulian Pullen return (NULL); 1430*7a8a68f5SJulian Pullen 1431*7a8a68f5SJulian Pullen if (!is_valid(&ctx->site_name) || 1432*7a8a68f5SJulian Pullen is_changed(&ctx->site_name, PARAM1, &ctx->domain_controller) || 1433*7a8a68f5SJulian Pullen ctx->subnets == NULL || ctx->subnets_changed) { 1434*7a8a68f5SJulian Pullen subnets = find_subnets(); 1435*7a8a68f5SJulian Pullen ctx->subnets_last_check = time(NULL); 1436*7a8a68f5SJulian Pullen update_required = B_TRUE; 1437*7a8a68f5SJulian Pullen } else if (ctx->subnets_last_check + 60 < time(NULL)) { 1438*7a8a68f5SJulian Pullen subnets = find_subnets(); 1439*7a8a68f5SJulian Pullen ctx->subnets_last_check = time(NULL); 1440*7a8a68f5SJulian Pullen if (cmpsubnets(ctx->subnets, subnets) != 0) 1441*7a8a68f5SJulian Pullen update_required = B_TRUE; 1442*7a8a68f5SJulian Pullen } 1443*7a8a68f5SJulian Pullen 1444*7a8a68f5SJulian Pullen if (!update_required) { 1445*7a8a68f5SJulian Pullen free(subnets); 1446*7a8a68f5SJulian Pullen return (&ctx->site_name); 1447*7a8a68f5SJulian Pullen } 1448*7a8a68f5SJulian Pullen 1449*7a8a68f5SJulian Pullen if (subnets == NULL) 1450*7a8a68f5SJulian Pullen return (NULL); 1451*7a8a68f5SJulian Pullen 1452*7a8a68f5SJulian Pullen dn_root[0] = ""; 1453*7a8a68f5SJulian Pullen dn_root[1] = NULL; 1454*7a8a68f5SJulian Pullen 1455*7a8a68f5SJulian Pullen config_naming_context = ldap_lookup_entry_attr( 1456*7a8a68f5SJulian Pullen &ld, ctx->domain_controller.value, 1457*7a8a68f5SJulian Pullen dn_root, "configurationNamingContext"); 1458*7a8a68f5SJulian Pullen if (config_naming_context == NULL) 1459*7a8a68f5SJulian Pullen goto out; 1460*7a8a68f5SJulian Pullen /* 1461*7a8a68f5SJulian Pullen * configurationNamingContext also provides the Forest 1462*7a8a68f5SJulian Pullen * Name. 1463*7a8a68f5SJulian Pullen */ 1464*7a8a68f5SJulian Pullen if (!is_fixed(&ctx->forest_name)) { 1465*7a8a68f5SJulian Pullen /* 1466*7a8a68f5SJulian Pullen * The configurationNamingContext should be of 1467*7a8a68f5SJulian Pullen * form: 1468*7a8a68f5SJulian Pullen * CN=Configuration,<DNforestName> 1469*7a8a68f5SJulian Pullen * Remove the first part and convert to DNS form 1470*7a8a68f5SJulian Pullen * (replace ",DC=" with ".") 1471*7a8a68f5SJulian Pullen */ 1472*7a8a68f5SJulian Pullen char *str = "CN=Configuration,"; 1473*7a8a68f5SJulian Pullen int len = strlen(str); 1474*7a8a68f5SJulian Pullen if (strncasecmp(config_naming_context, str, len) == 0) { 1475*7a8a68f5SJulian Pullen forest_name = DN_to_DNS(config_naming_context + len); 1476*7a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, 1477*7a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 1478*7a8a68f5SJulian Pullen } 1479*7a8a68f5SJulian Pullen } 1480*7a8a68f5SJulian Pullen 1481*7a8a68f5SJulian Pullen dn_subnets = subnets_to_DNs(subnets, config_naming_context); 1482*7a8a68f5SJulian Pullen if (dn_subnets == NULL) 1483*7a8a68f5SJulian Pullen goto out; 1484*7a8a68f5SJulian Pullen 1485*7a8a68f5SJulian Pullen site_object = ldap_lookup_entry_attr( 1486*7a8a68f5SJulian Pullen &ld, domain_controller_item->value, 1487*7a8a68f5SJulian Pullen dn_subnets, "siteobject"); 1488*7a8a68f5SJulian Pullen if (site_object != NULL) { 1489*7a8a68f5SJulian Pullen /* 1490*7a8a68f5SJulian Pullen * The site object should be of the form 1491*7a8a68f5SJulian Pullen * CN=<site>,CN=Sites,CN=Configuration, 1492*7a8a68f5SJulian Pullen * <DN Domain> 1493*7a8a68f5SJulian Pullen */ 1494*7a8a68f5SJulian Pullen if (strncasecmp(site_object, "CN=", 3) == 0) { 1495*7a8a68f5SJulian Pullen for (len = 0; site_object[len + 3] != ','; len++) 1496*7a8a68f5SJulian Pullen ; 1497*7a8a68f5SJulian Pullen site_name = malloc(len + 1); 1498*7a8a68f5SJulian Pullen (void) strncpy(site_name, &site_object[3], len); 1499*7a8a68f5SJulian Pullen site_name[len] = '\0'; 1500*7a8a68f5SJulian Pullen update_item(&ctx->site_name, site_name, 1501*7a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 1502*7a8a68f5SJulian Pullen } 1503*7a8a68f5SJulian Pullen } 1504*7a8a68f5SJulian Pullen 1505*7a8a68f5SJulian Pullen if (ctx->subnets != NULL) { 1506*7a8a68f5SJulian Pullen free(ctx->subnets); 1507*7a8a68f5SJulian Pullen ctx->subnets = NULL; 1508*7a8a68f5SJulian Pullen } 1509*7a8a68f5SJulian Pullen ctx->subnets = subnets; 1510*7a8a68f5SJulian Pullen subnets = NULL; 1511*7a8a68f5SJulian Pullen ctx->subnets_changed = B_FALSE; 1512*7a8a68f5SJulian Pullen 1513*7a8a68f5SJulian Pullen out: 1514*7a8a68f5SJulian Pullen if (ld != NULL) 1515*7a8a68f5SJulian Pullen (void) ldap_unbind(ld); 1516*7a8a68f5SJulian Pullen 1517*7a8a68f5SJulian Pullen if (dn_subnets != NULL) { 1518*7a8a68f5SJulian Pullen for (i = 0; dn_subnets[i] != NULL; i++) 1519*7a8a68f5SJulian Pullen free(dn_subnets[i]); 1520*7a8a68f5SJulian Pullen free(dn_subnets); 1521*7a8a68f5SJulian Pullen } 1522*7a8a68f5SJulian Pullen if (config_naming_context != NULL) 1523*7a8a68f5SJulian Pullen free(config_naming_context); 1524*7a8a68f5SJulian Pullen if (site_object != NULL) 1525*7a8a68f5SJulian Pullen free(site_object); 1526*7a8a68f5SJulian Pullen 1527*7a8a68f5SJulian Pullen free(subnets); 1528*7a8a68f5SJulian Pullen if (site_name == NULL) 1529*7a8a68f5SJulian Pullen return (NULL); 1530*7a8a68f5SJulian Pullen return (&ctx->site_name); 1531*7a8a68f5SJulian Pullen 1532*7a8a68f5SJulian Pullen } 1533*7a8a68f5SJulian Pullen 1534*7a8a68f5SJulian Pullen 1535*7a8a68f5SJulian Pullen char * 1536*7a8a68f5SJulian Pullen ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered) 1537*7a8a68f5SJulian Pullen { 1538*7a8a68f5SJulian Pullen ad_item_t *site_name_item; 1539*7a8a68f5SJulian Pullen char *site_name = NULL; 1540*7a8a68f5SJulian Pullen 1541*7a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 1542*7a8a68f5SJulian Pullen if (site_name_item != NULL) { 1543*7a8a68f5SJulian Pullen site_name = strdup(site_name_item->value); 1544*7a8a68f5SJulian Pullen if (auto_discovered != NULL) 1545*7a8a68f5SJulian Pullen *auto_discovered = 1546*7a8a68f5SJulian Pullen (site_name_item->state == AD_STATE_AUTO); 1547*7a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 1548*7a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1549*7a8a68f5SJulian Pullen 1550*7a8a68f5SJulian Pullen return (site_name); 1551*7a8a68f5SJulian Pullen } 1552*7a8a68f5SJulian Pullen 1553*7a8a68f5SJulian Pullen 1554*7a8a68f5SJulian Pullen 1555*7a8a68f5SJulian Pullen /* Discover forest name */ 1556*7a8a68f5SJulian Pullen static ad_item_t * 1557*7a8a68f5SJulian Pullen validate_ForestName(ad_disc_t ctx) 1558*7a8a68f5SJulian Pullen { 1559*7a8a68f5SJulian Pullen LDAP *ld = NULL; 1560*7a8a68f5SJulian Pullen char *config_naming_context; 1561*7a8a68f5SJulian Pullen char *forest_name = NULL; 1562*7a8a68f5SJulian Pullen char *dn_list[2]; 1563*7a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 1564*7a8a68f5SJulian Pullen 1565*7a8a68f5SJulian Pullen if (is_fixed(&ctx->forest_name)) 1566*7a8a68f5SJulian Pullen return (&ctx->forest_name); 1567*7a8a68f5SJulian Pullen /* 1568*7a8a68f5SJulian Pullen * We may not have a site name yet, so we won't rely on 1569*7a8a68f5SJulian Pullen * site-specific DCs. (But maybe we could replace 1570*7a8a68f5SJulian Pullen * validate_ForestName() with validate_siteName()?) 1571*7a8a68f5SJulian Pullen */ 1572*7a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1573*7a8a68f5SJulian Pullen if (domain_controller_item == NULL) 1574*7a8a68f5SJulian Pullen return (NULL); 1575*7a8a68f5SJulian Pullen 1576*7a8a68f5SJulian Pullen if (!is_valid(&ctx->forest_name) || 1577*7a8a68f5SJulian Pullen is_changed(&ctx->forest_name, PARAM1, domain_controller_item)) { 1578*7a8a68f5SJulian Pullen 1579*7a8a68f5SJulian Pullen dn_list[0] = ""; 1580*7a8a68f5SJulian Pullen dn_list[1] = NULL; 1581*7a8a68f5SJulian Pullen config_naming_context = ldap_lookup_entry_attr( 1582*7a8a68f5SJulian Pullen &ld, ctx->domain_controller.value, 1583*7a8a68f5SJulian Pullen dn_list, "configurationNamingContext"); 1584*7a8a68f5SJulian Pullen if (config_naming_context != NULL) { 1585*7a8a68f5SJulian Pullen /* 1586*7a8a68f5SJulian Pullen * The configurationNamingContext should be of 1587*7a8a68f5SJulian Pullen * form: 1588*7a8a68f5SJulian Pullen * CN=Configuration,<DNforestName> 1589*7a8a68f5SJulian Pullen * Remove the first part and convert to DNS form 1590*7a8a68f5SJulian Pullen * (replace ",DC=" with ".") 1591*7a8a68f5SJulian Pullen */ 1592*7a8a68f5SJulian Pullen char *str = "CN=Configuration,"; 1593*7a8a68f5SJulian Pullen int len = strlen(str); 1594*7a8a68f5SJulian Pullen if (strncasecmp(config_naming_context, str, len) == 0) { 1595*7a8a68f5SJulian Pullen forest_name = DN_to_DNS( 1596*7a8a68f5SJulian Pullen config_naming_context + len); 1597*7a8a68f5SJulian Pullen } 1598*7a8a68f5SJulian Pullen free(config_naming_context); 1599*7a8a68f5SJulian Pullen } 1600*7a8a68f5SJulian Pullen if (ld != NULL) 1601*7a8a68f5SJulian Pullen (void) ldap_unbind(ld); 1602*7a8a68f5SJulian Pullen 1603*7a8a68f5SJulian Pullen if (forest_name == NULL) 1604*7a8a68f5SJulian Pullen return (NULL); 1605*7a8a68f5SJulian Pullen 1606*7a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); 1607*7a8a68f5SJulian Pullen update_version(&ctx->forest_name, PARAM1, 1608*7a8a68f5SJulian Pullen domain_controller_item); 1609*7a8a68f5SJulian Pullen } 1610*7a8a68f5SJulian Pullen return (&ctx->forest_name); 1611*7a8a68f5SJulian Pullen } 1612*7a8a68f5SJulian Pullen 1613*7a8a68f5SJulian Pullen 1614*7a8a68f5SJulian Pullen char * 1615*7a8a68f5SJulian Pullen ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered) 1616*7a8a68f5SJulian Pullen { 1617*7a8a68f5SJulian Pullen ad_item_t *forest_name_item; 1618*7a8a68f5SJulian Pullen char *forest_name = NULL; 1619*7a8a68f5SJulian Pullen 1620*7a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 1621*7a8a68f5SJulian Pullen 1622*7a8a68f5SJulian Pullen if (forest_name_item != NULL) { 1623*7a8a68f5SJulian Pullen forest_name = strdup(forest_name_item->value); 1624*7a8a68f5SJulian Pullen if (auto_discovered != NULL) 1625*7a8a68f5SJulian Pullen *auto_discovered = 1626*7a8a68f5SJulian Pullen (forest_name_item->state == AD_STATE_AUTO); 1627*7a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 1628*7a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1629*7a8a68f5SJulian Pullen 1630*7a8a68f5SJulian Pullen return (forest_name); 1631*7a8a68f5SJulian Pullen } 1632*7a8a68f5SJulian Pullen 1633*7a8a68f5SJulian Pullen 1634*7a8a68f5SJulian Pullen /* Discover global catalog servers */ 1635*7a8a68f5SJulian Pullen static ad_item_t * 1636*7a8a68f5SJulian Pullen validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) 1637*7a8a68f5SJulian Pullen { 1638*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *global_catalog = NULL; 1639*7a8a68f5SJulian Pullen uint32_t ttl = 0; 1640*7a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 1641*7a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 1642*7a8a68f5SJulian Pullen ad_item_t *forest_name_item; 1643*7a8a68f5SJulian Pullen ad_item_t *site_name_item; 1644*7a8a68f5SJulian Pullen 1645*7a8a68f5SJulian Pullen /* If the values is fixed there will not be a site specific version */ 1646*7a8a68f5SJulian Pullen if (is_fixed(&ctx->global_catalog)) 1647*7a8a68f5SJulian Pullen return (&ctx->global_catalog); 1648*7a8a68f5SJulian Pullen 1649*7a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 1650*7a8a68f5SJulian Pullen if (forest_name_item == NULL) 1651*7a8a68f5SJulian Pullen return (NULL); 1652*7a8a68f5SJulian Pullen 1653*7a8a68f5SJulian Pullen if (req == AD_DISC_GLOBAL) 1654*7a8a68f5SJulian Pullen validate_global = B_TRUE; 1655*7a8a68f5SJulian Pullen else { 1656*7a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 1657*7a8a68f5SJulian Pullen if (site_name_item != NULL) 1658*7a8a68f5SJulian Pullen validate_site = B_TRUE; 1659*7a8a68f5SJulian Pullen else if (req == AD_DISC_PREFER_SITE) 1660*7a8a68f5SJulian Pullen validate_global = B_TRUE; 1661*7a8a68f5SJulian Pullen } 1662*7a8a68f5SJulian Pullen 1663*7a8a68f5SJulian Pullen if (validate_global) { 1664*7a8a68f5SJulian Pullen if (!is_valid(&ctx->global_catalog) || 1665*7a8a68f5SJulian Pullen is_changed(&ctx->global_catalog, PARAM1, 1666*7a8a68f5SJulian Pullen forest_name_item)) { 1667*7a8a68f5SJulian Pullen /* 1668*7a8a68f5SJulian Pullen * Lookup DNS SRV RR named 1669*7a8a68f5SJulian Pullen * _ldap._tcp.gc._msdcs.<ForestName> 1670*7a8a68f5SJulian Pullen */ 1671*7a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1672*7a8a68f5SJulian Pullen global_catalog = 1673*7a8a68f5SJulian Pullen srv_query(&ctx->res_state, 1674*7a8a68f5SJulian Pullen LDAP_SRV_HEAD GC_SRV_TAIL, 1675*7a8a68f5SJulian Pullen ctx->forest_name.value, NULL, &ttl); 1676*7a8a68f5SJulian Pullen 1677*7a8a68f5SJulian Pullen if (global_catalog == NULL) 1678*7a8a68f5SJulian Pullen return (NULL); 1679*7a8a68f5SJulian Pullen 1680*7a8a68f5SJulian Pullen update_item(&ctx->global_catalog, global_catalog, 1681*7a8a68f5SJulian Pullen AD_STATE_AUTO, ttl); 1682*7a8a68f5SJulian Pullen update_version(&ctx->global_catalog, PARAM1, 1683*7a8a68f5SJulian Pullen forest_name_item); 1684*7a8a68f5SJulian Pullen } 1685*7a8a68f5SJulian Pullen return (&ctx->global_catalog); 1686*7a8a68f5SJulian Pullen } 1687*7a8a68f5SJulian Pullen 1688*7a8a68f5SJulian Pullen if (validate_site) { 1689*7a8a68f5SJulian Pullen if (!is_valid(&ctx->site_global_catalog) || 1690*7a8a68f5SJulian Pullen is_changed(&ctx->site_global_catalog, PARAM1, 1691*7a8a68f5SJulian Pullen forest_name_item) || 1692*7a8a68f5SJulian Pullen is_changed(&ctx->site_global_catalog, PARAM2, 1693*7a8a68f5SJulian Pullen site_name_item)) { 1694*7a8a68f5SJulian Pullen char rr_name[DNS_MAX_NAME]; 1695*7a8a68f5SJulian Pullen 1696*7a8a68f5SJulian Pullen /* 1697*7a8a68f5SJulian Pullen * Lookup DNS SRV RR named: 1698*7a8a68f5SJulian Pullen * _ldap._tcp.<siteName>._sites.gc. 1699*7a8a68f5SJulian Pullen * _msdcs.<ForestName> 1700*7a8a68f5SJulian Pullen */ 1701*7a8a68f5SJulian Pullen (void) snprintf(rr_name, 1702*7a8a68f5SJulian Pullen sizeof (rr_name), 1703*7a8a68f5SJulian Pullen LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, 1704*7a8a68f5SJulian Pullen ctx->site_name.value); 1705*7a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1706*7a8a68f5SJulian Pullen global_catalog = srv_query(&ctx->res_state, rr_name, 1707*7a8a68f5SJulian Pullen ctx->forest_name.value, NULL, &ttl); 1708*7a8a68f5SJulian Pullen 1709*7a8a68f5SJulian Pullen if (global_catalog == NULL) 1710*7a8a68f5SJulian Pullen return (NULL); 1711*7a8a68f5SJulian Pullen update_item(&ctx->site_global_catalog, global_catalog, 1712*7a8a68f5SJulian Pullen AD_STATE_AUTO, ttl); 1713*7a8a68f5SJulian Pullen update_version(&ctx->site_global_catalog, PARAM1, 1714*7a8a68f5SJulian Pullen forest_name_item); 1715*7a8a68f5SJulian Pullen update_version(&ctx->site_global_catalog, PARAM2, 1716*7a8a68f5SJulian Pullen site_name_item); 1717*7a8a68f5SJulian Pullen } 1718*7a8a68f5SJulian Pullen return (&ctx->site_global_catalog); 1719*7a8a68f5SJulian Pullen } 1720*7a8a68f5SJulian Pullen return (NULL); 1721*7a8a68f5SJulian Pullen } 1722*7a8a68f5SJulian Pullen 1723*7a8a68f5SJulian Pullen 1724*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t * 1725*7a8a68f5SJulian Pullen ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, 1726*7a8a68f5SJulian Pullen boolean_t *auto_discovered) 1727*7a8a68f5SJulian Pullen { 1728*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *global_catalog = NULL; 1729*7a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 1730*7a8a68f5SJulian Pullen 1731*7a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, req); 1732*7a8a68f5SJulian Pullen 1733*7a8a68f5SJulian Pullen if (global_catalog_item != NULL) { 1734*7a8a68f5SJulian Pullen global_catalog = ds_dup(global_catalog_item->value); 1735*7a8a68f5SJulian Pullen if (auto_discovered != NULL) 1736*7a8a68f5SJulian Pullen *auto_discovered = 1737*7a8a68f5SJulian Pullen (global_catalog_item->state == AD_STATE_AUTO); 1738*7a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 1739*7a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1740*7a8a68f5SJulian Pullen 1741*7a8a68f5SJulian Pullen return (global_catalog); 1742*7a8a68f5SJulian Pullen } 1743*7a8a68f5SJulian Pullen 1744*7a8a68f5SJulian Pullen 1745*7a8a68f5SJulian Pullen static ad_item_t * 1746*7a8a68f5SJulian Pullen validate_TrustedDomains(ad_disc_t ctx) 1747*7a8a68f5SJulian Pullen { 1748*7a8a68f5SJulian Pullen LDAP *ld = NULL; 1749*7a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 1750*7a8a68f5SJulian Pullen ad_item_t *forest_name_item; 1751*7a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains; 1752*7a8a68f5SJulian Pullen char *dn = NULL; 1753*7a8a68f5SJulian Pullen char *forest_name_dn; 1754*7a8a68f5SJulian Pullen int len; 1755*7a8a68f5SJulian Pullen int num_parts; 1756*7a8a68f5SJulian Pullen 1757*7a8a68f5SJulian Pullen if (is_fixed(&ctx->trusted_domains)) 1758*7a8a68f5SJulian Pullen return (&ctx->trusted_domains); 1759*7a8a68f5SJulian Pullen 1760*7a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 1761*7a8a68f5SJulian Pullen if (global_catalog_item == NULL) 1762*7a8a68f5SJulian Pullen return (NULL); 1763*7a8a68f5SJulian Pullen 1764*7a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 1765*7a8a68f5SJulian Pullen if (forest_name_item == NULL) 1766*7a8a68f5SJulian Pullen return (NULL); 1767*7a8a68f5SJulian Pullen 1768*7a8a68f5SJulian Pullen if (!is_valid(&ctx->trusted_domains) || 1769*7a8a68f5SJulian Pullen is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) || 1770*7a8a68f5SJulian Pullen is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) { 1771*7a8a68f5SJulian Pullen 1772*7a8a68f5SJulian Pullen forest_name_dn = ldap_dns_to_dn(forest_name_item->value, 1773*7a8a68f5SJulian Pullen &num_parts); 1774*7a8a68f5SJulian Pullen if (forest_name_dn == NULL) 1775*7a8a68f5SJulian Pullen return (NULL); 1776*7a8a68f5SJulian Pullen 1777*7a8a68f5SJulian Pullen len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1; 1778*7a8a68f5SJulian Pullen dn = malloc(len); 1779*7a8a68f5SJulian Pullen if (dn == NULL) { 1780*7a8a68f5SJulian Pullen free(forest_name_dn); 1781*7a8a68f5SJulian Pullen return (NULL); 1782*7a8a68f5SJulian Pullen } 1783*7a8a68f5SJulian Pullen (void) snprintf(dn, len, "CN=System,%s", forest_name_dn); 1784*7a8a68f5SJulian Pullen free(forest_name_dn); 1785*7a8a68f5SJulian Pullen 1786*7a8a68f5SJulian Pullen trusted_domains = ldap_lookup_trusted_domains( 1787*7a8a68f5SJulian Pullen &ld, global_catalog_item->value, dn); 1788*7a8a68f5SJulian Pullen 1789*7a8a68f5SJulian Pullen if (ld != NULL) 1790*7a8a68f5SJulian Pullen (void) ldap_unbind(ld); 1791*7a8a68f5SJulian Pullen free(dn); 1792*7a8a68f5SJulian Pullen 1793*7a8a68f5SJulian Pullen if (trusted_domains == NULL) 1794*7a8a68f5SJulian Pullen return (NULL); 1795*7a8a68f5SJulian Pullen 1796*7a8a68f5SJulian Pullen update_item(&ctx->trusted_domains, trusted_domains, 1797*7a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 1798*7a8a68f5SJulian Pullen update_version(&ctx->trusted_domains, PARAM1, 1799*7a8a68f5SJulian Pullen global_catalog_item); 1800*7a8a68f5SJulian Pullen update_version(&ctx->trusted_domains, PARAM2, 1801*7a8a68f5SJulian Pullen forest_name_item); 1802*7a8a68f5SJulian Pullen } 1803*7a8a68f5SJulian Pullen 1804*7a8a68f5SJulian Pullen return (&ctx->trusted_domains); 1805*7a8a68f5SJulian Pullen } 1806*7a8a68f5SJulian Pullen 1807*7a8a68f5SJulian Pullen 1808*7a8a68f5SJulian Pullen ad_disc_trusteddomains_t * 1809*7a8a68f5SJulian Pullen ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered) 1810*7a8a68f5SJulian Pullen { 1811*7a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 1812*7a8a68f5SJulian Pullen ad_item_t *trusted_domains_item; 1813*7a8a68f5SJulian Pullen 1814*7a8a68f5SJulian Pullen trusted_domains_item = validate_TrustedDomains(ctx); 1815*7a8a68f5SJulian Pullen 1816*7a8a68f5SJulian Pullen if (trusted_domains_item != NULL) { 1817*7a8a68f5SJulian Pullen trusted_domains = td_dup(trusted_domains_item->value); 1818*7a8a68f5SJulian Pullen if (auto_discovered != NULL) 1819*7a8a68f5SJulian Pullen *auto_discovered = 1820*7a8a68f5SJulian Pullen (trusted_domains_item->state == AD_STATE_AUTO); 1821*7a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 1822*7a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1823*7a8a68f5SJulian Pullen 1824*7a8a68f5SJulian Pullen return (trusted_domains); 1825*7a8a68f5SJulian Pullen } 1826*7a8a68f5SJulian Pullen 1827*7a8a68f5SJulian Pullen 1828*7a8a68f5SJulian Pullen static ad_item_t * 1829*7a8a68f5SJulian Pullen validate_DomainsInForest(ad_disc_t ctx) 1830*7a8a68f5SJulian Pullen { 1831*7a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 1832*7a8a68f5SJulian Pullen LDAP *ld = NULL; 1833*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest; 1834*7a8a68f5SJulian Pullen 1835*7a8a68f5SJulian Pullen if (is_fixed(&ctx->domains_in_forest)) 1836*7a8a68f5SJulian Pullen return (&ctx->domains_in_forest); 1837*7a8a68f5SJulian Pullen 1838*7a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 1839*7a8a68f5SJulian Pullen if (global_catalog_item == NULL) 1840*7a8a68f5SJulian Pullen return (NULL); 1841*7a8a68f5SJulian Pullen 1842*7a8a68f5SJulian Pullen if (!is_valid(&ctx->domains_in_forest) || 1843*7a8a68f5SJulian Pullen is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) { 1844*7a8a68f5SJulian Pullen 1845*7a8a68f5SJulian Pullen domains_in_forest = ldap_lookup_domains_in_forest( 1846*7a8a68f5SJulian Pullen &ld, global_catalog_item->value); 1847*7a8a68f5SJulian Pullen 1848*7a8a68f5SJulian Pullen if (ld != NULL) 1849*7a8a68f5SJulian Pullen (void) ldap_unbind(ld); 1850*7a8a68f5SJulian Pullen 1851*7a8a68f5SJulian Pullen if (domains_in_forest == NULL) 1852*7a8a68f5SJulian Pullen return (NULL); 1853*7a8a68f5SJulian Pullen 1854*7a8a68f5SJulian Pullen update_item(&ctx->domains_in_forest, domains_in_forest, 1855*7a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 1856*7a8a68f5SJulian Pullen update_version(&ctx->domains_in_forest, PARAM1, 1857*7a8a68f5SJulian Pullen global_catalog_item); 1858*7a8a68f5SJulian Pullen } 1859*7a8a68f5SJulian Pullen return (&ctx->domains_in_forest); 1860*7a8a68f5SJulian Pullen } 1861*7a8a68f5SJulian Pullen 1862*7a8a68f5SJulian Pullen 1863*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t * 1864*7a8a68f5SJulian Pullen ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered) 1865*7a8a68f5SJulian Pullen { 1866*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest = NULL; 1867*7a8a68f5SJulian Pullen ad_item_t *domains_in_forest_item; 1868*7a8a68f5SJulian Pullen 1869*7a8a68f5SJulian Pullen domains_in_forest_item = validate_DomainsInForest(ctx); 1870*7a8a68f5SJulian Pullen 1871*7a8a68f5SJulian Pullen if (domains_in_forest_item != NULL) { 1872*7a8a68f5SJulian Pullen domains_in_forest = df_dup(domains_in_forest_item->value); 1873*7a8a68f5SJulian Pullen if (auto_discovered != NULL) 1874*7a8a68f5SJulian Pullen *auto_discovered = 1875*7a8a68f5SJulian Pullen (domains_in_forest_item->state == AD_STATE_AUTO); 1876*7a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 1877*7a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 1878*7a8a68f5SJulian Pullen 1879*7a8a68f5SJulian Pullen return (domains_in_forest); 1880*7a8a68f5SJulian Pullen } 1881*7a8a68f5SJulian Pullen 1882*7a8a68f5SJulian Pullen 1883*7a8a68f5SJulian Pullen 1884*7a8a68f5SJulian Pullen 1885*7a8a68f5SJulian Pullen int 1886*7a8a68f5SJulian Pullen ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) 1887*7a8a68f5SJulian Pullen { 1888*7a8a68f5SJulian Pullen char *domain_name = NULL; 1889*7a8a68f5SJulian Pullen if (domainName != NULL) { 1890*7a8a68f5SJulian Pullen domain_name = strdup(domainName); 1891*7a8a68f5SJulian Pullen if (domain_name == NULL) 1892*7a8a68f5SJulian Pullen return (-1); 1893*7a8a68f5SJulian Pullen update_item(&ctx->domain_name, domain_name, 1894*7a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 1895*7a8a68f5SJulian Pullen } else if (ctx->domain_name.state == AD_STATE_FIXED) 1896*7a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 1897*7a8a68f5SJulian Pullen return (0); 1898*7a8a68f5SJulian Pullen } 1899*7a8a68f5SJulian Pullen 1900*7a8a68f5SJulian Pullen 1901*7a8a68f5SJulian Pullen int 1902*7a8a68f5SJulian Pullen ad_disc_set_DomainController(ad_disc_t ctx, 1903*7a8a68f5SJulian Pullen const idmap_ad_disc_ds_t *domainController) 1904*7a8a68f5SJulian Pullen { 1905*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 1906*7a8a68f5SJulian Pullen if (domainController != NULL) { 1907*7a8a68f5SJulian Pullen domain_controller = ds_dup(domainController); 1908*7a8a68f5SJulian Pullen if (domain_controller == NULL) 1909*7a8a68f5SJulian Pullen return (-1); 1910*7a8a68f5SJulian Pullen update_item(&ctx->domain_controller, domain_controller, 1911*7a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 1912*7a8a68f5SJulian Pullen } else if (ctx->domain_controller.state == AD_STATE_FIXED) 1913*7a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 1914*7a8a68f5SJulian Pullen return (0); 1915*7a8a68f5SJulian Pullen } 1916*7a8a68f5SJulian Pullen 1917*7a8a68f5SJulian Pullen 1918*7a8a68f5SJulian Pullen int 1919*7a8a68f5SJulian Pullen ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) 1920*7a8a68f5SJulian Pullen { 1921*7a8a68f5SJulian Pullen char *site_name = NULL; 1922*7a8a68f5SJulian Pullen if (siteName != NULL) { 1923*7a8a68f5SJulian Pullen site_name = strdup(siteName); 1924*7a8a68f5SJulian Pullen if (site_name == NULL) 1925*7a8a68f5SJulian Pullen return (-1); 1926*7a8a68f5SJulian Pullen update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0); 1927*7a8a68f5SJulian Pullen } else if (ctx->site_name.state == AD_STATE_FIXED) 1928*7a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 1929*7a8a68f5SJulian Pullen return (0); 1930*7a8a68f5SJulian Pullen } 1931*7a8a68f5SJulian Pullen 1932*7a8a68f5SJulian Pullen int 1933*7a8a68f5SJulian Pullen ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) 1934*7a8a68f5SJulian Pullen { 1935*7a8a68f5SJulian Pullen char *forest_name = NULL; 1936*7a8a68f5SJulian Pullen if (forestName != NULL) { 1937*7a8a68f5SJulian Pullen forest_name = strdup(forestName); 1938*7a8a68f5SJulian Pullen if (forest_name == NULL) 1939*7a8a68f5SJulian Pullen return (-1); 1940*7a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, 1941*7a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 1942*7a8a68f5SJulian Pullen } else if (ctx->forest_name.state == AD_STATE_FIXED) 1943*7a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 1944*7a8a68f5SJulian Pullen return (0); 1945*7a8a68f5SJulian Pullen } 1946*7a8a68f5SJulian Pullen 1947*7a8a68f5SJulian Pullen int 1948*7a8a68f5SJulian Pullen ad_disc_set_GlobalCatalog(ad_disc_t ctx, 1949*7a8a68f5SJulian Pullen const idmap_ad_disc_ds_t *globalCatalog) 1950*7a8a68f5SJulian Pullen { 1951*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *global_catalog = NULL; 1952*7a8a68f5SJulian Pullen if (globalCatalog != NULL) { 1953*7a8a68f5SJulian Pullen global_catalog = ds_dup(globalCatalog); 1954*7a8a68f5SJulian Pullen if (global_catalog == NULL) 1955*7a8a68f5SJulian Pullen return (-1); 1956*7a8a68f5SJulian Pullen update_item(&ctx->global_catalog, global_catalog, 1957*7a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 1958*7a8a68f5SJulian Pullen } else if (ctx->global_catalog.state == AD_STATE_FIXED) 1959*7a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 1960*7a8a68f5SJulian Pullen return (0); 1961*7a8a68f5SJulian Pullen } 1962*7a8a68f5SJulian Pullen 1963*7a8a68f5SJulian Pullen 1964*7a8a68f5SJulian Pullen int 1965*7a8a68f5SJulian Pullen ad_disc_unset(ad_disc_t ctx) 1966*7a8a68f5SJulian Pullen { 1967*7a8a68f5SJulian Pullen if (ctx->domain_name.state == AD_STATE_FIXED) 1968*7a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 1969*7a8a68f5SJulian Pullen 1970*7a8a68f5SJulian Pullen if (ctx->domain_controller.state == AD_STATE_FIXED) 1971*7a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 1972*7a8a68f5SJulian Pullen 1973*7a8a68f5SJulian Pullen if (ctx->site_name.state == AD_STATE_FIXED) 1974*7a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 1975*7a8a68f5SJulian Pullen 1976*7a8a68f5SJulian Pullen if (ctx->forest_name.state == AD_STATE_FIXED) 1977*7a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 1978*7a8a68f5SJulian Pullen 1979*7a8a68f5SJulian Pullen if (ctx->global_catalog.state == AD_STATE_FIXED) 1980*7a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 1981*7a8a68f5SJulian Pullen 1982*7a8a68f5SJulian Pullen return (0); 1983*7a8a68f5SJulian Pullen } 1984*7a8a68f5SJulian Pullen 1985*7a8a68f5SJulian Pullen /* 1986*7a8a68f5SJulian Pullen * ad_disc_get_TTL 1987*7a8a68f5SJulian Pullen * 1988*7a8a68f5SJulian Pullen * This routines the time to live for AD 1989*7a8a68f5SJulian Pullen * auto discovered items. 1990*7a8a68f5SJulian Pullen * 1991*7a8a68f5SJulian Pullen * Returns: 1992*7a8a68f5SJulian Pullen * -1 if there are no TTL items 1993*7a8a68f5SJulian Pullen * 0 if there are expired items 1994*7a8a68f5SJulian Pullen * else the number of seconds 1995*7a8a68f5SJulian Pullen * 1996*7a8a68f5SJulian Pullen * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it 1997*7a8a68f5SJulian Pullen * is positive -- min() greater than zero. 1998*7a8a68f5SJulian Pullen */ 1999*7a8a68f5SJulian Pullen #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \ 2000*7a8a68f5SJulian Pullen (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x)))) 2001*7a8a68f5SJulian Pullen int 2002*7a8a68f5SJulian Pullen ad_disc_get_TTL(ad_disc_t ctx) 2003*7a8a68f5SJulian Pullen { 2004*7a8a68f5SJulian Pullen int ttl; 2005*7a8a68f5SJulian Pullen 2006*7a8a68f5SJulian Pullen ttl = MIN_GT_ZERO(ctx->domain_controller.ttl, ctx->global_catalog.ttl); 2007*7a8a68f5SJulian Pullen ttl = MIN_GT_ZERO(ttl, ctx->site_domain_controller.ttl); 2008*7a8a68f5SJulian Pullen ttl = MIN_GT_ZERO(ttl, ctx->site_global_catalog.ttl); 2009*7a8a68f5SJulian Pullen 2010*7a8a68f5SJulian Pullen if (ttl == -1) 2011*7a8a68f5SJulian Pullen return (-1); 2012*7a8a68f5SJulian Pullen ttl -= time(NULL); 2013*7a8a68f5SJulian Pullen if (ttl < 0) 2014*7a8a68f5SJulian Pullen return (0); 2015*7a8a68f5SJulian Pullen return (ttl); 2016*7a8a68f5SJulian Pullen } 2017*7a8a68f5SJulian Pullen 2018*7a8a68f5SJulian Pullen boolean_t 2019*7a8a68f5SJulian Pullen ad_disc_SubnetChanged(ad_disc_t ctx) 2020*7a8a68f5SJulian Pullen { 2021*7a8a68f5SJulian Pullen ad_subnet_t *subnets; 2022*7a8a68f5SJulian Pullen 2023*7a8a68f5SJulian Pullen if (ctx->subnets_changed || ctx->subnets == NULL) 2024*7a8a68f5SJulian Pullen return (B_TRUE); 2025*7a8a68f5SJulian Pullen 2026*7a8a68f5SJulian Pullen if ((subnets = find_subnets()) != NULL) { 2027*7a8a68f5SJulian Pullen if (cmpsubnets(subnets, ctx->subnets) != 0) 2028*7a8a68f5SJulian Pullen ctx->subnets_changed = B_TRUE; 2029*7a8a68f5SJulian Pullen free(subnets); 2030*7a8a68f5SJulian Pullen } 2031*7a8a68f5SJulian Pullen 2032*7a8a68f5SJulian Pullen return (ctx->subnets_changed); 2033*7a8a68f5SJulian Pullen } 2034