librpc: add dcerpc_get_auth_{type,level,context_id}() helper functions
[samba.git] / dfs_server / dfs_server_ad.c
index 4d3891a774a9042749d1a6f0b1be685b5fa39225..84a19bd380551af2db88cc169079e150981dc253 100644 (file)
@@ -27,6 +27,7 @@
 #include "lib/tsocket/tsocket.h"
 #include "dfs_server/dfs_server_ad.h"
 #include "lib/util/util_net.h"
+#include "libds/common/roles.h"
 
 #define MAX_DFS_RESPONSE 56*1024 /* 56 Kb */
 
@@ -38,6 +39,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
  */
@@ -198,22 +215,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)));
@@ -221,7 +244,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)));
@@ -230,10 +253,13 @@ 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 *aname = ldb_msg_find_attr_as_string(r2->msgs[0], "sAMAccountName", 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)));
@@ -242,7 +268,10 @@ static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
                        }
 
                        tmp = talloc_strdup(list->names, aname);
-                       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp, r);
+                       if (tmp == NULL) {
+                               TALLOC_FREE(r);
+                               return NT_STATUS_NO_MEMORY;
+                       }
 
                        /* Netbios name is also the sAMAccountName for
                           computer but without the final $ */
@@ -250,9 +279,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;
 }
@@ -334,14 +365,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)) {
@@ -384,10 +428,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;
@@ -424,8 +474,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);
@@ -554,7 +602,7 @@ static NTSTATUS dodc_referral(struct loadparm_context *lp_ctx,
                }
        }
 
-       site_name = samdb_client_site_name(sam_ctx, r, client_str, NULL);
+       site_name = samdb_client_site_name(sam_ctx, r, client_str, NULL, true);
 
        status = get_dcs(r, sam_ctx, site_name, need_fqdn, &set, 0);
        if (!NT_STATUS_IS_OK(status)) {
@@ -665,7 +713,7 @@ static NTSTATUS dosysvol_referral(struct loadparm_context *lp_ctx,
                }
        }
 
-       site_name = samdb_client_site_name(sam_ctx, r, client_str, NULL);
+       site_name = samdb_client_site_name(sam_ctx, r, client_str, NULL, true);
 
        status = get_dcs(r, sam_ctx, site_name, need_fqdn, &set, 0);
        if (!NT_STATUS_IS_OK(status)) {
@@ -751,6 +799,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;
@@ -778,16 +828,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++;
@@ -827,6 +879,40 @@ NTSTATUS dfs_server_ad_get_referrals(struct loadparm_context *lp_ctx,
                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) &&
            (strcasecmp_m(server_name, dns_domain) != 0)) {
                /*