diff options
Diffstat (limited to 'source4/dsdb')
-rw-r--r-- | source4/dsdb/common/util.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 3a04797f82..7dd68b8b99 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -40,6 +40,7 @@ #include "system/locale.h" #include "lib/util/tsort.h" #include "dsdb/common/util.h" +#include "lib/socket/socket.h" /* search the sam for the specified attributes in a specific domain, filter on @@ -1593,6 +1594,95 @@ const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) } /* + * Finds the client site by using the client's IP address. + * The "subnet_name" returns the name of the subnet if parameter != NULL + */ +const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, + const char *ip_address, char **subnet_name) +{ + const char *attrs[] = { "cn", "siteObject", NULL }; + struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn; + struct ldb_result *res; + const struct ldb_val *val; + const char *site_name = NULL, *l_subnet_name = NULL; + const char *allow_list[2] = { NULL, NULL }; + unsigned int i; + int cnt, ret; + + sites_container_dn = samdb_sites_dn(ldb, mem_ctx); + if (sites_container_dn == NULL) { + return NULL; + } + + subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn); + if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) { + talloc_free(sites_container_dn); + talloc_free(subnets_dn); + return NULL; + } + + ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL, + attrs, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(sites_container_dn); + talloc_free(subnets_dn); + return NULL; + } + + for (i = 0; i < res->count; i++) { + l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn", + NULL); + + allow_list[0] = l_subnet_name; + + if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) { + sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, + res->msgs[i], + "siteObject"); + if (sites_dn == NULL) { + /* No reference, maybe another subnet matches */ + continue; + } + + /* "val" cannot be NULL here since "sites_dn" != NULL */ + val = ldb_dn_get_rdn_val(sites_dn); + site_name = talloc_strdup(mem_ctx, + (const char *) val->data); + + talloc_free(sites_dn); + + break; + } + } + + if (site_name == NULL) { + /* This is the Windows Server fallback rule: when no subnet + * exists and we have only one site available then use it (it + * is for sure the same as our server site). If more sites do + * exist then we don't know which one to use and set the site + * name to "". */ + cnt = samdb_search_count(ldb, sites_container_dn, + "(objectClass=site)"); + if (cnt == 1) { + site_name = samdb_server_site_name(ldb, mem_ctx); + } else { + site_name = talloc_strdup(mem_ctx, ""); + } + l_subnet_name = NULL; + } + + if (subnet_name != NULL) { + *subnet_name = talloc_strdup(mem_ctx, l_subnet_name); + } + + talloc_free(sites_container_dn); + talloc_free(subnets_dn); + talloc_free(res); + + return site_name; +} + +/* work out if we are the PDC for the domain of the current open ldb */ bool samdb_is_pdc(struct ldb_context *ldb) |