summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McDonald <danmcd@mnx.io>2022-10-17 17:45:31 -0400
committerGitHub <noreply@github.com>2022-10-17 17:45:31 -0400
commit0304e418633be64468218263192782a12da919a2 (patch)
treea305a88a3fb813163a34c393e4ec6742c519c038
parenta41cec58980057a54ffdf464a2b2d381d819b975 (diff)
parent4012c8b05c5f0ba3a55d5f171a8906ec60b60076 (diff)
downloadillumos-joyent-OS-8418.tar.gz
Merge branch 'master' into OS-8418OS-8418
-rw-r--r--usr/src/cmd/bhyve/rfb.c25
-rw-r--r--usr/src/cmd/bhyve/sockstream.c8
-rw-r--r--usr/src/lib/libsec/common/aclutils.c153
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_fsctl_fs.c25
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c5
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_negotiate.c428
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_qinfo_quota.c14
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_setinfo_quota.c17
-rw-r--r--usr/src/uts/common/smb/winioctl.h4
-rw-r--r--usr/src/uts/common/smbsrv/smb_ktypes.h14
10 files changed, 374 insertions, 319 deletions
diff --git a/usr/src/cmd/bhyve/rfb.c b/usr/src/cmd/bhyve/rfb.c
index c58fd2d6cd..576b66c0e8 100644
--- a/usr/src/cmd/bhyve/rfb.c
+++ b/usr/src/cmd/bhyve/rfb.c
@@ -193,8 +193,10 @@ fast_crc32(void *buf, int len, uint32_t crcval)
static void
rfb_send_client_status(rfb_client_t *c, uint32_t status, const char *msg)
{
- status = htonl(status);
+ rfb_printf(c, RFB_LOGDEBUG, "sending client status %u (%s)",
+ status, msg ? msg : "NULL");
+ status = htonl(status);
(void) stream_write(c->rc_fd, &status, sizeof (status));
if (msg != NULL && status != 0 && c->rc_cver == RFB_CVER_3_8) {
@@ -214,7 +216,7 @@ rfb_handshake_version(rfb_client_t *c)
unsigned char buf[RFB_VERSION_LEN];
ssize_t l;
- rfb_printf(c, RFB_LOGDEBUG, "handshake version");
+ rfb_printf(c, RFB_LOGDEBUG, "handshake version");
if (stream_write(c->rc_fd, RFB_VERSION, RFB_VERSION_LEN) !=
RFB_VERSION_LEN) {
@@ -368,12 +370,19 @@ rfb_handshake_auth(rfb_client_t *c)
/* Initialize a 16-byte random challenge. */
arc4random_buf(challenge, sizeof (challenge));
- (void) stream_write(c->rc_fd, challenge, RFBP_SECURITY_VNC_AUTH_LEN);
+
+ /* Send the challenge to the client. */
+ if (stream_write(c->rc_fd, challenge, RFBP_SECURITY_VNC_AUTH_LEN)
+ != RFBP_SECURITY_VNC_AUTH_LEN) {
+ rfb_printf(c, RFB_LOGERR,
+ "failed to send challenge to client");
+ return (false);
+ }
/* Receive the 16-byte challenge response. */
if (stream_read(c->rc_fd, buf, RFBP_SECURITY_VNC_AUTH_LEN)
!= RFBP_SECURITY_VNC_AUTH_LEN) {
- rfb_send_client_status(c, 1, "response read failed");
+ rfb_send_client_status(c, 1, "Challenge response read failed");
return (false);
}
@@ -1216,8 +1225,10 @@ rfb_client_tx_thread(void *arg)
c->rc_sinfo.rsi_pixfmt = c->rc_s->rs_pixfmt;
c->rc_encodings = RFB_ENCODING_RAW;
- if (!rfb_handshake(c))
+ if (!rfb_handshake(c)) {
+ rfb_printf(c, RFB_LOGWARN, "handshake failure");
goto out;
+ }
c->rc_cells = howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, RFB_PIX_PER_CELL);
if ((c->rc_crc = calloc(c->rc_cells, sizeof (uint32_t))) == NULL ||
@@ -1275,10 +1286,10 @@ rfb_client_tx_thread(void *arg)
}
}
- rfb_printf(c, RFB_LOGWARN, "disconnected");
-
out:
+ rfb_printf(c, RFB_LOGWARN, "disconnected");
+
(void) pthread_join(c->rc_rx_tid, &status);
pthread_mutex_lock(&s->rs_clientlock);
s->rs_clientcount--;
diff --git a/usr/src/cmd/bhyve/sockstream.c b/usr/src/cmd/bhyve/sockstream.c
index b592bce9aa..d8d9966cfb 100644
--- a/usr/src/cmd/bhyve/sockstream.c
+++ b/usr/src/cmd/bhyve/sockstream.c
@@ -34,6 +34,10 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <unistd.h>
+#ifndef __FreeBSD__
+#include <sys/socket.h>
+#endif
+
#include <errno.h>
#include "sockstream.h"
@@ -72,7 +76,11 @@ stream_write(int fd, const void *buf, ssize_t nbytes)
p = buf;
while (len < nbytes) {
+#ifdef __FreeBSD__
n = write(fd, p + len, nbytes - len);
+#else
+ n = send(fd, p + len, nbytes - len, MSG_NOSIGNAL);
+#endif
if (n == 0)
break;
if (n < 0) {
diff --git a/usr/src/lib/libsec/common/aclutils.c b/usr/src/lib/libsec/common/aclutils.c
index ea91ddb96e..5a67ca1397 100644
--- a/usr/src/lib/libsec/common/aclutils.c
+++ b/usr/src/lib/libsec/common/aclutils.c
@@ -746,64 +746,95 @@ acl_error(const char *fmt, ...)
va_end(va);
}
-int
-sid_to_id(char *sid, boolean_t user, uid_t *id)
+typedef enum id_type {
+ UID_TYPE,
+ GID_TYPE,
+ PID_TYPE
+} id_type_t;
+
+static int
+sid_to_id_impl(char *sid, id_type_t type, int *is_user, uid_t *id)
{
- idmap_get_handle_t *get_hdl = NULL;
- char *rid_start = NULL;
+ idmap_get_handle_t *get_hdl;
+ char *rid_start;
+ idmap_stat rv;
+ idmap_rid_t rid;
+ const char *errstr;
idmap_stat status;
- char *end;
int error = 1;
+
+ rid_start = strrchr(sid, '-');
+ if (rid_start == NULL)
+ return (error);
+
+ rid = strtonum(rid_start + 1, 0, UINT32_MAX, &errstr);
+ if (errstr != NULL)
+ return (error);
+
+ if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS)
+ return (error);
+
+ /*
+ * When these functions return success, the &status output is
+ * indeterminate. We only care about rv==success in this caller,
+ * so just ignore &status.
+ */
+ /* We need sid prefix. Insert NUL on '-', restore it later. */
+ *rid_start = '\0';
+ switch (type) {
+ case UID_TYPE:
+ rv = idmap_get_uidbysid(get_hdl,
+ sid, rid, IDMAP_REQ_FLG_USE_CACHE,
+ id, &status);
+ break;
+
+ case GID_TYPE:
+ rv = idmap_get_gidbysid(get_hdl,
+ sid, rid, IDMAP_REQ_FLG_USE_CACHE,
+ id, &status);
+ break;
+
+ case PID_TYPE:
+ rv = idmap_get_pidbysid(get_hdl, sid, rid,
+ IDMAP_REQ_FLG_USE_CACHE, id, is_user,
+ &status);
+ break;
+ }
+
+ *rid_start = '-'; /* putback character removed earlier */
+ if (rv == IDMAP_SUCCESS &&
+ idmap_get_mappings(get_hdl) == IDMAP_SUCCESS) {
+ error = 0;
+ }
+ idmap_get_destroy(get_hdl);
+
+ return (error);
+}
+
+int
+sid_to_id(char *sid, boolean_t user, uid_t *id)
+{
char *domain_start;
+ int error = 1;
if ((domain_start = strchr(sid, '@')) == NULL) {
- idmap_rid_t rid;
-
- if ((rid_start = strrchr(sid, '-')) == NULL)
- return (1);
- *rid_start++ = '\0';
- errno = 0;
- rid = strtoul(rid_start--, &end, 10);
- if (errno == 0 && *end == '\0') {
- if (idmap_get_create(&get_hdl) ==
- IDMAP_SUCCESS) {
- if (user)
- error = idmap_get_uidbysid(get_hdl,
- sid, rid, IDMAP_REQ_FLG_USE_CACHE,
- id, &status);
- else
- error = idmap_get_gidbysid(get_hdl,
- sid, rid, IDMAP_REQ_FLG_USE_CACHE,
- id, &status);
- if (error == IDMAP_SUCCESS) {
- error = idmap_get_mappings(get_hdl);
- if (error == IDMAP_SUCCESS &&
- status != IDMAP_SUCCESS)
- error = 1;
- else
- error = 0;
- }
- } else {
- error = 1;
- }
- if (get_hdl)
- idmap_get_destroy(get_hdl);
- } else {
- error = 1;
- }
- *rid_start = '-'; /* putback character removed earlier */
+ error = sid_to_id_impl(sid, user ? UID_TYPE : GID_TYPE,
+ NULL, id);
} else {
char *name = sid;
+ idmap_stat rv;
+
*domain_start++ = '\0';
if (user)
- error = idmap_getuidbywinname(name, domain_start,
+ rv = idmap_getuidbywinname(name, domain_start,
IDMAP_REQ_FLG_USE_CACHE, id);
else
- error = idmap_getgidbywinname(name, domain_start,
+ rv = idmap_getgidbywinname(name, domain_start,
IDMAP_REQ_FLG_USE_CACHE, id);
*--domain_start = '@';
- error = (error == IDMAP_SUCCESS) ? 0 : 1;
+ if (rv == IDMAP_SUCCESS)
+ error = 0;
}
return (error);
@@ -817,42 +848,8 @@ sid_to_id(char *sid, boolean_t user, uid_t *id)
int
sid_to_xid(char *sid, int *is_user, uid_t *id)
{
- idmap_get_handle_t *get_hdl = NULL;
- char *rid_start = NULL;
- char *end;
- idmap_stat status;
- idmap_rid_t rid;
- int error = 1;
-
if ((strchr(sid, '@')) != NULL)
return (1);
- if ((rid_start = strrchr(sid, '-')) == NULL)
- return (1);
- *rid_start++ = '\0';
- errno = 0;
- rid = strtoul(rid_start--, &end, 10);
- if (errno == 0 && *end == '\0') {
- if (idmap_get_create(&get_hdl) == IDMAP_SUCCESS) {
- error = idmap_get_pidbysid(get_hdl,
- sid, rid, IDMAP_REQ_FLG_USE_CACHE,
- id, is_user, &status);
- if (error == IDMAP_SUCCESS) {
- error = idmap_get_mappings(get_hdl);
- if (error == IDMAP_SUCCESS &&
- status != IDMAP_SUCCESS)
- error = 1;
- else
- error = 0;
- }
- } else {
- error = 1;
- }
- if (get_hdl)
- idmap_get_destroy(get_hdl);
- }
-
- *rid_start = '-'; /* putback character removed earlier */
-
- return (error);
+ return (sid_to_id_impl(sid, PID_TYPE, is_user, id));
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_fs.c b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_fs.c
index 381fd7663e..d6da839e05 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_fs.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_fs.c
@@ -11,6 +11,7 @@
/*
* Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
+ * Copyright 2022 RackTop Systems, Inc.
*/
/*
@@ -23,10 +24,6 @@
#include <smbsrv/smb_fsops.h>
#include <smb/winioctl.h>
-/*
- * XXX: Should use smb2_fsctl_invalid in place of smb2_fsctl_notsup
- * but that will require some re-testing.
- */
static uint32_t
smb2_fsctl_invalid(smb_request_t *sr, smb_fsctl_t *fsctl)
{
@@ -40,7 +37,7 @@ smb2_fsctl_notsup(smb_request_t *sr, smb_fsctl_t *fsctl)
}
/*
- * Same as smb2_fsctl_notsup, but make some noise (if DEBUG)
+ * Same as smb2_fsctl_invalid, but make some noise (if DEBUG)
* so we'll learn about new fsctl codes clients start using.
*/
/* ARGSUSED */
@@ -50,7 +47,7 @@ smb2_fsctl_unknown(smb_request_t *sr, smb_fsctl_t *fsctl)
#ifdef DEBUG
cmn_err(CE_NOTE, "smb2_fsctl_unknown: code 0x%x", fsctl->CtlCode);
#endif
- return (NT_STATUS_NOT_SUPPORTED);
+ return (NT_STATUS_INVALID_DEVICE_REQUEST);
}
/*
@@ -145,7 +142,7 @@ smb2_fsctl_fs(smb_request_t *sr, smb_fsctl_t *fsctl)
break;
case FSCTL_SET_REPARSE_POINT: /* 41 */
case FSCTL_GET_REPARSE_POINT: /* 42 */
- func = smb2_fsctl_notsup;
+ func = smb2_fsctl_invalid;
break;
case FSCTL_CREATE_OR_GET_OBJECT_ID: /* 48 */
func = smb2_fsctl_invalid;
@@ -160,7 +157,7 @@ smb2_fsctl_fs(smb_request_t *sr, smb_fsctl_t *fsctl)
func = smb2_fsctl_query_alloc_ranges;
break;
case FSCTL_FILE_LEVEL_TRIM: /* 130 */
- func = smb2_fsctl_notsup;
+ func = smb2_fsctl_invalid;
break;
case FSCTL_OFFLOAD_READ: /* 153 */
func = smb2_fsctl_odx_read;
@@ -168,13 +165,19 @@ smb2_fsctl_fs(smb_request_t *sr, smb_fsctl_t *fsctl)
case FSCTL_OFFLOAD_WRITE: /* 154 */
func = smb2_fsctl_odx_write;
break;
+ case FSCTL_GET_INTEGRITY_INFORMATION: /* 159 */
case FSCTL_SET_INTEGRITY_INFORMATION: /* 160 */
- func = smb2_fsctl_notsup;
+ func = smb2_fsctl_invalid;
break;
case FSCTL_QUERY_FILE_REGIONS: /* 161 */
func = smb2_fsctl_query_file_regions;
break;
+ case FSCTL_REFS_STREAM_SNAPSHOT_MANAGEMENT:
+ /* WPTS wants NOT_SUPPORTED here. */
+ func = smb2_fsctl_notsup;
+ break;
+
default:
func = smb2_fsctl_unknown;
break;
@@ -213,14 +216,14 @@ smb2_fsctl_netfs(smb_request_t *sr, smb_fsctl_t *fsctl)
func = smb2_fsctl_copychunk;
break;
case FSCTL_SRV_READ_HASH: /* 0x6e */
- func = smb2_fsctl_notsup;
+ func = smb2_fsctl_invalid;
break;
case FSCTL_LMR_REQUEST_RESILIENCY: /* 0x75 */
func = smb2_fsctl_set_resilient;
break;
case FSCTL_QUERY_NETWORK_INTERFACE_INFO: /* 0x7f */
need_disk_file = B_FALSE;
- func = smb2_fsctl_notsup;
+ func = smb2_fsctl_invalid;
break;
case FSCTL_VALIDATE_NEGOTIATE_INFO: /* 0x81 */
need_disk_file = B_FALSE;
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
index ebf59f6a59..cc37664ffb 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
@@ -11,6 +11,7 @@
/*
* Copyright 2018-2021 Tintri by DDN, Inc. All rights reserved.
+ * Copyright 2022 RackTop Systems, Inc.
*/
/*
@@ -197,7 +198,7 @@ smb2_fsctl_odx_read(smb_request_t *sr, smb_fsctl_t *fsctl)
int rc;
if (smb2_odx_enable == 0)
- return (NT_STATUS_NOT_SUPPORTED);
+ return (NT_STATUS_INVALID_DEVICE_REQUEST);
/*
* Make sure the (src) ofile granted access allows read.
@@ -391,7 +392,7 @@ smb2_fsctl_odx_write(smb_request_t *sr, smb_fsctl_t *fsctl)
args.out_struct_size = 16;
if (smb2_odx_enable == 0)
- return (NT_STATUS_NOT_SUPPORTED);
+ return (NT_STATUS_INVALID_DEVICE_REQUEST);
/*
* Make sure the (dst) ofile granted_access allows write.
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c b/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c
index 7d67247588..473115e179 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c
@@ -11,7 +11,7 @@
/*
* Copyright 2019 Nexenta Systems, Inc. All rights reserved.
- * Copyright 2021 RackTop Systems, Inc.
+ * Copyright 2022 RackTop Systems, Inc.
*/
/*
@@ -22,6 +22,14 @@
#include <smbsrv/smb2.h>
#include <sys/random.h>
+/*
+ * Note from [MS-SMB2] Sec. 2.2.3: Windows servers return
+ * invalid parameter if the dialect count is greater than 64
+ * This is here (and not in smb2.h) because this is technically
+ * an implementation detail, not protocol specification.
+ */
+#define SMB2_NEGOTIATE_MAX_DIALECTS 64
+
static int smb2_negotiate_common(smb_request_t *, uint16_t);
/* List of supported capabilities. Can be patched for testing. */
@@ -83,127 +91,6 @@ static uint16_t smb2_versions[] = {
static uint16_t smb2_nversions =
sizeof (smb2_versions) / sizeof (smb2_versions[0]);
-static boolean_t
-smb2_supported_version(smb_session_t *s, uint16_t version)
-{
- int i;
-
- if (version > s->s_cfg.skc_max_protocol ||
- version < s->s_cfg.skc_min_protocol)
- return (B_FALSE);
- for (i = 0; i < smb2_nversions; i++)
- if (version == smb2_versions[i])
- return (B_TRUE);
- return (B_FALSE);
-}
-
-/*
- * Helper for the (SMB1) smb_com_negotiate(). This is the
- * very unusual protocol interaction where an SMB1 negotiate
- * gets an SMB2 negotiate response. This is the normal way
- * clients first find out if the server supports SMB2.
- *
- * Note: This sends an SMB2 reply _itself_ and then returns
- * SDRC_NO_REPLY so the caller will not send an SMB1 reply.
- * Also, this is called directly from the reader thread, so
- * we know this is the only thread using this session.
- *
- * The caller frees this request.
- */
-smb_sdrc_t
-smb1_negotiate_smb2(smb_request_t *sr)
-{
- smb_session_t *s = sr->session;
- smb_arg_negotiate_t *negprot = sr->sr_negprot;
- uint16_t smb2_version;
-
- /*
- * Note: In the SMB1 negotiate command handler, we
- * agreed with one of the SMB2 dialects. If that
- * dialect was "SMB 2.002", we'll respond here with
- * version 0x202 and negotiation is done. If that
- * dialect was "SMB 2.???", we'll respond here with
- * the "wildcard" version 0x2FF, and the client will
- * come back with an SMB2 negotiate.
- */
- switch (negprot->ni_dialect) {
- case DIALECT_SMB2002: /* SMB 2.002 (a.k.a. SMB2.0) */
- smb2_version = SMB_VERS_2_002;
- s->dialect = smb2_version;
- s->s_state = SMB_SESSION_STATE_NEGOTIATED;
- /* Allow normal SMB2 requests now. */
- s->newrq_func = smb2sr_newrq;
- break;
- case DIALECT_SMB2XXX: /* SMB 2.??? (wildcard vers) */
- /*
- * Expecting an SMB2 negotiate next, so keep the
- * initial s->newrq_func.
- */
- smb2_version = 0x2FF;
- break;
- default:
- return (SDRC_DROP_VC);
- }
-
- /*
- * We did not decode an SMB2 header, so make sure
- * the SMB2 header fields are initialized.
- * (Most are zero from smb_request_alloc.)
- * Also, the SMB1 common dispatch code reserved space
- * for an SMB1 header, which we need to undo here.
- */
- sr->smb2_reply_hdr = sr->reply.chain_offset = 0;
- sr->smb2_cmd_code = SMB2_NEGOTIATE;
- sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
-
- (void) smb2_encode_header(sr, B_FALSE);
- if (smb2_negotiate_common(sr, smb2_version) != 0)
- sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
- if (sr->smb2_status != 0)
- smb2sr_put_error(sr, sr->smb2_status);
- (void) smb2_encode_header(sr, B_TRUE);
-
- smb2_send_reply(sr);
-
- /*
- * We sent the reply, so tell the SMB1 dispatch
- * it should NOT (also) send a reply.
- */
- return (SDRC_NO_REPLY);
-}
-
-static uint16_t
-smb2_find_best_dialect(smb_session_t *s, uint16_t cl_versions[],
- uint16_t version_cnt)
-{
- uint16_t best_version = 0;
- int i;
-
- for (i = 0; i < version_cnt; i++)
- if (smb2_supported_version(s, cl_versions[i]) &&
- best_version < cl_versions[i])
- best_version = cl_versions[i];
-
- return (best_version);
-}
-
-/*
- * SMB2 Negotiate gets special handling. This is called directly by
- * the reader thread (see smbsr_newrq_initial) with what _should_ be
- * an SMB2 Negotiate. Only the "\feSMB" header has been checked
- * when this is called, so this needs to check the SMB command,
- * if it's Negotiate execute it, then send the reply, etc.
- *
- * Since this is called directly from the reader thread, we
- * know this is the only thread currently using this session.
- * This has to duplicate some of what smb2sr_work does as a
- * result of bypassing the normal dispatch mechanism.
- *
- * The caller always frees this request.
- *
- * Return value is 0 for success, and anything else will
- * terminate the reader thread (drop the connection).
- */
enum smb2_neg_ctx_type {
SMB2_PREAUTH_INTEGRITY_CAPS = 1,
SMB2_ENCRYPTION_CAPS = 2,
@@ -272,6 +159,44 @@ typedef struct smb2_neg_ctxs {
#define SMB3_CIPHER_ENABLED(c, f) ((c) <= SMB3_CIPHER_MAX && \
SMB3_CIPHER_BIT(c) & (f))
+typedef struct smb2_arg_negotiate {
+ struct smb2_neg_ctxs neg_in_ctxs;
+ struct smb2_neg_ctxs neg_out_ctxs;
+ uint16_t neg_dialect_cnt;
+ uint16_t neg_dialects[SMB2_NEGOTIATE_MAX_DIALECTS];
+ uint16_t neg_highest_dialect;
+} smb2_arg_negotiate_t;
+
+
+static boolean_t
+smb2_supported_version(smb_session_t *s, uint16_t version)
+{
+ int i;
+
+ if (version > s->s_cfg.skc_max_protocol ||
+ version < s->s_cfg.skc_min_protocol)
+ return (B_FALSE);
+ for (i = 0; i < smb2_nversions; i++)
+ if (version == smb2_versions[i])
+ return (B_TRUE);
+ return (B_FALSE);
+}
+
+static uint16_t
+smb2_find_best_dialect(smb_session_t *s, uint16_t cl_versions[],
+ uint16_t version_cnt)
+{
+ uint16_t best_version = 0;
+ int i;
+
+ for (i = 0; i < version_cnt; i++)
+ if (smb2_supported_version(s, cl_versions[i]) &&
+ best_version < cl_versions[i])
+ best_version = cl_versions[i];
+
+ return (best_version);
+}
+
/*
* This function should be called only for dialect >= 0x311
* Negotiate context list should contain exactly one
@@ -281,9 +206,11 @@ typedef struct smb2_neg_ctxs {
* Otehrwise STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP.
*/
static uint32_t
-smb31_decode_neg_ctxs(smb_request_t *sr, smb2_neg_ctxs_t *neg_ctxs)
+smb31_decode_neg_ctxs(smb_request_t *sr)
{
smb_session_t *s = sr->session;
+ smb2_arg_negotiate_t *nego = sr->arg.other;
+ smb2_neg_ctxs_t *neg_ctxs = &nego->neg_in_ctxs;
smb2_preauth_caps_t *picap = &neg_ctxs->preauth_ctx.preauth_caps;
smb2_encrypt_caps_t *encap = &neg_ctxs->encrypt_ctx.encrypt_caps;
boolean_t found_sha512 = B_FALSE;
@@ -296,15 +223,6 @@ smb31_decode_neg_ctxs(smb_request_t *sr, smb2_neg_ctxs_t *neg_ctxs)
int cnt, i;
int rc;
- sr->command.chain_offset = NEG_CTX_INFO_OFFSET;
-
- rc = smb_mbc_decodef(&sr->command, "lw2.",
- &neg_ctxs->offset, /* l */
- &neg_ctxs->count); /* w */
- if (rc != 0) {
- status = NT_STATUS_INVALID_PARAMETER;
- goto errout;
- }
/*
* There should be exactly 1 SMB2_PREAUTH_INTEGRITY_CAPS negotiate ctx.
* SMB2_ENCRYPTION_CAPS is optional one.
@@ -497,9 +415,11 @@ errout:
}
static int
-smb31_encode_neg_ctxs(smb_request_t *sr, smb2_neg_ctxs_t *neg_ctxs)
+smb31_encode_neg_ctxs(smb_request_t *sr)
{
smb_session_t *s = sr->session;
+ smb2_arg_negotiate_t *nego = sr->arg.other;
+ smb2_neg_ctxs_t *neg_ctxs = &nego->neg_out_ctxs;
smb2_preauth_caps_t *picap = &neg_ctxs->preauth_ctx.preauth_caps;
smb2_encrypt_caps_t *encap = &neg_ctxs->encrypt_ctx.encrypt_caps;
uint16_t salt_len = sizeof (picap->picap_salt);
@@ -561,20 +481,121 @@ smb31_encode_neg_ctxs(smb_request_t *sr, smb2_neg_ctxs_t *neg_ctxs)
return (rc);
}
+/*
+ * Helper for the (SMB1) smb_com_negotiate(). This is the
+ * very unusual protocol interaction where an SMB1 negotiate
+ * gets an SMB2 negotiate response. This is the normal way
+ * clients first find out if the server supports SMB2.
+ *
+ * Note: This sends an SMB2 reply _itself_ and then returns
+ * SDRC_NO_REPLY so the caller will not send an SMB1 reply.
+ * Also, this is called directly from the reader thread, so
+ * we know this is the only thread using this session.
+ * Otherwise, this is similar to smb2_newrq_negotiate().
+ *
+ * The caller frees this request.
+ */
+smb_sdrc_t
+smb1_negotiate_smb2(smb_request_t *sr)
+{
+ smb_session_t *s = sr->session;
+ smb_arg_negotiate_t *negprot = sr->sr_negprot;
+ uint16_t smb2_version;
+
+ /*
+ * Note: In the SMB1 negotiate command handler, we
+ * agreed with one of the SMB2 dialects. If that
+ * dialect was "SMB 2.002", we'll respond here with
+ * version 0x202 and negotiation is done. If that
+ * dialect was "SMB 2.???", we'll respond here with
+ * the "wildcard" version 0x2FF, and the client will
+ * come back with an SMB2 negotiate.
+ */
+ switch (negprot->ni_dialect) {
+ case DIALECT_SMB2002: /* SMB 2.002 (a.k.a. SMB2.0) */
+ smb2_version = SMB_VERS_2_002;
+ s->dialect = smb2_version;
+ s->s_state = SMB_SESSION_STATE_NEGOTIATED;
+ /* Allow normal SMB2 requests now. */
+ s->newrq_func = smb2sr_newrq;
+ break;
+ case DIALECT_SMB2XXX: /* SMB 2.??? (wildcard vers) */
+ /*
+ * Expecting an SMB2 negotiate next, so keep the
+ * initial s->newrq_func.
+ */
+ smb2_version = 0x2FF;
+ break;
+ default:
+ return (SDRC_DROP_VC);
+ }
+
+ /*
+ * We did not decode an SMB2 header, so make sure
+ * the SMB2 header fields are initialized.
+ * (Most are zero from smb_request_alloc.)
+ * Also, the SMB1 common dispatch code reserved space
+ * for an SMB1 header, which we need to undo here.
+ */
+ sr->smb2_reply_hdr = sr->reply.chain_offset = 0;
+ sr->smb2_cmd_code = SMB2_NEGOTIATE;
+ sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
+
+ /*
+ * Also setup SMB2 negotiate args (empty here).
+ * SMB1 args free'd by smb_srm_fini(sr)
+ */
+ sr->arg.other = smb_srm_zalloc(sr, sizeof (smb2_arg_negotiate_t));
+
+ (void) smb2_encode_header(sr, B_FALSE);
+ if (smb2_negotiate_common(sr, smb2_version) != 0)
+ sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
+ if (sr->smb2_status != 0)
+ smb2sr_put_error(sr, sr->smb2_status);
+ (void) smb2_encode_header(sr, B_TRUE);
+
+ smb2_send_reply(sr);
+
+ /*
+ * We sent the reply, so tell the SMB1 dispatch
+ * it should NOT (also) send a reply.
+ */
+ return (SDRC_NO_REPLY);
+}
+
+/*
+ * SMB2 Negotiate gets special handling. This is called directly by
+ * the reader thread (see smbsr_newrq_initial) with what _should_ be
+ * an SMB2 Negotiate. Only the "\feSMB" header has been checked
+ * when this is called, so this needs to check the SMB command,
+ * if it's Negotiate execute it, then send the reply, etc.
+ *
+ * Since this is called directly from the reader thread, we
+ * know this is the only thread currently using this session.
+ * This has to duplicate some of what smb2sr_work does as a
+ * result of bypassing the normal dispatch mechanism.
+ *
+ * The caller always frees this request.
+ *
+ * Return value is 0 for success, and anything else will
+ * terminate the reader thread (drop the connection).
+ */
int
smb2_newrq_negotiate(smb_request_t *sr)
{
smb_session_t *s = sr->session;
- smb2_neg_ctxs_t neg_in_ctxs;
- smb2_neg_ctxs_t neg_out_ctxs;
- smb2_arg_negotiate_t *nego2 = &sr->sr_nego2;
+ smb2_arg_negotiate_t *nego;
int rc;
+ uint32_t nctx_status = 0;
uint32_t status = 0;
+ uint32_t neg_ctx_off;
+ uint16_t neg_ctx_cnt;
uint16_t struct_size;
+ uint16_t dialect_cnt;
uint16_t best_version;
- bzero(&neg_in_ctxs, sizeof (neg_in_ctxs));
- bzero(&neg_out_ctxs, sizeof (neg_out_ctxs));
+ nego = smb_srm_zalloc(sr, sizeof (smb2_arg_negotiate_t));
+ sr->arg.other = nego; // for dtrace
sr->smb2_cmd_hdr = sr->command.chain_offset;
rc = smb2_decode_header(sr);
@@ -592,14 +613,16 @@ smb2_newrq_negotiate(smb_request_t *sr)
* Decode SMB2 Negotiate (fixed-size part)
*/
rc = smb_mbc_decodef(
- &sr->command, "www..l16c8.",
+ &sr->command, "www..l16clw..",
&struct_size, /* w */
- &s->cli_dialect_cnt, /* w */
+ &dialect_cnt, /* w */
&s->cli_secmode, /* w */
/* reserved (..) */
&s->capabilities, /* l */
- s->clnt_uuid); /* 16c */
- /* start_time 8. */
+ s->clnt_uuid, /* 16c */
+ &neg_ctx_off, /* l */
+ &neg_ctx_cnt); /* w */
+ /* reserverd (..) */
if (rc != 0)
return (rc);
if (struct_size != 36)
@@ -611,56 +634,40 @@ smb2_newrq_negotiate(smb_request_t *sr)
* Be somewhat tolerant while decoding the variable part
* so we can return errors instead of dropping the client.
* Will limit decoding to the size of cli_dialects here,
- * and do the error checks on s->cli_dialect_cnt after the
+ * and do error checks on the decoded dialect_cnt after the
* dtrace start probe.
*/
- if (s->cli_dialect_cnt > 0 &&
- s->cli_dialect_cnt <= SMB2_NEGOTIATE_MAX_DIALECTS &&
- smb_mbc_decodef(&sr->command, "#w", s->cli_dialect_cnt,
- s->cli_dialects) != 0) {
- /* decode error; force an error below */
- s->cli_dialect_cnt = 0;
- }
-
- /*
- * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
- * "If the DialectCount of the SMB2 NEGOTIATE Request is 0, the
- * server MUST fail the request with STATUS_INVALID_PARAMETER."
- */
- if (s->cli_dialect_cnt == 0 ||
- s->cli_dialect_cnt > SMB2_NEGOTIATE_MAX_DIALECTS) {
- status = NT_STATUS_INVALID_PARAMETER;
+ if (dialect_cnt > SMB2_NEGOTIATE_MAX_DIALECTS)
+ nego->neg_dialect_cnt = SMB2_NEGOTIATE_MAX_DIALECTS;
+ else
+ nego->neg_dialect_cnt = dialect_cnt;
+ if (nego->neg_dialect_cnt > 0) {
+ rc = smb_mbc_decodef(&sr->command, "#w",
+ nego->neg_dialect_cnt,
+ nego->neg_dialects);
+ if (rc != 0)
+ return (rc); // short msg
}
- /*
- * The client offers an array of protocol versions it
- * supports, which we have decoded into s->cli_dialects[].
- * We walk the array and pick the highest supported.
- *
- * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
- * "If a common dialect is not found, the server MUST fail
- * the request with STATUS_NOT_SUPPORTED."
- */
+ best_version = smb2_find_best_dialect(s, nego->neg_dialects,
+ nego->neg_dialect_cnt);
- if (status == 0) {
- best_version = smb2_find_best_dialect(s, s->cli_dialects,
- s->cli_dialect_cnt);
- if (best_version >= SMB_VERS_3_11) {
- status = smb31_decode_neg_ctxs(sr, &neg_in_ctxs);
- nego2->neg_in_ctxs = &neg_in_ctxs;
- } else if (best_version == 0) {
- status = NT_STATUS_NOT_SUPPORTED;
- }
+ if (best_version >= SMB_VERS_3_11) {
+ nego->neg_in_ctxs.offset = neg_ctx_off;
+ nego->neg_in_ctxs.count = neg_ctx_cnt;
+ nctx_status = smb31_decode_neg_ctxs(sr);
+ /* check nctx_status below */
}
DTRACE_SMB2_START(op__Negotiate, smb_request_t *, sr);
- nego2->neg_in_ctxs = NULL;
+ sr->smb2_credit_response = 1;
sr->smb2_hdr_flags |= SMB2_FLAGS_SERVER_TO_REDIR;
(void) smb2_encode_header(sr, B_FALSE);
- if (status != 0)
- goto errout;
+ /*
+ * NOW start validating things (NOT before here)
+ */
/*
* [MS-SMB2] 3.3.5.2.4 Verifying the Signature
@@ -674,9 +681,41 @@ smb2_newrq_negotiate(smb_request_t *sr)
goto errout;
}
- s->dialect = best_version;
+ /*
+ * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
+ * "If the DialectCount of the SMB2 NEGOTIATE Request is 0, the
+ * server MUST fail the request with STATUS_INVALID_PARAMETER."
+ * Checking the decoded value here, not the constrained one.
+ */
+ if (dialect_cnt == 0 ||
+ dialect_cnt > SMB2_NEGOTIATE_MAX_DIALECTS) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto errout;
+ }
+
+ /*
+ * We decoded the offered dialects above, and
+ * determined which was the highest we support.
+ *
+ * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
+ * "If a common dialect is not found, the server MUST fail
+ * the request with STATUS_NOT_SUPPORTED."
+ */
+ if (best_version == 0) {
+ status = NT_STATUS_NOT_SUPPORTED;
+ goto errout;
+ }
+
+ /*
+ * Check for problems with the negotiate contexts.
+ */
+ if (nctx_status != 0) {
+ status = nctx_status;
+ goto errout;
+ }
/* Allow normal SMB2 requests now. */
+ s->dialect = best_version;
s->s_state = SMB_SESSION_STATE_NEGOTIATED;
s->newrq_func = smb2sr_newrq;
@@ -684,15 +723,13 @@ smb2_newrq_negotiate(smb_request_t *sr)
status = NT_STATUS_INTERNAL_ERROR;
if (s->dialect >= SMB_VERS_3_11 && status == 0) {
- if (smb31_encode_neg_ctxs(sr, &neg_out_ctxs) != 0)
+ if (smb31_encode_neg_ctxs(sr) != 0)
status = NT_STATUS_INTERNAL_ERROR;
- nego2->neg_out_ctxs = &neg_out_ctxs;
}
errout:
sr->smb2_status = status;
DTRACE_SMB2_DONE(op__Negotiate, smb_request_t *, sr);
- nego2->neg_out_ctxs = NULL;
if (sr->smb2_status != 0)
smb2sr_put_error(sr, sr->smb2_status);
@@ -869,7 +906,6 @@ uint32_t
smb2_nego_validate(smb_request_t *sr, smb_fsctl_t *fsctl)
{
smb_session_t *s = sr->session;
- boolean_t smb311 = s->s_cfg.skc_max_protocol >= SMB_VERS_3_11;
int rc;
/*
@@ -911,8 +947,6 @@ smb2_nego_validate(smb_request_t *sr, smb_fsctl_t *fsctl)
if (num_dialects == 0 || num_dialects > SMB2_NEGOTIATE_MAX_DIALECTS)
goto drop;
- if (smb311 && num_dialects != s->cli_dialect_cnt)
- goto drop;
if (secmode != s->cli_secmode)
goto drop;
if (capabilities != s->capabilities)
@@ -920,23 +954,17 @@ smb2_nego_validate(smb_request_t *sr, smb_fsctl_t *fsctl)
if (memcmp(clnt_guid, s->clnt_uuid, sizeof (clnt_guid)) != 0)
goto drop;
- if (fsctl->InputCount < (24 + num_dialects * sizeof (*dialects)))
- goto drop;
-
rc = smb_mbc_decodef(fsctl->in_mbc, "#w", num_dialects, dialects);
if (rc != 0)
goto drop;
- if (smb311) {
- for (int i = 0; i < num_dialects; i++) {
- if (dialects[i] != s->cli_dialects[i])
- goto drop;
- }
- } else {
- if (smb2_find_best_dialect(s, dialects, num_dialects) !=
- s->dialect)
- goto drop;
- }
+ /*
+ * MS-SMB2 says we should compare the dialects array with the
+ * one sent previously, but that appears to be unnecessary
+ * as long as we end up with the same dialect.
+ */
+ if (smb2_find_best_dialect(s, dialects, num_dialects) != s->dialect)
+ goto drop;
rc = smb_mbc_encodef(
fsctl->out_mbc, "l#cww",
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_qinfo_quota.c b/usr/src/uts/common/fs/smbsrv/smb2_qinfo_quota.c
index da2b0176b8..496c6fe414 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_qinfo_quota.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_qinfo_quota.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2022 RackTop Systems, Inc.
*/
/*
@@ -32,6 +33,15 @@
#include <smbsrv/smb_fsops.h>
#include <smbsrv/ntifs.h>
+/*
+ * MS-FSA 2.1.5.20 Server Requests Querying Quota Information
+ *
+ * Support for this operation is optional. If the object store does not
+ * implement this functionality, the operation MUST be failed with
+ * STATUS_INVALID_DEVICE_REQUEST
+ *
+ * Similar to smb_nt_transact_query_quota()
+ */
uint32_t
smb2_qinfo_quota(smb_request_t *sr, smb_queryinfo_t *qi)
{
@@ -49,11 +59,11 @@ smb2_qinfo_quota(smb_request_t *sr, smb_queryinfo_t *qi)
bzero(&reply, sizeof (smb_quota_response_t));
if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA))
- return (NT_STATUS_NOT_SUPPORTED);
+ return (NT_STATUS_INVALID_DEVICE_REQUEST);
if ((ofile->f_node == NULL) ||
(ofile->f_ftype != SMB_FTYPE_DISK))
- return (NT_STATUS_NOT_SUPPORTED);
+ return (NT_STATUS_INVALID_DEVICE_REQUEST);
rc = smb_mbc_decodef(
&sr->smb_data, "bb..lll",
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_setinfo_quota.c b/usr/src/uts/common/fs/smbsrv/smb2_setinfo_quota.c
index bdeda05ba7..6dcf0112b3 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_setinfo_quota.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_setinfo_quota.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2022 RackTop Systems, Inc.
*/
/*
@@ -33,6 +34,12 @@
#include <smbsrv/ntifs.h>
/*
+ * MS-FSA 2.1.5.21 Server Requests Setting Quota Information
+ *
+ * Support for this operation is optional. If the object store does not
+ * implement this functionality, the operation MUST be failed with
+ * STATUS_INVALID_DEVICE_REQUEST
+ *
* Similar to smb_nt_transact_set_quota()
*/
uint32_t
@@ -44,18 +51,18 @@ smb2_setinfo_quota(smb_request_t *sr, smb_setinfo_t *si)
smb_node_t *tnode;
smb_quota_set_t request;
uint32_t reply;
- list_t *quota_list;
+ list_t *quota_list;
bzero(&request, sizeof (smb_quota_set_t));
if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA))
- return (NT_STATUS_NOT_SUPPORTED);
-
- if (!smb_user_is_admin(sr->uid_user))
- return (NT_STATUS_ACCESS_DENIED);
+ return (NT_STATUS_INVALID_DEVICE_REQUEST);
if ((ofile->f_node == NULL) ||
(ofile->f_ftype != SMB_FTYPE_DISK))
+ return (NT_STATUS_INVALID_DEVICE_REQUEST);
+
+ if (!smb_user_is_admin(sr->uid_user))
return (NT_STATUS_ACCESS_DENIED);
tnode = sr->tid_tree->t_snode;
diff --git a/usr/src/uts/common/smb/winioctl.h b/usr/src/uts/common/smb/winioctl.h
index 0f322cc4ef..a991841b4e 100644
--- a/usr/src/uts/common/smb/winioctl.h
+++ b/usr/src/uts/common/smb/winioctl.h
@@ -23,6 +23,7 @@
* Use is subject to license terms.
*
* Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2022 RackTop Systems, Inc.
*/
#ifndef _SMB_WINIOCTL_H
#define _SMB_WINIOCTL_H
@@ -483,6 +484,9 @@ extern "C" {
#define FSCTL_QUERY_FILE_REGIONS \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 161, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_REFS_STREAM_SNAPSHOT_MANAGEMENT \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 272, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
/* FILE_DEVICE_NETWORK_FILE_SYSTEM */
/* Read the snapshot info for Volume Shadow Copy Services */
#define FSCTL_SRV_ENUMERATE_SNAPSHOTS \
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index 89b057ff91..a220faef6b 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -730,11 +730,6 @@ typedef struct smb_arg_negotiate {
timestruc_t ni_servertime;
} smb_arg_negotiate_t;
-typedef struct smb2_arg_negotiate {
- struct smb2_neg_ctxs *neg_in_ctxs;
- struct smb2_neg_ctxs *neg_out_ctxs;
-} smb2_arg_negotiate_t;
-
typedef enum {
SMB_SSNSETUP_PRE_NTLM012 = 1,
SMB_SSNSETUP_NTLM012_NOEXT,
@@ -911,8 +906,6 @@ typedef enum {
#define SMB_SSN_AAPL_CCEXT 1 /* Saw "AAPL" create ctx. ext. */
#define SMB_SSN_AAPL_READDIR 2 /* Wants MacOS ext. readdir */
-#define SMB2_NEGOTIATE_MAX_DIALECTS 64
-
typedef struct smb_session {
list_node_t s_lnd;
uint32_t s_magic;
@@ -977,11 +970,6 @@ typedef struct smb_session {
timeout_id_t s_auth_tmo;
/*
- * Client dialects
- */
- uint16_t cli_dialect_cnt;
- uint16_t cli_dialects[SMB2_NEGOTIATE_MAX_DIALECTS];
- /*
* Maximum negotiated buffer sizes between SMB client and server
* in SMB_SESSION_SETUP_ANDX
*/
@@ -1925,7 +1913,6 @@ typedef struct smb_request {
uint32_t sr_seqnum;
union {
- smb2_arg_negotiate_t nego2;
smb_arg_negotiate_t *negprot;
smb_arg_sessionsetup_t *ssetup;
smb_arg_tcon_t tcon;
@@ -1941,7 +1928,6 @@ typedef struct smb_request {
#define sr_ssetup arg.ssetup
#define sr_negprot arg.negprot
-#define sr_nego2 arg.nego2
#define sr_tcon arg.tcon
#define sr_dirop arg.dirop
#define sr_open arg.open