Print this page
NEX-20555 idmap fall-back to DC discovery is broken
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-3155 idmap in a loop spamming its svc log
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Tony Nguyen <tony.nguyen@nexenta.com>
NEX-2892 NexentaStor losing connectivity to multihomed AD servers
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-2225 Unable to join NexentaStor to 2008 AD
NEX-1638 Updated DC Locator
 Includes work by: matt.barden@nexenta.com, kevin.crowe@nexenta.com


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Active Directory Auto-Discovery.
  29  *
  30  * This [project private] API allows the caller to provide whatever
  31  * details it knows a priori (i.e., provided via configuration so as to
  32  * override auto-discovery) and in any order.  Then the caller can ask
  33  * for any of the auto-discoverable parameters in any order.
  34  *
  35  * But there is an actual order in which discovery must be done.  Given
  36  * the discovery mechanism implemented here, that order is:
  37  *
  38  *  - the domain name joined must be discovered first
  39  *  - then the domain controllers
  40  *  - then the forest name and site name
  41  *  - then the global catalog servers, and site-specific domain
  42  *    controllers and global catalog servers.
  43  *
  44  * The API does not require it be called in the same order because there


1205 /* Discover domain controllers */
1206 static ad_item_t *
1207 validate_DomainController(ad_disc_t ctx, enum ad_disc_req req)
1208 {
1209         ad_disc_ds_t *dc = NULL;
1210         ad_disc_cds_t *cdc = NULL;
1211         boolean_t validate_global = B_FALSE;
1212         boolean_t validate_site = B_FALSE;
1213         ad_item_t *domain_name_item;
1214         char *domain_name;
1215         ad_item_t *site_name_item = NULL;
1216         char *site_name;
1217         ad_item_t *prefer_dc_item;
1218         ad_disc_ds_t *prefer_dc = NULL;
1219 
1220         /* If the values is fixed there will not be a site specific version */
1221         if (is_fixed(&ctx->domain_controller))
1222                 return (&ctx->domain_controller);
1223 
1224         domain_name_item = validate_DomainName(ctx);
1225         if (domain_name_item == NULL)

1226                 return (NULL);

1227         domain_name = (char *)domain_name_item->value;
1228 
1229         /* Get (optional) preferred DC. */
1230         prefer_dc_item = validate_PreferredDC(ctx);
1231         if (prefer_dc_item != NULL)
1232                 prefer_dc = prefer_dc_item->value;
1233 
1234         if (req == AD_DISC_GLOBAL)
1235                 validate_global = B_TRUE;
1236         else {
1237                 if (is_fixed(&ctx->site_name))
1238                         validate_site = B_TRUE;
1239                 else if (req == AD_DISC_PREFER_SITE)
1240                         validate_global = B_TRUE;
1241         }
1242 
1243         if (validate_global) {
1244                 if (!is_valid(&ctx->domain_controller) ||
1245                     is_changed(&ctx->domain_controller, PARAM1,
1246                     domain_name_item)) {



1247 







1248                         /*
1249                          * Lookup DNS SRV RR named
1250                          * _ldap._tcp.dc._msdcs.<DomainName>
1251                          */
1252                         DEBUG1STATUS(ctx, "DNS SRV query, dom=%s",
1253                             domain_name);



1254                         DO_RES_NINIT(ctx);
1255                         cdc = srv_query(&ctx->res_state,
1256                             LDAP_SRV_HEAD DC_SRV_TAIL,
1257                             domain_name, prefer_dc);
1258 
1259                         if (cdc == NULL) {
1260                                 DEBUG1STATUS(ctx, "(no DNS response)");
1261                                 return (NULL);
1262                         }
1263                         log_cds(ctx, cdc);
1264 
1265                         /*
1266                          * Filter out unresponsive servers, and
1267                          * save the domain info we get back.
1268                          */
1269                         dc = ldap_ping(
1270                             ctx,
1271                             cdc,
1272                             domain_name,
1273                             DS_DS_FLAG);
1274                         srv_free(cdc);
1275                         cdc = NULL;
1276 
1277                         if (dc == NULL) {
1278                                 DEBUG1STATUS(ctx, "(no LDAP response)");
1279                                 return (NULL);
1280                         }
1281                         log_ds(ctx, dc);
1282 
1283                         update_item(&ctx->domain_controller, dc,
1284                             AD_STATE_AUTO, dc->ttl);
1285                         update_version(&ctx->domain_controller, PARAM1,
1286                             domain_name_item);


1287                 }
1288                 return (&ctx->domain_controller);
1289         }
1290 
1291         if (validate_site) {
1292                 site_name_item = &ctx->site_name;
1293                 site_name = (char *)site_name_item->value;
1294 
1295                 if (!is_valid(&ctx->site_domain_controller) ||
1296                     is_changed(&ctx->site_domain_controller, PARAM1,
1297                     domain_name_item) ||
1298                     is_changed(&ctx->site_domain_controller, PARAM2,
1299                     site_name_item)) {
1300                         char rr_name[DNS_MAX_NAME];
1301 
1302                         /*
1303                          * Lookup DNS SRV RR named
1304                          * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName>
1305                          */
1306                         DEBUG1STATUS(ctx, "DNS SRV query, dom=%s, site=%s",
1307                             domain_name, site_name);
1308                         (void) snprintf(rr_name, sizeof (rr_name),
1309                             LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL,
1310                             site_name);
1311                         DO_RES_NINIT(ctx);
1312                         cdc = srv_query(&ctx->res_state, rr_name,

1313                             domain_name, prefer_dc);
1314 
1315                         if (cdc == NULL) {
1316                                 DEBUG1STATUS(ctx, "(no DNS response)");
1317                                 return (NULL);
1318                         }
1319                         log_cds(ctx, cdc);
1320 
1321                         /*
1322                          * Filter out unresponsive servers, and
1323                          * save the domain info we get back.
1324                          */
1325                         dc = ldap_ping(
1326                             ctx,
1327                             cdc,
1328                             domain_name,
1329                             DS_DS_FLAG);
1330                         srv_free(cdc);
1331                         cdc = NULL;
1332 
1333                         if (dc == NULL) {
1334                                 DEBUG1STATUS(ctx, "(no LDAP response)");
1335                                 return (NULL);
1336                         }
1337                         log_ds(ctx, dc);
1338 
1339                         update_item(&ctx->site_domain_controller, dc,
1340                             AD_STATE_AUTO, dc->ttl);
1341                         update_version(&ctx->site_domain_controller, PARAM1,
1342                             domain_name_item);
1343                         update_version(&ctx->site_domain_controller, PARAM2,
1344                             site_name_item);
1345                 }
1346                 return (&ctx->site_domain_controller);
1347         }

1348         return (NULL);
1349 }
1350 
1351 ad_disc_ds_t *
1352 ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req,
1353     boolean_t *auto_discovered)
1354 {
1355         ad_item_t *domain_controller_item;
1356         ad_disc_ds_t *domain_controller = NULL;
1357 
1358         domain_controller_item = validate_DomainController(ctx, req);
1359 
1360         if (domain_controller_item != NULL) {
1361                 domain_controller = ds_dup(domain_controller_item->value);
1362                 if (auto_discovered != NULL)
1363                         *auto_discovered =
1364                             (domain_controller_item->state == AD_STATE_AUTO);
1365         } else if (auto_discovered != NULL)
1366                 *auto_discovered = B_FALSE;
1367 


1499 
1500 /* Discover global catalog servers */
1501 static ad_item_t *
1502 validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req)
1503 {
1504         ad_disc_ds_t *gc = NULL;
1505         ad_disc_cds_t *cgc = NULL;
1506         boolean_t validate_global = B_FALSE;
1507         boolean_t validate_site = B_FALSE;
1508         ad_item_t *dc_item;
1509         ad_item_t *forest_name_item;
1510         ad_item_t *site_name_item;
1511         char *forest_name;
1512         char *site_name;
1513 
1514         /* If the values is fixed there will not be a site specific version */
1515         if (is_fixed(&ctx->global_catalog))
1516                 return (&ctx->global_catalog);
1517 
1518         forest_name_item = validate_ForestName(ctx);
1519         if (forest_name_item == NULL)

1520                 return (NULL);

1521         forest_name = (char *)forest_name_item->value;
1522 
1523         if (req == AD_DISC_GLOBAL)
1524                 validate_global = B_TRUE;
1525         else {
1526                 if (is_fixed(&ctx->site_name))
1527                         validate_site = B_TRUE;
1528                 else if (req == AD_DISC_PREFER_SITE)
1529                         validate_global = B_TRUE;
1530         }
1531 
1532         if (validate_global) {
1533                 if (!is_valid(&ctx->global_catalog) ||
1534                     is_changed(&ctx->global_catalog, PARAM1,
1535                     forest_name_item)) {



1536 







1537                         /*
1538                          * See if our DC is also a GC.
1539                          */
1540                         dc_item = validate_DomainController(ctx, req);
1541                         if (dc_item != NULL) {
1542                                 ad_disc_ds_t *ds = dc_item->value;
1543                                 if ((ds->flags & DS_GC_FLAG) != 0) {
1544                                         DEBUG1STATUS(ctx,
1545                                             "DC is also a GC for %s",
1546                                             forest_name);
1547                                         gc = ds_dup(ds);
1548                                         if (gc != NULL) {
1549                                                 gc->port = GC_PORT;
1550                                                 goto update_global;
1551                                         }
1552                                 }
1553                         }
1554 
1555                         /*
1556                          * Lookup DNS SRV RR named:
1557                          * _ldap._tcp.gc._msdcs.<ForestName>

1558                          */
1559                         DEBUG1STATUS(ctx, "DNS SRV query, forest=%s",
1560                             forest_name);



1561                         DO_RES_NINIT(ctx);
1562                         cgc = srv_query(&ctx->res_state,
1563                             LDAP_SRV_HEAD GC_SRV_TAIL,
1564                             forest_name, NULL);
1565 
1566                         if (cgc == NULL) {
1567                                 DEBUG1STATUS(ctx, "(no DNS response)");
1568                                 return (NULL);
1569                         }
1570                         log_cds(ctx, cgc);
1571 
1572                         /*
1573                          * Filter out unresponsive servers, and
1574                          * save the domain info we get back.
1575                          */
1576                         gc = ldap_ping(
1577                             NULL,
1578                             cgc,
1579                             forest_name,
1580                             DS_GC_FLAG);
1581                         srv_free(cgc);
1582                         cgc = NULL;
1583 
1584                         if (gc == NULL) {
1585                                 DEBUG1STATUS(ctx, "(no LDAP response)");
1586                                 return (NULL);
1587                         }
1588                         log_ds(ctx, gc);
1589 
1590                 update_global:
1591                         update_item(&ctx->global_catalog, gc,
1592                             AD_STATE_AUTO, gc->ttl);
1593                         update_version(&ctx->global_catalog, PARAM1,
1594                             forest_name_item);


1595                 }
1596                 return (&ctx->global_catalog);
1597         }
1598 
1599         if (validate_site) {
1600                 site_name_item = &ctx->site_name;
1601                 site_name = (char *)site_name_item->value;
1602 
1603                 if (!is_valid(&ctx->site_global_catalog) ||
1604                     is_changed(&ctx->site_global_catalog, PARAM1,
1605                     forest_name_item) ||
1606                     is_changed(&ctx->site_global_catalog, PARAM2,
1607                     site_name_item)) {
1608                         char rr_name[DNS_MAX_NAME];
1609 
1610                         /*
1611                          * See if our DC is also a GC.
1612                          */
1613                         dc_item = validate_DomainController(ctx, req);
1614                         if (dc_item != NULL) {
1615                                 ad_disc_ds_t *ds = dc_item->value;
1616                                 if ((ds->flags & DS_GC_FLAG) != 0) {
1617                                         DEBUG1STATUS(ctx,
1618                                             "DC is also a GC for %s in %s",
1619                                             forest_name, site_name);
1620                                         gc = ds_dup(ds);
1621                                         if (gc != NULL) {
1622                                                 gc->port = GC_PORT;
1623                                                 goto update_site;
1624                                         }
1625                                 }
1626                         }
1627 
1628                         /*
1629                          * Lookup DNS SRV RR named:
1630                          * _ldap._tcp.<siteName>._sites.gc.
1631                          *      _msdcs.<ForestName>
1632                          */
1633                         DEBUG1STATUS(ctx, "DNS SRV query, forest=%s, site=%s",
1634                             forest_name, site_name);
1635                         (void) snprintf(rr_name, sizeof (rr_name),
1636                             LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL,
1637                             site_name);
1638                         DO_RES_NINIT(ctx);
1639                         cgc = srv_query(&ctx->res_state, rr_name,

1640                             forest_name, NULL);
1641 
1642                         if (cgc == NULL) {
1643                                 DEBUG1STATUS(ctx, "(no DNS response)");
1644                                 return (NULL);
1645                         }
1646                         log_cds(ctx, cgc);
1647 
1648                         /*
1649                          * Filter out unresponsive servers, and
1650                          * save the domain info we get back.
1651                          */
1652                         gc = ldap_ping(
1653                             NULL,
1654                             cgc,
1655                             forest_name,
1656                             DS_GC_FLAG);
1657                         srv_free(cgc);
1658                         cgc = NULL;
1659 
1660                         if (gc == NULL) {
1661                                 DEBUG1STATUS(ctx, "(no LDAP response)");
1662                                 return (NULL);
1663                         }
1664                         log_ds(ctx, gc);
1665 
1666                 update_site:
1667                         update_item(&ctx->site_global_catalog, gc,
1668                             AD_STATE_AUTO, gc->ttl);
1669                         update_version(&ctx->site_global_catalog, PARAM1,
1670                             forest_name_item);
1671                         update_version(&ctx->site_global_catalog, PARAM2,
1672                             site_name_item);
1673                 }
1674                 return (&ctx->site_global_catalog);
1675         }
1676         return (NULL);
1677 }
1678 
1679 
1680 ad_disc_ds_t *
1681 ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req,
1682                         boolean_t *auto_discovered)
1683 {
1684         ad_disc_ds_t *global_catalog = NULL;
1685         ad_item_t *global_catalog_item;
1686 
1687         global_catalog_item = validate_GlobalCatalog(ctx, req);
1688 
1689         if (global_catalog_item != NULL) {
1690                 global_catalog = ds_dup(global_catalog_item->value);
1691                 if (auto_discovered != NULL)
1692                         *auto_discovered =
1693                             (global_catalog_item->state == AD_STATE_AUTO);
1694         } else if (auto_discovered != NULL)




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Active Directory Auto-Discovery.
  29  *
  30  * This [project private] API allows the caller to provide whatever
  31  * details it knows a priori (i.e., provided via configuration so as to
  32  * override auto-discovery) and in any order.  Then the caller can ask
  33  * for any of the auto-discoverable parameters in any order.
  34  *
  35  * But there is an actual order in which discovery must be done.  Given
  36  * the discovery mechanism implemented here, that order is:
  37  *
  38  *  - the domain name joined must be discovered first
  39  *  - then the domain controllers
  40  *  - then the forest name and site name
  41  *  - then the global catalog servers, and site-specific domain
  42  *    controllers and global catalog servers.
  43  *
  44  * The API does not require it be called in the same order because there


1205 /* Discover domain controllers */
1206 static ad_item_t *
1207 validate_DomainController(ad_disc_t ctx, enum ad_disc_req req)
1208 {
1209         ad_disc_ds_t *dc = NULL;
1210         ad_disc_cds_t *cdc = NULL;
1211         boolean_t validate_global = B_FALSE;
1212         boolean_t validate_site = B_FALSE;
1213         ad_item_t *domain_name_item;
1214         char *domain_name;
1215         ad_item_t *site_name_item = NULL;
1216         char *site_name;
1217         ad_item_t *prefer_dc_item;
1218         ad_disc_ds_t *prefer_dc = NULL;
1219 
1220         /* If the values is fixed there will not be a site specific version */
1221         if (is_fixed(&ctx->domain_controller))
1222                 return (&ctx->domain_controller);
1223 
1224         domain_name_item = validate_DomainName(ctx);
1225         if (domain_name_item == NULL) {
1226                 DEBUG1STATUS(ctx, "(no domain name)");
1227                 return (NULL);
1228         }
1229         domain_name = (char *)domain_name_item->value;
1230 
1231         /* Get (optional) preferred DC. */
1232         prefer_dc_item = validate_PreferredDC(ctx);
1233         if (prefer_dc_item != NULL)
1234                 prefer_dc = prefer_dc_item->value;
1235 
1236         if (req == AD_DISC_GLOBAL)
1237                 validate_global = B_TRUE;
1238         else {
1239                 if (is_fixed(&ctx->site_name))
1240                         validate_site = B_TRUE;
1241                 if (req == AD_DISC_PREFER_SITE)
1242                         validate_global = B_TRUE;
1243         }
1244 
1245         /*
1246          * If we're trying both site-specific and global,
1247          * try the site-specific first, then fall-back.
1248          */
1249         if (validate_site) {
1250                 site_name_item = &ctx->site_name;
1251                 site_name = (char *)site_name_item->value;
1252 
1253                 if (!is_valid(&ctx->site_domain_controller) ||
1254                     is_changed(&ctx->site_domain_controller, PARAM1,
1255                     domain_name_item) ||
1256                     is_changed(&ctx->site_domain_controller, PARAM2,
1257                     site_name_item)) {
1258                         char rr_name[DNS_MAX_NAME];
1259 
1260                         /*
1261                          * Lookup DNS SRV RR named
1262                          * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName>
1263                          */
1264                         DEBUG1STATUS(ctx, "DNS SRV query, dom=%s, site=%s",
1265                             domain_name, site_name);
1266                         (void) snprintf(rr_name, sizeof (rr_name),
1267                             LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL,
1268                             site_name);
1269                         DO_RES_NINIT(ctx);
1270                         cdc = srv_query(&ctx->res_state, rr_name,

1271                             domain_name, prefer_dc);
1272 
1273                         if (cdc == NULL) {
1274                                 DEBUG1STATUS(ctx, "(no DNS response)");
1275                                 goto try_global;
1276                         }
1277                         log_cds(ctx, cdc);
1278 
1279                         /*
1280                          * Filter out unresponsive servers, and
1281                          * save the domain info we get back.
1282                          */
1283                         dc = ldap_ping(
1284                             ctx,
1285                             cdc,
1286                             domain_name,
1287                             DS_DS_FLAG);
1288                         srv_free(cdc);
1289                         cdc = NULL;
1290 
1291                         if (dc == NULL) {
1292                                 DEBUG1STATUS(ctx, "(no LDAP response)");
1293                                 goto try_global;
1294                         }
1295                         log_ds(ctx, dc);
1296 
1297                         update_item(&ctx->site_domain_controller, dc,
1298                             AD_STATE_AUTO, dc->ttl);
1299                         update_version(&ctx->site_domain_controller, PARAM1,
1300                             domain_name_item);
1301                         update_version(&ctx->site_domain_controller, PARAM2,
1302                             site_name_item);
1303                 }
1304                 return (&ctx->site_domain_controller);
1305         }
1306 
1307 try_global:


1308 
1309         if (validate_global) {
1310                 if (!is_valid(&ctx->domain_controller) ||
1311                     is_changed(&ctx->domain_controller, PARAM1,
1312                     domain_name_item)) {


1313 
1314                         /*
1315                          * Lookup DNS SRV RR named
1316                          * _ldap._tcp.dc._msdcs.<DomainName>
1317                          */
1318                         DEBUG1STATUS(ctx, "DNS SRV query, dom=%s",
1319                             domain_name);



1320                         DO_RES_NINIT(ctx);
1321                         cdc = srv_query(&ctx->res_state,
1322                             LDAP_SRV_HEAD DC_SRV_TAIL,
1323                             domain_name, prefer_dc);
1324 
1325                         if (cdc == NULL) {
1326                                 DEBUG1STATUS(ctx, "(no DNS response)");
1327                                 return (NULL);
1328                         }
1329                         log_cds(ctx, cdc);
1330 
1331                         /*
1332                          * Filter out unresponsive servers, and
1333                          * save the domain info we get back.
1334                          */
1335                         dc = ldap_ping(
1336                             ctx,
1337                             cdc,
1338                             domain_name,
1339                             DS_DS_FLAG);
1340                         srv_free(cdc);
1341                         cdc = NULL;
1342 
1343                         if (dc == NULL) {
1344                                 DEBUG1STATUS(ctx, "(no LDAP response)");
1345                                 return (NULL);
1346                         }
1347                         log_ds(ctx, dc);
1348 
1349                         update_item(&ctx->domain_controller, dc,
1350                             AD_STATE_AUTO, dc->ttl);
1351                         update_version(&ctx->domain_controller, PARAM1,
1352                             domain_name_item);


1353                 }
1354                 return (&ctx->domain_controller);
1355         }
1356 
1357         return (NULL);
1358 }
1359 
1360 ad_disc_ds_t *
1361 ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req,
1362     boolean_t *auto_discovered)
1363 {
1364         ad_item_t *domain_controller_item;
1365         ad_disc_ds_t *domain_controller = NULL;
1366 
1367         domain_controller_item = validate_DomainController(ctx, req);
1368 
1369         if (domain_controller_item != NULL) {
1370                 domain_controller = ds_dup(domain_controller_item->value);
1371                 if (auto_discovered != NULL)
1372                         *auto_discovered =
1373                             (domain_controller_item->state == AD_STATE_AUTO);
1374         } else if (auto_discovered != NULL)
1375                 *auto_discovered = B_FALSE;
1376 


1508 
1509 /* Discover global catalog servers */
1510 static ad_item_t *
1511 validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req)
1512 {
1513         ad_disc_ds_t *gc = NULL;
1514         ad_disc_cds_t *cgc = NULL;
1515         boolean_t validate_global = B_FALSE;
1516         boolean_t validate_site = B_FALSE;
1517         ad_item_t *dc_item;
1518         ad_item_t *forest_name_item;
1519         ad_item_t *site_name_item;
1520         char *forest_name;
1521         char *site_name;
1522 
1523         /* If the values is fixed there will not be a site specific version */
1524         if (is_fixed(&ctx->global_catalog))
1525                 return (&ctx->global_catalog);
1526 
1527         forest_name_item = validate_ForestName(ctx);
1528         if (forest_name_item == NULL) {
1529                 DEBUG1STATUS(ctx, "(no forrest name)");
1530                 return (NULL);
1531         }
1532         forest_name = (char *)forest_name_item->value;
1533 
1534         if (req == AD_DISC_GLOBAL)
1535                 validate_global = B_TRUE;
1536         else {
1537                 if (is_fixed(&ctx->site_name))
1538                         validate_site = B_TRUE;
1539                 if (req == AD_DISC_PREFER_SITE)
1540                         validate_global = B_TRUE;
1541         }
1542 
1543         /*
1544          * If we're trying both site-specific and global,
1545          * try the site-specific first, then fall-back.
1546          */
1547         if (validate_site) {
1548                 site_name_item = &ctx->site_name;
1549                 site_name = (char *)site_name_item->value;
1550 
1551                 if (!is_valid(&ctx->site_global_catalog) ||
1552                     is_changed(&ctx->site_global_catalog, PARAM1,
1553                     forest_name_item) ||
1554                     is_changed(&ctx->site_global_catalog, PARAM2,
1555                     site_name_item)) {
1556                         char rr_name[DNS_MAX_NAME];
1557 
1558                         /*
1559                          * See if our DC is also a GC.
1560                          */
1561                         dc_item = validate_DomainController(ctx, req);
1562                         if (dc_item != NULL) {
1563                                 ad_disc_ds_t *ds = dc_item->value;
1564                                 if ((ds->flags & DS_GC_FLAG) != 0) {
1565                                         DEBUG1STATUS(ctx,
1566                                             "DC is also a GC for %s in %s",
1567                                             forest_name, site_name);
1568                                         gc = ds_dup(ds);
1569                                         if (gc != NULL) {
1570                                                 gc->port = GC_PORT;
1571                                                 goto update_site;
1572                                         }
1573                                 }
1574                         }
1575 
1576                         /*
1577                          * Lookup DNS SRV RR named:
1578                          * _ldap._tcp.<siteName>._sites.gc.
1579                          *      _msdcs.<ForestName>
1580                          */
1581                         DEBUG1STATUS(ctx, "DNS SRV query, forest=%s, site=%s",
1582                             forest_name, site_name);
1583                         (void) snprintf(rr_name, sizeof (rr_name),
1584                             LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL,
1585                             site_name);
1586                         DO_RES_NINIT(ctx);
1587                         cgc = srv_query(&ctx->res_state, rr_name,

1588                             forest_name, NULL);
1589 
1590                         if (cgc == NULL) {
1591                                 DEBUG1STATUS(ctx, "(no DNS response)");
1592                                 goto try_global;
1593                         }
1594                         log_cds(ctx, cgc);
1595 
1596                         /*
1597                          * Filter out unresponsive servers, and
1598                          * save the domain info we get back.
1599                          */
1600                         gc = ldap_ping(
1601                             NULL,
1602                             cgc,
1603                             forest_name,
1604                             DS_GC_FLAG);
1605                         srv_free(cgc);
1606                         cgc = NULL;
1607 
1608                         if (gc == NULL) {
1609                                 DEBUG1STATUS(ctx, "(no LDAP response)");
1610                                 goto try_global;
1611                         }
1612                         log_ds(ctx, gc);
1613 
1614                 update_site:
1615                         update_item(&ctx->site_global_catalog, gc,
1616                             AD_STATE_AUTO, gc->ttl);
1617                         update_version(&ctx->site_global_catalog, PARAM1,
1618                             forest_name_item);
1619                         update_version(&ctx->site_global_catalog, PARAM2,
1620                             site_name_item);
1621                 }
1622                 return (&ctx->site_global_catalog);
1623         }
1624 
1625 try_global:


1626 
1627         if (validate_global) {
1628                 if (!is_valid(&ctx->global_catalog) ||
1629                     is_changed(&ctx->global_catalog, PARAM1,
1630                     forest_name_item)) {


1631 
1632                         /*
1633                          * See if our DC is also a GC.
1634                          */
1635                         dc_item = validate_DomainController(ctx, req);
1636                         if (dc_item != NULL) {
1637                                 ad_disc_ds_t *ds = dc_item->value;
1638                                 if ((ds->flags & DS_GC_FLAG) != 0) {
1639                                         DEBUG1STATUS(ctx,
1640                                             "DC is also a GC for %s",
1641                                             forest_name);
1642                                         gc = ds_dup(ds);
1643                                         if (gc != NULL) {
1644                                                 gc->port = GC_PORT;
1645                                                 goto update_global;
1646                                         }
1647                                 }
1648                         }
1649 
1650                         /*
1651                          * Lookup DNS SRV RR named:
1652                          * _ldap._tcp.gc._msdcs.<ForestName>

1653                          */
1654                         DEBUG1STATUS(ctx, "DNS SRV query, forest=%s",
1655                             forest_name);



1656                         DO_RES_NINIT(ctx);
1657                         cgc = srv_query(&ctx->res_state,
1658                             LDAP_SRV_HEAD GC_SRV_TAIL,
1659                             forest_name, NULL);
1660 
1661                         if (cgc == NULL) {
1662                                 DEBUG1STATUS(ctx, "(no DNS response)");
1663                                 return (NULL);
1664                         }
1665                         log_cds(ctx, cgc);
1666 
1667                         /*
1668                          * Filter out unresponsive servers, and
1669                          * save the domain info we get back.
1670                          */
1671                         gc = ldap_ping(
1672                             NULL,
1673                             cgc,
1674                             forest_name,
1675                             DS_GC_FLAG);
1676                         srv_free(cgc);
1677                         cgc = NULL;
1678 
1679                         if (gc == NULL) {
1680                                 DEBUG1STATUS(ctx, "(no LDAP response)");
1681                                 return (NULL);
1682                         }
1683                         log_ds(ctx, gc);
1684 
1685                 update_global:
1686                         update_item(&ctx->global_catalog, gc,
1687                             AD_STATE_AUTO, gc->ttl);
1688                         update_version(&ctx->global_catalog, PARAM1,
1689                             forest_name_item);


1690                 }
1691                 return (&ctx->global_catalog);
1692         }
1693         return (NULL);
1694 }
1695 
1696 
1697 ad_disc_ds_t *
1698 ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req,
1699                         boolean_t *auto_discovered)
1700 {
1701         ad_disc_ds_t *global_catalog = NULL;
1702         ad_item_t *global_catalog_item;
1703 
1704         global_catalog_item = validate_GlobalCatalog(ctx, req);
1705 
1706         if (global_catalog_item != NULL) {
1707                 global_catalog = ds_dup(global_catalog_item->value);
1708                 if (auto_discovered != NULL)
1709                         *auto_discovered =
1710                             (global_catalog_item->state == AD_STATE_AUTO);
1711         } else if (auto_discovered != NULL)