s3:vfs: add SMB_VFS_GET_DFS_REFERRAL() hooks
authorStefan Metzmacher <metze@samba.org>
Sat, 1 Oct 2011 04:57:18 +0000 (06:57 +0200)
committerStefan Metzmacher <metze@samba.org>
Fri, 7 Oct 2011 23:43:38 +0000 (01:43 +0200)
metze

source3/Makefile.in
source3/include/vfs.h
source3/include/vfs_macros.h
source3/modules/vfs_default.c
source3/modules/wscript_build
source3/smbd/vfs.c

index 1264611f726e5cc7642db8eead705482efece945..24567e27ef966849c0737fa3839ce19561eff4cc 100644 (file)
@@ -385,6 +385,7 @@ LIBCLI_EPMAPPER_OBJ = librpc/gen_ndr/ndr_epmapper_c.o
 LIBNDR_GEN_OBJ = librpc/gen_ndr/ndr_wkssvc.o \
                 $(LIBNDR_GEN_OBJ0) \
                 librpc/gen_ndr/ndr_dfs.o \
+                librpc/gen_ndr/ndr_dfsblobs.o \
                 librpc/gen_ndr/ndr_echo.o \
                 librpc/gen_ndr/ndr_winreg.o \
                 librpc/gen_ndr/ndr_initshutdown.o \
index 3b5e0e7f6a24afeb29d18dad605a149ed3715ad8..4559b351bc6451a974a4ee7da6930c0d93b8e9d4 100644 (file)
 /* Leave at 28 - not yet released. Make getwd function always return malloced memory. JRA. */
 /* Bump to version 29 - Samba 3.6.0 will ship with interface version 28. */
 /* Leave at 29 - not yet releases. Add fsctl. Richard Sharpe */
+/* Leave at 29 - not yet released. add SMB_VFS_GET_DFS_REFERRAL() - metze */
 #define SMB_VFS_INTERFACE_VERSION 29
 
 /*
@@ -157,6 +158,7 @@ struct ea_list;
 struct smb_file_time;
 struct blocking_lock_record;
 struct smb_filename;
+struct dfs_GetDFSReferral;
 
 #define VFS_FIND(__fn__) while (handle->fns->__fn__==NULL) { \
                                handle = handle->next; \
@@ -193,6 +195,13 @@ struct vfs_fn_pointers {
        int (*statvfs)(struct vfs_handle_struct *handle, const char *path, struct vfs_statvfs_struct *statbuf);
        uint32_t (*fs_capabilities)(struct vfs_handle_struct *handle, enum timestamp_set_resolution *p_ts_res);
 
+       /*
+        * Note: that "struct dfs_GetDFSReferral *r"
+        * needs to be a valid TALLOC_CTX
+        */
+       NTSTATUS (*get_dfs_referrals)(struct vfs_handle_struct *handle,
+                                     struct dfs_GetDFSReferral *r);
+
        /* Directory operations */
 
        SMB_STRUCT_DIR *(*opendir)(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attributes);
@@ -536,6 +545,11 @@ int smb_vfs_call_statvfs(struct vfs_handle_struct *handle, const char *path,
                         struct vfs_statvfs_struct *statbuf);
 uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle,
                        enum timestamp_set_resolution *p_ts_res);
+/*
+ * Note: that "struct dfs_GetDFSReferral *r" needs to be a valid TALLOC_CTX
+ */
+NTSTATUS smb_vfs_call_get_dfs_referrals(struct vfs_handle_struct *handle,
+                                       struct dfs_GetDFSReferral *r);
 SMB_STRUCT_DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle,
                                     const char *fname, const char *mask,
                                     uint32 attributes);
index 3dd6a642496085a1b13806ae31af5b86ba8199dd..6047f59392cd2434af6306268e85a7cad7560aa2 100644 (file)
 #define SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) \
        smb_vfs_call_fs_capabilities((handle)->next, (p_ts_res))
 
+/*
+ * Note: that "struct dfs_GetDFSReferral *r"
+ * needs to be a valid TALLOC_CTX
+ */
+#define SMB_VFS_GET_DFS_REFERRALS(conn, r) \
+       smb_vfs_call_get_dfs_referrals((conn)->vfs_handles, (r))
+#define SMB_VFS_NEXT_GET_DFS_REFERRALS(handle, r) \
+       smb_vfs_call_get_dfs_referrals((handle)->next, (r))
+
 /* Directory operations */
 #define SMB_VFS_OPENDIR(conn, fname, mask, attr) \
        smb_vfs_call_opendir((conn)->vfs_handles, (fname), (mask), (attr))
index d1bf95eb2334f2a19c12ff131c2446fd53d67a82..17200696b340858c81a4e713142049c024a591f7 100644 (file)
@@ -26,6 +26,8 @@
 #include "smbprofile.h"
 #include "../libcli/security/security.h"
 #include "passdb/lookup_sid.h"
+#include "source3/include/msdfs.h"
+#include "librpc/gen_ndr/ndr_dfsblobs.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -165,6 +167,180 @@ static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
        return caps;
 }
 
+static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
+                                         struct dfs_GetDFSReferral *r)
+{
+       struct junction_map *junction = NULL;
+       int consumedcnt = 0;
+       bool self_referral = false;
+       char *pathnamep = NULL;
+       char *local_dfs_path = NULL;
+       NTSTATUS status;
+       int i;
+       uint16_t max_referral_level = r->in.req.max_referral_level;
+
+       if (DEBUGLVL(10)) {
+               NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
+       }
+
+       /* get the junction entry */
+       if (r->in.req.servername == NULL) {
+               return NT_STATUS_NOT_FOUND;
+       }
+
+       /*
+        * Trim pathname sent by client so it begins with only one backslash.
+        * Two backslashes confuse some dfs clients
+        */
+
+       local_dfs_path = talloc_strdup(r, r->in.req.servername);
+       if (local_dfs_path == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       pathnamep = local_dfs_path;
+       while (IS_DIRECTORY_SEP(pathnamep[0]) &&
+              IS_DIRECTORY_SEP(pathnamep[1])) {
+               pathnamep++;
+       }
+
+       junction = talloc_zero(r, struct junction_map);
+       if (junction == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* The following call can change cwd. */
+       status = get_referred_path(r, pathnamep, handle->conn->sconn,
+                                  junction, &consumedcnt, &self_referral);
+       if (!NT_STATUS_IS_OK(status)) {
+               vfs_ChDir(handle->conn, handle->conn->connectpath);
+               return status;
+       }
+       vfs_ChDir(handle->conn, handle->conn->connectpath);
+
+       if (!self_referral) {
+               pathnamep[consumedcnt] = '\0';
+
+               if (DEBUGLVL(3)) {
+                       dbgtext("setup_dfs_referral: Path %s to "
+                               "alternate path(s):",
+                               pathnamep);
+                       for (i=0; i < junction->referral_count; i++) {
+                               dbgtext(" %s",
+                               junction->referral_list[i].alternate_path);
+                       }
+                       dbgtext(".\n");
+               }
+       }
+
+       if (r->in.req.max_referral_level <= 2) {
+               max_referral_level = 2;
+       }
+       if (r->in.req.max_referral_level >= 3) {
+               max_referral_level = 3;
+       }
+
+       r->out.resp = talloc_zero(r, struct dfs_referral_resp);
+       if (r->out.resp == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
+       r->out.resp->nb_referrals = junction->referral_count;
+
+       r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
+       if (self_referral) {
+               r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
+       }
+
+       r->out.resp->referral_entries = talloc_zero_array(r,
+                               struct dfs_referral_type,
+                               r->out.resp->nb_referrals);
+       if (r->out.resp->referral_entries == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       switch (max_referral_level) {
+       case 2:
+               for(i=0; i < junction->referral_count; i++) {
+                       struct referral *ref = &junction->referral_list[i];
+                       TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
+                       struct dfs_referral_type *t =
+                               &r->out.resp->referral_entries[i];
+                       struct dfs_referral_v2 *v2 = &t->referral.v2;
+
+                       t->version = 2;
+                       v2->size = VERSION2_REFERRAL_SIZE;
+                       if (self_referral) {
+                               v2->server_type = DFS_SERVER_ROOT;
+                       } else {
+                               v2->server_type = DFS_SERVER_NON_ROOT;
+                       }
+                       v2->entry_flags = 0;
+                       v2->proximity = ref->proximity;
+                       v2->ttl = ref->ttl;
+                       v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
+                       if (v2->DFS_path == NULL) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+                       v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
+                       if (v2->DFS_alt_path == NULL) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+                       v2->netw_address = talloc_strdup(mem_ctx,
+                                                        ref->alternate_path);
+                       if (v2->netw_address == NULL) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+               }
+
+               break;
+       case 3:
+               for(i=0; i < junction->referral_count; i++) {
+                       struct referral *ref = &junction->referral_list[i];
+                       TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
+                       struct dfs_referral_type *t =
+                               &r->out.resp->referral_entries[i];
+                       struct dfs_referral_v3 *v3 = &t->referral.v3;
+                       struct dfs_normal_referral *r1 = &v3->referrals.r1;
+
+                       t->version = 3;
+                       v3->size = VERSION3_REFERRAL_SIZE;
+                       if (self_referral) {
+                               v3->server_type = DFS_SERVER_ROOT;
+                       } else {
+                               v3->server_type = DFS_SERVER_NON_ROOT;
+                       }
+                       v3->entry_flags = 0;
+                       v3->ttl = ref->ttl;
+                       r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
+                       if (r1->DFS_path == NULL) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+                       r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
+                       if (r1->DFS_alt_path == NULL) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+                       r1->netw_address = talloc_strdup(mem_ctx,
+                                                        ref->alternate_path);
+                       if (r1->netw_address == NULL) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+               }
+               break;
+       default:
+               DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
+                       "version: %d\n",
+                       max_referral_level));
+               return NT_STATUS_INVALID_LEVEL;
+       }
+
+       if (DEBUGLVL(10)) {
+               NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
+       }
+
+       return NT_STATUS_OK;
+}
+
 /* Directory operations */
 
 static SMB_STRUCT_DIR *vfswrap_opendir(vfs_handle_struct *handle,  const char *fname, const char *mask, uint32 attr)
@@ -2002,6 +2178,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .get_shadow_copy_data = vfswrap_get_shadow_copy_data,
        .statvfs = vfswrap_statvfs,
        .fs_capabilities = vfswrap_fs_capabilities,
+       .get_dfs_referrals = vfswrap_get_dfs_referrals,
 
        /* Directory operations */
 
index 2ae7a7e33afc2195157059fa620e342305e6706f..b3ab734ac15ed08afcca580936d8d1b8222a0fdd 100644 (file)
@@ -68,7 +68,7 @@ bld.SAMBA3_SUBSYSTEM('vfs',
 bld.SAMBA3_MODULE('vfs_default',
                  subsystem='vfs',
                  source=VFS_DEFAULT_SRC,
-                 deps='samba-util',
+                 deps='samba-util NDR_DFSBLOBS',
                  init_function='',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_default'),
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_default'))
index 9b1f2484b427b59b59c99e6959d343d18b82c907..7f166701732be5cee671630331f96423d81aff24 100644 (file)
@@ -1196,6 +1196,13 @@ uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle,
        return handle->fns->fs_capabilities(handle, p_ts_res);
 }
 
+NTSTATUS smb_vfs_call_get_dfs_referrals(struct vfs_handle_struct *handle,
+                                       struct dfs_GetDFSReferral *r)
+{
+       VFS_FIND(get_dfs_referrals);
+       return handle->fns->get_dfs_referrals(handle, r);
+}
+
 SMB_STRUCT_DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle,
                                     const char *fname, const char *mask,
                                     uint32 attributes)