struct dnsserver_serverinfo *dnsserver_init_serverinfo(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_context *samdb) { struct dnsserver_serverinfo *serverinfo; struct dcerpc_server_info *dinfo; struct ldb_dn *domain_dn, *forest_dn; struct interface *ifaces; int num_interfaces, i; serverinfo = talloc_zero(mem_ctx, struct dnsserver_serverinfo); if (serverinfo == NULL) { return NULL; } dinfo = lpcfg_dcerpc_server_info(mem_ctx, lp_ctx); if (dinfo) { serverinfo->dwVersion = (dinfo->version_build & 0x0000FFFF) << 16 | (dinfo->version_minor & 0x000000FF) << 8 | (dinfo->version_major & 0x000000FF); talloc_free(dinfo); } else { serverinfo->dwVersion = 0x0ECE0205; /* build, os_minor, os_major */; } serverinfo->fBootMethod = DNS_BOOT_METHOD_DIRECTORY; serverinfo->fAdminConfigured = 0; serverinfo->fAllowUpdate = 1; serverinfo->fDsAvailable = 1; serverinfo->pszServerName = talloc_asprintf(mem_ctx, "%s.%s", lpcfg_netbios_name(lp_ctx), lpcfg_dnsdomain(lp_ctx)); domain_dn = ldb_get_default_basedn(samdb); forest_dn = ldb_get_root_basedn(samdb); serverinfo->pszDsContainer = talloc_asprintf(mem_ctx, "CN=MicrosoftDNS,DC=DomainDnsZones,%s", ldb_dn_get_linearized(domain_dn)); serverinfo->dwDsForestVersion = dsdb_forest_functional_level(samdb); serverinfo->dwDsDomainVersion = dsdb_functional_level(samdb); serverinfo->dwDsDsaVersion = 4; /* need to do ldb search here */ serverinfo->pszDomainName = samdb_dn_to_dns_domain(mem_ctx, domain_dn); serverinfo->pszForestName = samdb_dn_to_dns_domain(mem_ctx, forest_dn); serverinfo->pszDomainDirectoryPartition = talloc_asprintf(mem_ctx, "DC=DomainDnsZones,%s", ldb_dn_get_linearized(domain_dn)); serverinfo->pszForestDirectoryPartition = talloc_asprintf(mem_ctx, "DC=ForestDnsZones,%s", ldb_dn_get_linearized(forest_dn)); load_interface_list(mem_ctx, lp_ctx, &ifaces); num_interfaces = iface_list_count(ifaces); serverinfo->aipServerAddrs = talloc_zero(mem_ctx, struct IP4_ARRAY); if (serverinfo->aipServerAddrs) { serverinfo->aipServerAddrs->AddrCount = num_interfaces; if (num_interfaces > 0) { serverinfo->aipServerAddrs->AddrArray = talloc_zero_array(mem_ctx, unsigned int, num_interfaces); if (serverinfo->aipServerAddrs->AddrArray) { for (i=0; i<num_interfaces; i++) { serverinfo->aipServerAddrs->AddrArray[i] = inet_addr(iface_list_n_ip(ifaces, i)); } } else { serverinfo->aipServerAddrs->AddrCount = 0; } }
/* work out the principal to use for DRS replication connections */ NTSTATUS dreplsrv_get_target_principal(struct dreplsrv_service *s, TALLOC_CTX *mem_ctx, const struct repsFromTo1 *rft, const char **target_principal) { TALLOC_CTX *tmp_ctx; struct ldb_result *res; const char *attrs_server[] = { "dNSHostName", NULL }; const char *attrs_ntds[] = { "msDS-HasDomainNCs", "hasMasterNCs", NULL }; int ret; const char *hostname, *dnsdomain=NULL; struct ldb_dn *ntds_dn, *server_dn; struct ldb_dn *forest_dn, *nc_dn; *target_principal = NULL; tmp_ctx = talloc_new(mem_ctx); /* we need to find their hostname */ ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &rft->source_dsa_obj_guid, &ntds_dn); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); /* its OK for their NTDSDSA DN not to be in our database */ return NT_STATUS_OK; } server_dn = ldb_dn_copy(tmp_ctx, ntds_dn); if (server_dn == NULL) { talloc_free(tmp_ctx); return NT_STATUS_OK; } /* strip off the NTDS Settings */ if (!ldb_dn_remove_child_components(server_dn, 1)) { talloc_free(tmp_ctx); return NT_STATUS_OK; } ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, server_dn, attrs_server, 0); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); /* its OK for their server DN not to be in our database */ return NT_STATUS_OK; } forest_dn = ldb_get_root_basedn(s->samdb); if (forest_dn == NULL) { talloc_free(tmp_ctx); return NT_STATUS_OK; } hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL); if (hostname != NULL) { char *local_principal; /* if we have the dNSHostName attribute then we can use the GC/hostname/realm SPN. All DCs should have this SPN Windows DC may set up it's dNSHostName before setting up GC/xx/xx SPN. So make sure it exists, before using it. */ local_principal = talloc_asprintf(mem_ctx, "GC/%s/%s", hostname, samdb_dn_to_dns_domain(tmp_ctx, forest_dn)); if (dreplsrv_spn_exists(s->samdb, ntds_dn, local_principal)) { *target_principal = local_principal; talloc_free(tmp_ctx); return NT_STATUS_OK; } talloc_free(local_principal); } /* if we can't find the dNSHostName then we will try for the E3514235-4B06-11D1-AB04-00C04FC2DCD2/${NTDSGUID}/${DNSDOMAIN} SPN. To use that we need the DNS domain name of the target DC. We find that by first looking for the msDS-HasDomainNCs in the NTDSDSA object of the DC, and if we don't find that, then we look for the hasMasterNCs attribute, and eliminate the known schema and configuruation DNs. Despite how bizarre this seems, Hongwei tells us that this is in fact what windows does to find the SPN!! */ ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, ntds_dn, attrs_ntds, 0); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return NT_STATUS_OK; } nc_dn = ldb_msg_find_attr_as_dn(s->samdb, tmp_ctx, res->msgs[0], "msDS-HasDomainNCs"); if (nc_dn != NULL) { dnsdomain = samdb_dn_to_dns_domain(tmp_ctx, nc_dn); } if (dnsdomain == NULL) { struct ldb_message_element *el; int i; el = ldb_msg_find_element(res->msgs[0], "hasMasterNCs"); for (i=0; el && i<el->num_values; i++) { nc_dn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]); if (nc_dn == NULL || ldb_dn_compare(ldb_get_config_basedn(s->samdb), nc_dn) == 0 || ldb_dn_compare(ldb_get_schema_basedn(s->samdb), nc_dn) == 0) { continue; } /* it must be a domain DN, get the equivalent DNS domain name */ dnsdomain = samdb_dn_to_dns_domain(tmp_ctx, nc_dn); break; } } if (dnsdomain != NULL) { *target_principal = talloc_asprintf(mem_ctx, "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s", GUID_string(tmp_ctx, &rft->source_dsa_obj_guid), dnsdomain); } talloc_free(tmp_ctx); return NT_STATUS_OK; }
/* work out the principal to use for DRS replication connections */ NTSTATUS dreplsrv_get_target_principal(struct dreplsrv_service *s, TALLOC_CTX *mem_ctx, const struct repsFromTo1 *rft, const char **target_principal) { TALLOC_CTX *tmp_ctx; struct ldb_result *res; const char *attrs[] = { "dNSHostName", NULL }; int ret; const char *hostname; struct ldb_dn *dn; struct ldb_dn *forest_dn; *target_principal = NULL; tmp_ctx = talloc_new(mem_ctx); /* we need to find their hostname */ ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &rft->source_dsa_obj_guid, &dn); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); /* its OK for their NTDSDSA DN not to be in our database */ return NT_STATUS_OK; } /* strip off the NTDS Settings */ if (!ldb_dn_remove_child_components(dn, 1)) { talloc_free(tmp_ctx); return NT_STATUS_OK; } ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, dn, attrs, 0); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); /* its OK for their account DN not to be in our database */ return NT_STATUS_OK; } hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL); if (hostname == NULL) { talloc_free(tmp_ctx); /* its OK to not have a dnshostname */ return NT_STATUS_OK; } /* All DCs have the GC/hostname/realm name, but if some of the * preconditions are not satisfied, then we will fall back to * the * E3514235-4B06-11D1-AB04-00C04FC2DCD2/${NTDSGUID}/${DNSDOMAIN} * name. This means that if a AD server has a dnsHostName set * on it's record, it must also have GC/hostname/realm * servicePrincipalName */ forest_dn = ldb_get_root_basedn(s->samdb); if (forest_dn == NULL) { talloc_free(tmp_ctx); return NT_STATUS_OK; } *target_principal = talloc_asprintf(mem_ctx, "GC/%s/%s", hostname, samdb_dn_to_dns_domain(tmp_ctx, forest_dn)); talloc_free(tmp_ctx); return NT_STATUS_OK; }