MSDFS referral shuffling
authorRobin McCorkell <rmccorkell@karoshi.org.uk>
Fri, 27 Feb 2015 14:52:46 +0000 (14:52 +0000)
committerJeremy Allison <jra@samba.org>
Fri, 27 Feb 2015 21:53:06 +0000 (22:53 +0100)
Shuffle MSDFS referral list in smbd in accordance with [MS-DFSC] 3.2.1.1
When parsing an MSDFS symlink, the names are shuffled with a Fisher-Yates
algorithm.

Signed-off-by: Robin McCorkell <rmccorkell@karoshi.org.uk>
Reviewed-by: David Disseldorp <ddiss@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
docs-xml/smbdotconf/vfs/msdfsshufflereferrals.xml [new file with mode: 0644]
lib/param/param_table.c
source3/param/loadparm.c
source3/smbd/msdfs.c

diff --git a/docs-xml/smbdotconf/vfs/msdfsshufflereferrals.xml b/docs-xml/smbdotconf/vfs/msdfsshufflereferrals.xml
new file mode 100644 (file)
index 0000000..3461f3a
--- /dev/null
@@ -0,0 +1,16 @@
+<samba:parameter name="msdfs shuffle referrals"
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+       <para>If set to <constant>yes</constant>, Samba will shuffle
+       Dfs referrals for a given Dfs link if multiple are available,
+       allowing for load balancing across clients. For more information
+       on setting up a Dfs tree on Samba, refer to the MSDFS chapter in
+       the Samba3-HOWTO book.</para>
+</description>
+
+<related>host msdfs</related>
+<related>msdfs root</related>
+<value type="default">no</value>
+</samba:parameter>
index 18b0628791c4f1a7bbe122e975bfe3a59d077f9e..00274ca2cbdd6bc9b26710e3bb1de34e5c468a22 100644 (file)
@@ -3941,6 +3941,15 @@ struct parm_struct parm_table[] = {
                .enum_list      = NULL,
                .flags          = FLAG_ADVANCED | FLAG_SHARE,
        },
+       {
+               .label          = "msdfs shuffle referrals",
+               .type           = P_BOOL,
+               .p_class        = P_LOCAL,
+               .offset         = LOCAL_VAR(msdfs_shuffle_referrals),
+               .special        = NULL,
+               .enum_list      = NULL,
+               .flags          = FLAG_ADVANCED | FLAG_SHARE,
+       },
        {
                .label          = "host msdfs",
                .type           = P_BOOL,
index da50e3a58247acf0af9e5c89123779a27e2b6426..4a7484349f658c22d4818bc9d91c6d22f4ed32bc 100644 (file)
@@ -222,6 +222,7 @@ static struct loadparm_service sDefault =
        .inherit_acls = false,
        .inherit_owner = false,
        .msdfs_root = false,
+       .msdfs_shuffle_referrals = false,
        .use_client_driver = false,
        .default_devmode = true,
        .force_printername = false,
index 3bd8a0944a48a056ac4c01e885c624eed0fe4f30..a39efce0689554fdc3a02ae9059fd0da24250834 100644 (file)
@@ -4,6 +4,7 @@
    MSDFS services for Samba
    Copyright (C) Shirish Kalele 2000
    Copyright (C) Jeremy Allison 2007
+   Copyright (C) Robin McCorkell 2015
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -428,6 +429,22 @@ NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
        return NT_STATUS_OK;
 }
 
+static void shuffle_strlist(char **list, int count)
+{
+       int i, r;
+       char *tmp;
+
+       srandom(time(NULL));
+
+       for (i = count; i > 1; i--) {
+               r = random() % i;
+
+               tmp = list[i-1];
+               list[i-1] = list[r];
+               list[r] = tmp;
+       }
+}
+
 /**********************************************************************
  Parse the contents of a symlink to verify if it is an msdfs referral
  A valid referral is of the form:
@@ -448,6 +465,7 @@ NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
  **********************************************************************/
 
 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
+                               int snum,
                                const char *target,
                                struct referral **preflist,
                                int *refcount)
@@ -480,6 +498,11 @@ static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
                count++;
        }
 
+       /* shuffle alternate paths */
+       if (lp_msdfs_shuffle_referrals(snum)) {
+               shuffle_strlist(alt_path, count);
+       }
+
        DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
 
        if (count) {
@@ -1007,7 +1030,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
                        return NT_STATUS_NO_MEMORY;
                }
 
-               if (!parse_msdfs_symlink(ctx, tmp, &ref, &refcount)) {
+               if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
                        TALLOC_FREE(tmp);
                        TALLOC_FREE(pdp);
                        return NT_STATUS_INVALID_PARAMETER;
@@ -1056,7 +1079,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
        }
 
        /* We know this is a valid dfs link. Parse the targetpath. */
-       if (!parse_msdfs_symlink(ctx, targetpath,
+       if (!parse_msdfs_symlink(ctx, snum, targetpath,
                                &jucn->referral_list,
                                &jucn->referral_count)) {
                DEBUG(3,("get_referred_path: failed to parse symlink "
@@ -1517,7 +1540,7 @@ static int form_junctions(TALLOC_CTX *ctx,
                                        conn,
                                        dname, &link_target,
                                        NULL)) {
-                       if (parse_msdfs_symlink(ctx,
+                       if (parse_msdfs_symlink(ctx, snum,
                                        link_target,
                                        &jucn[cnt].referral_list,
                                        &jucn[cnt].referral_count)) {