summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/smbsrv/smb_dfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/fs/smbsrv/smb_dfs.c')
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dfs.c127
1 files changed, 117 insertions, 10 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_dfs.c
index ef199d4c8e..80d4479e68 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dfs.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dfs.c
@@ -83,6 +83,7 @@ static uint32_t smb_dfs_referrals_get(smb_request_t *, char *, dfs_reftype_t,
dfs_referral_response_t *);
static void smb_dfs_referrals_free(dfs_referral_response_t *);
static uint16_t smb_dfs_referrals_unclen(dfs_info_t *, uint16_t);
+static uint32_t smb_dfs_get_referrals_ex(smb_request_t *, smb_fsctl_t *);
/*
* Handle device type FILE_DEVICE_DFS
@@ -108,7 +109,9 @@ smb_dfs_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
case FSCTL_DFS_GET_REFERRALS:
status = smb_dfs_get_referrals(sr, fsctl);
break;
- case FSCTL_DFS_GET_REFERRALS_EX: /* XXX - todo */
+ case FSCTL_DFS_GET_REFERRALS_EX:
+ status = smb_dfs_get_referrals_ex(sr, fsctl);
+ break;
default:
/*
* MS-SMB2 suggests INVALID_DEVICE_REQUEST
@@ -122,6 +125,119 @@ smb_dfs_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
}
/*
+ * XXX Instead of decoding the referral request and encoding
+ * the response here (in-kernel) we could pass the given
+ * request buffer in our door call, and let that return the
+ * response buffer ready to stuff into out_mbc. That would
+ * allow all this decoding/encoding to happen at user-level.
+ * (and most of this file would go away. :-)
+ */
+
+/*
+ * See [MS-DFSC] for details about this command
+ * Handles FSCTL_DFS_GET_REFERRALS_EX (only)
+ */
+uint32_t
+smb_dfs_get_referrals_ex(smb_request_t *sr, smb_fsctl_t *fsctl)
+{
+ dfs_info_t *referrals;
+ dfs_referral_response_t refrsp;
+ dfs_reftype_t reftype;
+ char *path;
+ uint16_t maxver;
+ uint16_t flags;
+ uint16_t fnlen;
+ uint32_t datalen;
+ uint32_t status;
+ int rc;
+
+ /*
+ * The caller checks this, because the error reporting method
+ * varies across SMB versions.
+ */
+ ASSERT(STYPE_ISIPC(sr->tid_tree->t_res_type));
+
+ /*
+ * Decode fixed part.
+ * Input data is (w) MaxReferralLevel, (w) Flags,
+ * (l) RequestDataLength, ... variable data ...
+ */
+ rc = smb_mbc_decodef(fsctl->in_mbc, "wwl",
+ &maxver, &flags, &datalen);
+ if (rc != 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ /*
+ * Decode variable part:
+ * (w) file name length, (u) filename,
+ * ( if flags & 1 )
+ * (w) site name len, (u) site name
+ * We don't decode or use the site name
+ */
+ if (MBC_ROOM_FOR(fsctl->in_mbc, datalen) == 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+ rc = smb_mbc_decodef(fsctl->in_mbc, "%wu",
+ sr, &fnlen, &path);
+ if (rc != 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ reftype = smb_dfs_get_reftype((const char *)path);
+ switch (reftype) {
+ case DFS_REFERRAL_INVALID:
+ /* Need to check the error for this case */
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ case DFS_REFERRAL_DOMAIN:
+ case DFS_REFERRAL_DC:
+ /* MS-DFSC: this error is returned by non-DC root */
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ case DFS_REFERRAL_SYSVOL:
+ /* MS-DFSC: this error is returned by non-DC root */
+ return (NT_STATUS_NO_SUCH_DEVICE);
+
+ default:
+ break;
+ }
+
+ status = smb_dfs_referrals_get(sr, path, reftype, &refrsp);
+ if (status != NT_STATUS_SUCCESS)
+ return (status);
+
+ referrals = &refrsp.rp_referrals;
+ smb_dfs_encode_hdr(fsctl->out_mbc, referrals);
+
+ /*
+ * Server may respond with any referral version at or below
+ * the maximum specified in the request.
+ */
+ switch (maxver) {
+ case DFS_REFERRAL_V1:
+ status = smb_dfs_encode_refv1(sr, fsctl->out_mbc, referrals);
+ break;
+
+ case DFS_REFERRAL_V2:
+ status = smb_dfs_encode_refv2(sr, fsctl->out_mbc, referrals);
+ break;
+
+ case DFS_REFERRAL_V3:
+ status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
+ DFS_REFERRAL_V3);
+ break;
+
+ case DFS_REFERRAL_V4:
+ default:
+ status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
+ DFS_REFERRAL_V4);
+ break;
+ }
+
+ smb_dfs_referrals_free(&refrsp);
+
+ return (status);
+}
+
+/*
* Note: SMB1 callers in smb_trans2_dfs.c
* smb_com_trans2_report_dfs_inconsistency
* smb_com_trans2_get_dfs_referral
@@ -149,15 +265,6 @@ smb_dfs_get_referrals(smb_request_t *sr, smb_fsctl_t *fsctl)
ASSERT(STYPE_ISIPC(sr->tid_tree->t_res_type));
/*
- * XXX Instead of decoding the referral request and encoding
- * the response here (in-kernel) we could pass the given
- * request buffer in our door call, and let that return the
- * response buffer ready to stuff into out_mbc. That would
- * allow all this decoding/encoding to happen at user-level.
- * (and most of this file would go away. :-)
- */
-
- /*
* Input data is (w) MaxReferralLevel, (U) path
*/
rc = smb_mbc_decodef(fsctl->in_mbc, "%wu",