summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2011-10-01 06:57:18 +0200
committerStefan Metzmacher <metze@samba.org>2011-10-08 01:43:38 +0200
commit9bd26d81900c16718e9ad3916aec5a7ac6b636be (patch)
tree80724d3c6a69c2cf9c793ca260a97754f9b839d6
parent37a17a49175b2f0eca5578467b785325561eb0cf (diff)
downloadsamba-9bd26d81900c16718e9ad3916aec5a7ac6b636be.tar.gz
samba-9bd26d81900c16718e9ad3916aec5a7ac6b636be.tar.bz2
samba-9bd26d81900c16718e9ad3916aec5a7ac6b636be.zip
s3:vfs: add SMB_VFS_GET_DFS_REFERRAL() hooks
metze
-rw-r--r--source3/Makefile.in1
-rw-r--r--source3/include/vfs.h14
-rw-r--r--source3/include/vfs_macros.h9
-rw-r--r--source3/modules/vfs_default.c177
-rw-r--r--source3/modules/wscript_build2
-rw-r--r--source3/smbd/vfs.c7
6 files changed, 209 insertions, 1 deletions
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)