winbind client: avoid vicious cycle created by client retry
[samba.git] / dfs_server / dfs_server_ad.c
index b7004c5506fb08104dce6d6ed6f5b6bfa4cc3c0b..3a25dff9d14c40fae5021ead14ba5089aa56f7c9 100644 (file)
@@ -26,6 +26,7 @@
 #include "param/param.h"
 #include "lib/tsocket/tsocket.h"
 #include "dfs_server/dfs_server_ad.h"
+#include "lib/util/util_net.h"
 
 #define MAX_DFS_RESPONSE 56*1024 /* 56 Kb */
 
@@ -37,6 +38,22 @@ struct dc_set {
        uint32_t count;
 };
 
+static void shuffle_dc_set(struct dc_set *list)
+{
+       uint32_t i;
+
+       for (i = list->count; i > 1; i--) {
+               uint32_t r;
+               const char *tmp;
+
+               r = generate_random() % i;
+
+               tmp = list->names[i - 1];
+               list->names[i - 1] = list->names[r];
+               list->names[r] = tmp;
+       }
+}
+
 /*
   fill a referral type structure
  */
@@ -197,22 +214,28 @@ static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
         * Search all the object of class server in this site
         */
        dc_list = talloc_array(r, const char *, r->count);
-       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, r);
+       if (dc_list == NULL) {
+               TALLOC_FREE(r);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        /* TODO put some random here in the order */
        list->names = talloc_realloc(list, list->names, const char *, list->count + r->count);
-       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names, r);
+       if (list->names == NULL) {
+               TALLOC_FREE(r);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        for (i = 0; i<r->count; i++) {
                struct ldb_dn  *dn;
-               struct ldb_result *r2;
+               struct ldb_message *msg;
 
                dn = ldb_msg_find_attr_as_dn(ldb, ctx, r->msgs[i], "serverReference");
                if (!dn) {
                        return NT_STATUS_INTERNAL_ERROR;
                }
 
-               ret = ldb_search(ldb, r, &r2, dn, LDB_SCOPE_BASE, attrs2, "(objectClass=computer)");
+               ret = dsdb_search_one(ldb, r, &msg, dn, LDB_SCOPE_BASE, attrs2, 0, "(objectClass=computer)");
                if (ret != LDB_SUCCESS) {
                        DEBUG(2,(__location__ ": Search for computer on %s failed - %s\n",
                                 ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
@@ -220,7 +243,7 @@ static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
                }
 
                if (dofqdn) {
-                       const char *dns = ldb_msg_find_attr_as_string(r2->msgs[0], "dNSHostName", NULL);
+                       const char *dns = ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL);
                        if (dns == NULL) {
                                DEBUG(2,(__location__ ": dNSHostName missing on %s\n",
                                         ldb_dn_get_linearized(dn)));
@@ -229,19 +252,25 @@ static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
                        }
 
                        list->names[list->count] = talloc_strdup(list->names, dns);
-                       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names[list->count], r);
+                       if (list->names[list->count] == NULL) {
+                               TALLOC_FREE(r);
+                               return NT_STATUS_NO_MEMORY;
+                       }
                } else {
                        char *tmp;
-                       const char *acct = ldb_msg_find_attr_as_string(r2->msgs[0], "sAMAccountName", NULL);
-                       if (acct == NULL) {
+                       const char *aname = ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL);
+                       if (aname == NULL) {
                                DEBUG(2,(__location__ ": sAMAccountName missing on %s\n",
                                         ldb_dn_get_linearized(dn)));
                                talloc_free(r);
                                return NT_STATUS_INTERNAL_ERROR;
                        }
 
-                       tmp = talloc_strdup(list->names, acct);
-                       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp, r);
+                       tmp = talloc_strdup(list->names, aname);
+                       if (tmp == NULL) {
+                               TALLOC_FREE(r);
+                               return NT_STATUS_NO_MEMORY;
+                       }
 
                        /* Netbios name is also the sAMAccountName for
                           computer but without the final $ */
@@ -249,9 +278,11 @@ static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
                        list->names[list->count] = tmp;
                }
                list->count++;
-               talloc_free(r2);
+               talloc_free(msg);
        }
 
+       shuffle_dc_set(list);
+
        talloc_free(r);
        return NT_STATUS_OK;
 }
@@ -277,7 +308,7 @@ static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb,
        int ret;
        uint32_t current_pos = 0;
        NTSTATUS status;
-       TALLOC_CTX *subctx = talloc_new(ctx);
+       TALLOC_CTX *subctx;
 
        *pset_list = set_list = NULL;
 
@@ -333,14 +364,27 @@ static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb,
                /* All of this was to get the DN of the searched_site */
                sitedn = r->msgs[0]->dn;
 
-               set_list = talloc_realloc(subctx, set_list, struct dc_set *, current_pos+1);
-               NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
+               /*
+                * We will realloc + 2 because we will need one additional place
+                * for element at current_pos + 1 for the NULL element
+                */
+               set_list = talloc_realloc(subctx, set_list, struct dc_set *, current_pos+2);
+               if (set_list == NULL) {
+                       TALLOC_FREE(subctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
 
                set_list[current_pos] = talloc(set_list, struct dc_set);
-               NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
+               if (set_list[current_pos] == NULL) {
+                       TALLOC_FREE(subctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
 
                set_list[current_pos]->names = NULL;
                set_list[current_pos]->count = 0;
+
+               set_list[current_pos+1] = NULL;
+
                status = get_dcs_insite(subctx, ldb, sitedn,
                                        set_list[current_pos], need_fqdn);
                if (!NT_STATUS_IS_OK(status)) {
@@ -383,10 +427,16 @@ static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb,
                 */
                set_list = talloc_realloc(subctx, set_list, struct dc_set *,
                                          current_pos+2);
-               NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
+               if (set_list == NULL) {
+                       TALLOC_FREE(subctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
 
                set_list[current_pos] = talloc(ctx, struct dc_set);
-               NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
+               if (set_list[current_pos] == NULL) {
+                       TALLOC_FREE(subctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
 
                set_list[current_pos]->names = NULL;
                set_list[current_pos]->count = 0;
@@ -423,8 +473,6 @@ static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb,
                        }
                }
        }
-       current_pos++;
-       set_list[current_pos] = NULL;
 
        *pset_list = talloc_move(ctx, &set_list);
        talloc_free(subctx);
@@ -447,7 +495,7 @@ static NTSTATUS dodomain_referral(struct loadparm_context *lp_ctx,
        /* In the future this needs to be fetched from the ldb */
        uint32_t found_domain = 2;
 
-       if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
+       if (lpcfg_server_role(lp_ctx) != ROLE_ACTIVE_DIRECTORY_DC) {
                DEBUG(10 ,("Received a domain referral request on a non DC\n"));
                return NT_STATUS_INVALID_PARAMETER;
        }
@@ -529,7 +577,7 @@ static NTSTATUS dodc_referral(struct loadparm_context *lp_ctx,
        struct dfs_referral_type *referrals;
        const char *referral_str;
 
-       if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
+       if (lpcfg_server_role(lp_ctx) != ROLE_ACTIVE_DIRECTORY_DC) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -640,7 +688,7 @@ static NTSTATUS dosysvol_referral(struct loadparm_context *lp_ctx,
        NTSTATUS status;
        struct dfs_referral_type *referrals;
 
-       if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
+       if (lpcfg_server_role(lp_ctx) != ROLE_ACTIVE_DIRECTORY_DC) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -750,6 +798,8 @@ NTSTATUS dfs_server_ad_get_referrals(struct loadparm_context *lp_ctx,
        const char *dns_domain;
        const char *netbios_name;
        const char *dns_name;
+       const char **netbios_aliases;
+       char path_separator;
 
        if (!lpcfg_host_msdfs(lp_ctx)) {
                return NT_STATUS_FS_DRIVER_REQUIRED;
@@ -777,16 +827,18 @@ NTSTATUS dfs_server_ad_get_referrals(struct loadparm_context *lp_ctx,
                return NT_STATUS_NO_MEMORY;
        }
 
-       while(*server_name && *server_name == '\\') {
+       path_separator = (*server_name == '/') ? '/' : '\\';
+
+       while(*server_name && *server_name == path_separator) {
                server_name++;
        }
 
-       dfs_name = strchr(server_name, '\\');
+       dfs_name = strchr_m(server_name, path_separator);
        if (dfs_name != NULL) {
                dfs_name[0] = '\0';
                dfs_name++;
 
-               link_path = strchr(dfs_name, '\\');
+               link_path = strchr_m(dfs_name, path_separator);
                if (link_path != NULL) {
                        link_path[0] = '\0';
                        link_path++;
@@ -816,7 +868,48 @@ NTSTATUS dfs_server_ad_get_referrals(struct loadparm_context *lp_ctx,
                 * handle it here.
                 */
                return NT_STATUS_NOT_FOUND;
+       }
+
+       if (is_ipaddress(server_name)) {
+               /*
+                * If it is not domain related do not
+                * handle it here.
+                */
+               return NT_STATUS_NOT_FOUND;
+       }
+
+       netbios_aliases = lpcfg_netbios_aliases(lp_ctx);
+       while (netbios_aliases && *netbios_aliases) {
+               const char *netbios_alias = *netbios_aliases;
+               char *dns_alias;
+               int cmp;
+
+               cmp = strcasecmp_m(server_name, netbios_alias);
+               if (cmp == 0) {
+                       /*
+                        * If it is not domain related do not
+                        * handle it here.
+                        */
+                       return NT_STATUS_NOT_FOUND;
+               }
 
+               dns_alias = talloc_asprintf(r, "%s.%s",
+                                           netbios_alias,
+                                           dns_domain);
+               if (dns_alias == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               cmp = strcasecmp_m(server_name, dns_alias);
+               talloc_free(dns_alias);
+               if (cmp == 0) {
+                       /*
+                        * If it is not domain related do not
+                        * handle it here.
+                        */
+                       return NT_STATUS_NOT_FOUND;
+               }
+               netbios_aliases++;
        }
 
        if ((strcasecmp_m(server_name, netbios_domain) != 0) &&