From 9bd26d81900c16718e9ad3916aec5a7ac6b636be Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 1 Oct 2011 06:57:18 +0200 Subject: s3:vfs: add SMB_VFS_GET_DFS_REFERRAL() hooks metze --- source3/Makefile.in | 1 + source3/include/vfs.h | 14 ++++ source3/include/vfs_macros.h | 9 +++ source3/modules/vfs_default.c | 177 ++++++++++++++++++++++++++++++++++++++++++ source3/modules/wscript_build | 2 +- source3/smbd/vfs.c | 7 ++ 6 files changed, 209 insertions(+), 1 deletion(-) diff --git a/source3/Makefile.in b/source3/Makefile.in index 1264611f72..24567e27ef 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -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 \ diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 3b5e0e7f6a..4559b351bc 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -137,6 +137,7 @@ /* 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); diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index 3dd6a64249..6047f59392 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -68,6 +68,15 @@ #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)) diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index d1bf95eb23..17200696b3 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -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 */ diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build index 2ae7a7e33a..b3ab734ac1 100644 --- a/source3/modules/wscript_build +++ b/source3/modules/wscript_build @@ -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')) diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 9b1f2484b4..7f16670173 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -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) -- cgit