1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross * This file and its contents are supplied under the terms of the
3a90cf9f2SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0.
4a90cf9f2SGordon Ross * You may only use this file in accordance with the terms of version
5a90cf9f2SGordon Ross * 1.0 of the CDDL.
6a90cf9f2SGordon Ross *
7a90cf9f2SGordon Ross * A full copy of the text of the CDDL should have accompanied this
8a90cf9f2SGordon Ross * source. A copy of the CDDL is also available via the Internet at
9a90cf9f2SGordon Ross * http://www.illumos.org/license/CDDL.
10a90cf9f2SGordon Ross */
11a90cf9f2SGordon Ross
12a90cf9f2SGordon Ross /*
13*3e739001SGordon Ross * Copyright 2013-2021 Tintri by DDN, Inc. All rights reserved.
14b716e3d0SGordon Ross * Copyright 2022 RackTop Systems, Inc.
15a90cf9f2SGordon Ross */
16a90cf9f2SGordon Ross
17a90cf9f2SGordon Ross /*
18a90cf9f2SGordon Ross * Dispatch function for SMB2_NEGOTIATE
19a90cf9f2SGordon Ross */
20a90cf9f2SGordon Ross
21a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
22a90cf9f2SGordon Ross #include <smbsrv/smb2.h>
234e065a9fSAlexander Stetsenko #include <sys/random.h>
24ebc5aadbSAndrew Stormont
25b716e3d0SGordon Ross /*
26b716e3d0SGordon Ross * Note from [MS-SMB2] Sec. 2.2.3: Windows servers return
27b716e3d0SGordon Ross * invalid parameter if the dialect count is greater than 64
28b716e3d0SGordon Ross * This is here (and not in smb2.h) because this is technically
29b716e3d0SGordon Ross * an implementation detail, not protocol specification.
30b716e3d0SGordon Ross */
31b716e3d0SGordon Ross #define SMB2_NEGOTIATE_MAX_DIALECTS 64
32b716e3d0SGordon Ross
33a90cf9f2SGordon Ross static int smb2_negotiate_common(smb_request_t *, uint16_t);
34a90cf9f2SGordon Ross
35700daa96SAndrew Stormont /* List of supported capabilities. Can be patched for testing. */
36a90cf9f2SGordon Ross uint32_t smb2srv_capabilities =
37a90cf9f2SGordon Ross SMB2_CAP_DFS |
3894047d49SGordon Ross SMB2_CAP_LEASING |
391160dcf7SMatt Barden SMB2_CAP_LARGE_MTU |
408d94f651SGordon Ross SMB2_CAP_PERSISTENT_HANDLES |
414f0ce1daSGordon Ross SMB2_CAP_ENCRYPTION;
42a90cf9f2SGordon Ross
438d94f651SGordon Ross /* These are the only capabilities defined for SMB2.X */
448d94f651SGordon Ross #define SMB_2X_CAPS (SMB2_CAP_DFS | SMB2_CAP_LEASING | SMB2_CAP_LARGE_MTU)
458d94f651SGordon Ross
46a90cf9f2SGordon Ross /*
47a90cf9f2SGordon Ross * These are not intended as customer tunables, but dev. & test folks
48a90cf9f2SGordon Ross * might want to adjust them (with caution).
49a90cf9f2SGordon Ross *
50a90cf9f2SGordon Ross * smb2_tcp_bufsize is the TCP buffer size, applied to the network socket
51a90cf9f2SGordon Ross * with setsockopt SO_SNDBUF, SO_RCVBUF. These set the TCP window size.
52a90cf9f2SGordon Ross * This is also used as a "sanity limit" for internal send/reply message
53a90cf9f2SGordon Ross * allocations. Note that with compounding SMB2 messages may contain
54a90cf9f2SGordon Ross * multiple requests/responses. This size should be large enough for
55a90cf9f2SGordon Ross * at least a few SMB2 requests, and at least 2X smb2_max_rwsize.
56a90cf9f2SGordon Ross *
57a90cf9f2SGordon Ross * smb2_max_rwsize is what we put in the SMB2 negotiate response to tell
58a90cf9f2SGordon Ross * the client the largest read and write request size we'll support.
59*3e739001SGordon Ross * One megabyte is a compromise between efficiency on fast networks
60*3e739001SGordon Ross * and memory consumption (for the buffers) on the server side.
61a90cf9f2SGordon Ross *
62a90cf9f2SGordon Ross * smb2_max_trans is the largest "transact" send or receive, which is
63a90cf9f2SGordon Ross * used for directory listings and info set/get operations.
64a90cf9f2SGordon Ross */
65a90cf9f2SGordon Ross uint32_t smb2_tcp_bufsize = (1<<22); /* 4MB */
66*3e739001SGordon Ross uint32_t smb2_max_rwsize = (1<<20); /* 1MB */
67a90cf9f2SGordon Ross uint32_t smb2_max_trans = (1<<16); /* 64KB */
68a90cf9f2SGordon Ross
69a90cf9f2SGordon Ross /*
70aa321b3cSDan McDonald * With clients (e.g. HP scanners) that don't advertise SMB2_CAP_LARGE_MTU
71aa321b3cSDan McDonald * (including all clients using dialect < SMB 2.1), use a "conservative" value
72aa321b3cSDan McDonald * for max r/w size because some older clients misbehave with larger values.
73aa321b3cSDan McDonald * 64KB is recommended in the [MS-SMB2] spec. (3.3.5.3.1 SMB 2.1 or SMB 3.x
74aa321b3cSDan McDonald * Support) as the minimum so we'll use that.
75aa321b3cSDan McDonald */
76aa321b3cSDan McDonald uint32_t smb2_old_rwsize = (1<<16); /* 64KB */
77aa321b3cSDan McDonald
78aa321b3cSDan McDonald /*
79a90cf9f2SGordon Ross * List of all SMB2 versions we implement. Note that the
803e2c0c09SMatt Barden * versions we support may be limited by the
813e2c0c09SMatt Barden * _cfg.skc_max_protocol and min_protocol settings.
82a90cf9f2SGordon Ross */
83a90cf9f2SGordon Ross static uint16_t smb2_versions[] = {
84a90cf9f2SGordon Ross 0x202, /* SMB 2.002 */
85a90cf9f2SGordon Ross 0x210, /* SMB 2.1 */
86c51c88bdSMatt Barden 0x300, /* SMB 3.0 */
87dfa42fabSMatt Barden 0x302, /* SMB 3.02 */
884e065a9fSAlexander Stetsenko 0x311, /* SMB 3.11 */
89a90cf9f2SGordon Ross };
90a90cf9f2SGordon Ross static uint16_t smb2_nversions =
91a90cf9f2SGordon Ross sizeof (smb2_versions) / sizeof (smb2_versions[0]);
92a90cf9f2SGordon Ross
934e065a9fSAlexander Stetsenko enum smb2_neg_ctx_type {
944e065a9fSAlexander Stetsenko SMB2_PREAUTH_INTEGRITY_CAPS = 1,
954e065a9fSAlexander Stetsenko SMB2_ENCRYPTION_CAPS = 2,
964e065a9fSAlexander Stetsenko SMB2_COMPRESSION_CAPS = 3, /* not imlemented */
974e065a9fSAlexander Stetsenko SMB2_NETNAME_NEGOTIATE_CONTEXT_ID = 5 /* not imlemented */
984e065a9fSAlexander Stetsenko };
994e065a9fSAlexander Stetsenko
1004e065a9fSAlexander Stetsenko typedef struct smb2_negotiate_ctx {
1014e065a9fSAlexander Stetsenko uint16_t type;
1024e065a9fSAlexander Stetsenko uint16_t datalen;
1034e065a9fSAlexander Stetsenko } smb2_neg_ctx_t;
1044e065a9fSAlexander Stetsenko
1054e065a9fSAlexander Stetsenko #define SMB31_PREAUTH_CTX_SALT_LEN 32
1064e065a9fSAlexander Stetsenko
1074e065a9fSAlexander Stetsenko /*
10874e3b2c7SAndy Fiddaman * SMB 3.1.1 originally specified a single hashing algorithm - SHA-512 - and
1094e065a9fSAlexander Stetsenko * two encryption ones - AES-128-CCM and AES-128-GCM.
11074e3b2c7SAndy Fiddaman * Windows Server 2022 and Windows 11 introduced two further encryption
11174e3b2c7SAndy Fiddaman * algorithms - AES-256-CCM and AES-256-GCM.
1124e065a9fSAlexander Stetsenko */
1134e065a9fSAlexander Stetsenko #define MAX_HASHID_NUM (1)
114a4568e19SAlexander Stetsenko #define MAX_CIPHER_NUM (8)
1154e065a9fSAlexander Stetsenko
1164e065a9fSAlexander Stetsenko typedef struct smb2_preauth_integrity_caps {
1174e065a9fSAlexander Stetsenko uint16_t picap_hash_count;
1184e065a9fSAlexander Stetsenko uint16_t picap_salt_len;
1194e065a9fSAlexander Stetsenko uint16_t picap_hash_id;
1204e065a9fSAlexander Stetsenko uint8_t picap_salt[SMB31_PREAUTH_CTX_SALT_LEN];
1214e065a9fSAlexander Stetsenko } smb2_preauth_caps_t;
1224e065a9fSAlexander Stetsenko
1234e065a9fSAlexander Stetsenko typedef struct smb2_encryption_caps {
1244e065a9fSAlexander Stetsenko uint16_t encap_cipher_count;
1254e065a9fSAlexander Stetsenko uint16_t encap_cipher_ids[MAX_CIPHER_NUM];
1264e065a9fSAlexander Stetsenko } smb2_encrypt_caps_t;
1274e065a9fSAlexander Stetsenko
1284e065a9fSAlexander Stetsenko /*
1294e065a9fSAlexander Stetsenko * The contexts we support
1304e065a9fSAlexander Stetsenko */
1314e065a9fSAlexander Stetsenko typedef struct smb2_preauth_neg_ctx {
1324e065a9fSAlexander Stetsenko smb2_neg_ctx_t neg_ctx;
1334e065a9fSAlexander Stetsenko smb2_preauth_caps_t preauth_caps;
1344e065a9fSAlexander Stetsenko } smb2_preauth_neg_ctx_t;
1354e065a9fSAlexander Stetsenko
1364e065a9fSAlexander Stetsenko typedef struct smb2_encrypt_neg_ctx {
1374e065a9fSAlexander Stetsenko smb2_neg_ctx_t neg_ctx;
1384e065a9fSAlexander Stetsenko smb2_encrypt_caps_t encrypt_caps;
1394e065a9fSAlexander Stetsenko } smb2_encrypt_neg_ctx_t;
1404e065a9fSAlexander Stetsenko
1414e065a9fSAlexander Stetsenko typedef struct smb2_neg_ctxs {
1424e065a9fSAlexander Stetsenko uint32_t offset;
1434e065a9fSAlexander Stetsenko uint16_t count;
1444e065a9fSAlexander Stetsenko smb2_preauth_neg_ctx_t preauth_ctx;
1454e065a9fSAlexander Stetsenko smb2_encrypt_neg_ctx_t encrypt_ctx;
1464e065a9fSAlexander Stetsenko } smb2_neg_ctxs_t;
1474e065a9fSAlexander Stetsenko
1484e065a9fSAlexander Stetsenko #define NEG_CTX_INFO_OFFSET (SMB2_HDR_SIZE + 28)
1494e065a9fSAlexander Stetsenko #define NEG_CTX_OFFSET_OFFSET (SMB2_HDR_SIZE + 64)
1504e065a9fSAlexander Stetsenko #define NEG_CTX_MAX_COUNT (16)
1514e065a9fSAlexander Stetsenko #define NEG_CTX_MAX_DATALEN (256)
1524e065a9fSAlexander Stetsenko
1534e065a9fSAlexander Stetsenko #define STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP (0xC05D0000)
1544e065a9fSAlexander Stetsenko
1554e065a9fSAlexander Stetsenko #define STATUS_PREAUTH_HASH_OVERLAP \
1564e065a9fSAlexander Stetsenko STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP
1574e065a9fSAlexander Stetsenko
158b716e3d0SGordon Ross typedef struct smb2_arg_negotiate {
159b716e3d0SGordon Ross struct smb2_neg_ctxs neg_in_ctxs;
160b716e3d0SGordon Ross struct smb2_neg_ctxs neg_out_ctxs;
161b716e3d0SGordon Ross uint16_t neg_dialect_cnt;
162b716e3d0SGordon Ross uint16_t neg_dialects[SMB2_NEGOTIATE_MAX_DIALECTS];
163b716e3d0SGordon Ross uint16_t neg_highest_dialect;
164b716e3d0SGordon Ross } smb2_arg_negotiate_t;
165b716e3d0SGordon Ross
166b716e3d0SGordon Ross
167b716e3d0SGordon Ross static boolean_t
smb2_supported_version(smb_session_t * s,uint16_t version)168b716e3d0SGordon Ross smb2_supported_version(smb_session_t *s, uint16_t version)
169b716e3d0SGordon Ross {
170b716e3d0SGordon Ross int i;
171b716e3d0SGordon Ross
172b716e3d0SGordon Ross if (version > s->s_cfg.skc_max_protocol ||
173b716e3d0SGordon Ross version < s->s_cfg.skc_min_protocol)
174b716e3d0SGordon Ross return (B_FALSE);
175b716e3d0SGordon Ross for (i = 0; i < smb2_nversions; i++)
176b716e3d0SGordon Ross if (version == smb2_versions[i])
177b716e3d0SGordon Ross return (B_TRUE);
178b716e3d0SGordon Ross return (B_FALSE);
179b716e3d0SGordon Ross }
180b716e3d0SGordon Ross
181b716e3d0SGordon Ross static uint16_t
smb2_find_best_dialect(smb_session_t * s,uint16_t cl_versions[],uint16_t version_cnt)182b716e3d0SGordon Ross smb2_find_best_dialect(smb_session_t *s, uint16_t cl_versions[],
183b716e3d0SGordon Ross uint16_t version_cnt)
184b716e3d0SGordon Ross {
185b716e3d0SGordon Ross uint16_t best_version = 0;
186b716e3d0SGordon Ross int i;
187b716e3d0SGordon Ross
188b716e3d0SGordon Ross for (i = 0; i < version_cnt; i++)
189b716e3d0SGordon Ross if (smb2_supported_version(s, cl_versions[i]) &&
190b716e3d0SGordon Ross best_version < cl_versions[i])
191b716e3d0SGordon Ross best_version = cl_versions[i];
192b716e3d0SGordon Ross
193b716e3d0SGordon Ross return (best_version);
194b716e3d0SGordon Ross }
195b716e3d0SGordon Ross
1964e065a9fSAlexander Stetsenko /*
1974e065a9fSAlexander Stetsenko * This function should be called only for dialect >= 0x311
1984e065a9fSAlexander Stetsenko * Negotiate context list should contain exactly one
1994e065a9fSAlexander Stetsenko * SMB2_PREAUTH_INTEGRITY_CAPS context.
2004e065a9fSAlexander Stetsenko * Otherwise STATUS_INVALID_PARAMETER.
2014e065a9fSAlexander Stetsenko * It should contain at least 1 hash algorith what server does support.
2024e065a9fSAlexander Stetsenko * Otehrwise STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP.
2034e065a9fSAlexander Stetsenko */
2044e065a9fSAlexander Stetsenko static uint32_t
smb31_decode_neg_ctxs(smb_request_t * sr)205b716e3d0SGordon Ross smb31_decode_neg_ctxs(smb_request_t *sr)
2064e065a9fSAlexander Stetsenko {
2074e065a9fSAlexander Stetsenko smb_session_t *s = sr->session;
208b716e3d0SGordon Ross smb2_arg_negotiate_t *nego = sr->arg.other;
209b716e3d0SGordon Ross smb2_neg_ctxs_t *neg_ctxs = &nego->neg_in_ctxs;
2104e065a9fSAlexander Stetsenko smb2_preauth_caps_t *picap = &neg_ctxs->preauth_ctx.preauth_caps;
2114e065a9fSAlexander Stetsenko smb2_encrypt_caps_t *encap = &neg_ctxs->encrypt_ctx.encrypt_caps;
212dee7ba86SAlexander Stetsenko boolean_t found_sha512 = B_FALSE;
213dee7ba86SAlexander Stetsenko boolean_t found_cipher = B_FALSE;
214b0bb0d63SGordon Ross uint32_t ciphers = sr->sr_server->sv_cfg.skc_encrypt_ciphers;
2154e065a9fSAlexander Stetsenko uint32_t status = 0;
2164e065a9fSAlexander Stetsenko int32_t skip;
2174e065a9fSAlexander Stetsenko int found_preauth_ctx = 0;
2184e065a9fSAlexander Stetsenko int found_encrypt_ctx = 0;
2194e065a9fSAlexander Stetsenko int cnt, i;
2204e065a9fSAlexander Stetsenko int rc;
2214e065a9fSAlexander Stetsenko
2224e065a9fSAlexander Stetsenko /*
2234e065a9fSAlexander Stetsenko * There should be exactly 1 SMB2_PREAUTH_INTEGRITY_CAPS negotiate ctx.
2244e065a9fSAlexander Stetsenko * SMB2_ENCRYPTION_CAPS is optional one.
2254e065a9fSAlexander Stetsenko * If there is no contexts or there are to many then stop parsing.
2264e065a9fSAlexander Stetsenko */
2274e065a9fSAlexander Stetsenko cnt = neg_ctxs->count;
2284e065a9fSAlexander Stetsenko if (cnt < 1 || cnt > NEG_CTX_MAX_COUNT) {
2294e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
2304e065a9fSAlexander Stetsenko goto errout;
2314e065a9fSAlexander Stetsenko }
2324e065a9fSAlexander Stetsenko
2334e065a9fSAlexander Stetsenko /*
2344e065a9fSAlexander Stetsenko * Cannot proceed parsing if the first context isn't aligned by 8.
2354e065a9fSAlexander Stetsenko */
2364e065a9fSAlexander Stetsenko if (neg_ctxs->offset % 8 != 0) {
2374e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
2384e065a9fSAlexander Stetsenko goto errout;
2394e065a9fSAlexander Stetsenko }
2404e065a9fSAlexander Stetsenko
2414e065a9fSAlexander Stetsenko if ((skip = neg_ctxs->offset - sr->command.chain_offset) != 0 &&
2424e065a9fSAlexander Stetsenko smb_mbc_decodef(&sr->command, "#.", skip) != 0) {
2434e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
2444e065a9fSAlexander Stetsenko goto errout;
2454e065a9fSAlexander Stetsenko }
2464e065a9fSAlexander Stetsenko
2474e065a9fSAlexander Stetsenko /*
2484e065a9fSAlexander Stetsenko * Parse negotiate contexts. Ignore non-decoding errors to fill
2494e065a9fSAlexander Stetsenko * as much as possible data for dtrace probe.
2504e065a9fSAlexander Stetsenko */
2514e065a9fSAlexander Stetsenko for (i = 0; i < cnt; i++) {
2524e065a9fSAlexander Stetsenko smb2_neg_ctx_t neg_ctx;
2534e065a9fSAlexander Stetsenko int32_t ctx_end_off;
2544e065a9fSAlexander Stetsenko int32_t ctx_next_off;
2554e065a9fSAlexander Stetsenko
2564e065a9fSAlexander Stetsenko if (i > 0) {
2574e065a9fSAlexander Stetsenko if ((skip = ctx_next_off - ctx_end_off) != 0 &&
2584e065a9fSAlexander Stetsenko smb_mbc_decodef(&sr->command, "#.", skip) != 0) {
2594e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
2604e065a9fSAlexander Stetsenko goto errout;
2614e065a9fSAlexander Stetsenko }
2624e065a9fSAlexander Stetsenko }
2634e065a9fSAlexander Stetsenko
2644e065a9fSAlexander Stetsenko rc = smb_mbc_decodef(
2654e065a9fSAlexander Stetsenko &sr->command, "ww4.",
2664e065a9fSAlexander Stetsenko &neg_ctx.type, /* w */
2674e065a9fSAlexander Stetsenko &neg_ctx.datalen); /* w */
2684e065a9fSAlexander Stetsenko if (rc != 0) {
2694e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
2704e065a9fSAlexander Stetsenko goto errout;
2714e065a9fSAlexander Stetsenko }
2724e065a9fSAlexander Stetsenko
2734e065a9fSAlexander Stetsenko /*
2744e065a9fSAlexander Stetsenko * We got something crazy
2754e065a9fSAlexander Stetsenko */
2764e065a9fSAlexander Stetsenko if (neg_ctx.datalen > NEG_CTX_MAX_DATALEN) {
2774e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
2784e065a9fSAlexander Stetsenko goto errout;
2794e065a9fSAlexander Stetsenko }
2804e065a9fSAlexander Stetsenko
2814e065a9fSAlexander Stetsenko ctx_end_off = sr->command.chain_offset + neg_ctx.datalen;
2824e065a9fSAlexander Stetsenko ctx_next_off = P2ROUNDUP(ctx_end_off, 8);
2834e065a9fSAlexander Stetsenko
2844e065a9fSAlexander Stetsenko switch (neg_ctx.type) {
2854e065a9fSAlexander Stetsenko case SMB2_PREAUTH_INTEGRITY_CAPS:
2864e065a9fSAlexander Stetsenko memcpy(&neg_ctxs->preauth_ctx.neg_ctx, &neg_ctx,
2874e065a9fSAlexander Stetsenko sizeof (neg_ctx));
2884e065a9fSAlexander Stetsenko
2894e065a9fSAlexander Stetsenko if (found_preauth_ctx++ != 0) {
2904e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
2914e065a9fSAlexander Stetsenko continue;
2924e065a9fSAlexander Stetsenko }
2934e065a9fSAlexander Stetsenko
2944e065a9fSAlexander Stetsenko rc = smb_mbc_decodef(
2954e065a9fSAlexander Stetsenko &sr->command, "ww",
2964e065a9fSAlexander Stetsenko &picap->picap_hash_count, /* w */
2974e065a9fSAlexander Stetsenko &picap->picap_salt_len); /* w */
2984e065a9fSAlexander Stetsenko if (rc != 0 || picap->picap_hash_count >
2994e065a9fSAlexander Stetsenko MAX_HASHID_NUM) {
3004e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
3014e065a9fSAlexander Stetsenko goto errout;
3024e065a9fSAlexander Stetsenko }
3034e065a9fSAlexander Stetsenko
3044e065a9fSAlexander Stetsenko /*
3054e065a9fSAlexander Stetsenko * Get hash id
3064e065a9fSAlexander Stetsenko */
3074e065a9fSAlexander Stetsenko rc = smb_mbc_decodef(
3084e065a9fSAlexander Stetsenko &sr->command, "#w",
3094e065a9fSAlexander Stetsenko picap->picap_hash_count,
3104e065a9fSAlexander Stetsenko &picap->picap_hash_id); /* w */
3114e065a9fSAlexander Stetsenko if (rc != 0) {
3124e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
3134e065a9fSAlexander Stetsenko goto errout;
3144e065a9fSAlexander Stetsenko }
3154e065a9fSAlexander Stetsenko
3164e065a9fSAlexander Stetsenko /*
3174e065a9fSAlexander Stetsenko * Get salt
3184e065a9fSAlexander Stetsenko */
3194e065a9fSAlexander Stetsenko rc = smb_mbc_decodef(
3204e065a9fSAlexander Stetsenko &sr->command, "#c",
3214e065a9fSAlexander Stetsenko sizeof (picap->picap_salt),
3224e065a9fSAlexander Stetsenko &picap->picap_salt[0]); /* w */
3234e065a9fSAlexander Stetsenko if (rc != 0) {
3244e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
3254e065a9fSAlexander Stetsenko goto errout;
3264e065a9fSAlexander Stetsenko }
3274e065a9fSAlexander Stetsenko
3284e065a9fSAlexander Stetsenko /*
3294e065a9fSAlexander Stetsenko * In SMB 0x311 there should be exactly 1 preauth
3304e065a9fSAlexander Stetsenko * negotiate context, and there should be exactly 1
3314e065a9fSAlexander Stetsenko * hash value in the list - SHA512.
3324e065a9fSAlexander Stetsenko */
3334e065a9fSAlexander Stetsenko if (picap->picap_hash_count != 1) {
3344e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
3354e065a9fSAlexander Stetsenko continue;
3364e065a9fSAlexander Stetsenko }
3374e065a9fSAlexander Stetsenko
3384e065a9fSAlexander Stetsenko if (picap->picap_hash_id == SMB3_HASH_SHA512)
339dee7ba86SAlexander Stetsenko found_sha512 = B_TRUE;
3404e065a9fSAlexander Stetsenko break;
3414e065a9fSAlexander Stetsenko case SMB2_ENCRYPTION_CAPS:
3424e065a9fSAlexander Stetsenko memcpy(&neg_ctxs->preauth_ctx.neg_ctx, &neg_ctx,
3434e065a9fSAlexander Stetsenko sizeof (neg_ctx));
3444e065a9fSAlexander Stetsenko
3454e065a9fSAlexander Stetsenko if (found_encrypt_ctx++ != 0) {
3464e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
3474e065a9fSAlexander Stetsenko continue;
3484e065a9fSAlexander Stetsenko }
3494e065a9fSAlexander Stetsenko
3504e065a9fSAlexander Stetsenko rc = smb_mbc_decodef(
3514e065a9fSAlexander Stetsenko &sr->command, "w",
3524e065a9fSAlexander Stetsenko &encap->encap_cipher_count); /* w */
3534e065a9fSAlexander Stetsenko if (rc != 0 || encap->encap_cipher_count >
3544e065a9fSAlexander Stetsenko MAX_CIPHER_NUM) {
3554e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
3564e065a9fSAlexander Stetsenko goto errout;
3574e065a9fSAlexander Stetsenko }
3584e065a9fSAlexander Stetsenko
3594e065a9fSAlexander Stetsenko /*
3604e065a9fSAlexander Stetsenko * Get cipher list
3614e065a9fSAlexander Stetsenko */
3624e065a9fSAlexander Stetsenko rc = smb_mbc_decodef(
3634e065a9fSAlexander Stetsenko &sr->command, "#w",
3644e065a9fSAlexander Stetsenko encap->encap_cipher_count,
3654e065a9fSAlexander Stetsenko &encap->encap_cipher_ids[0]); /* w */
3664e065a9fSAlexander Stetsenko if (rc != 0) {
3674e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
3684e065a9fSAlexander Stetsenko goto errout;
3694e065a9fSAlexander Stetsenko }
3704e065a9fSAlexander Stetsenko
371dee7ba86SAlexander Stetsenko /*
372dee7ba86SAlexander Stetsenko * Select the first enabled cipher.
373dee7ba86SAlexander Stetsenko * Client should list more prioritized ciphers first.
374dee7ba86SAlexander Stetsenko */
3754e065a9fSAlexander Stetsenko for (int k = 0; k < encap->encap_cipher_count; k++) {
376dee7ba86SAlexander Stetsenko uint16_t c = encap->encap_cipher_ids[k];
377dee7ba86SAlexander Stetsenko
378a4568e19SAlexander Stetsenko if (c <= SMB3_CIPHER_MAX &&
379a4568e19SAlexander Stetsenko (SMB3_CIPHER_BIT(c) & ciphers) != 0) {
380dee7ba86SAlexander Stetsenko s->smb31_enc_cipherid = c;
381dee7ba86SAlexander Stetsenko found_cipher = B_TRUE;
3824e065a9fSAlexander Stetsenko break;
3834e065a9fSAlexander Stetsenko }
3844e065a9fSAlexander Stetsenko }
3854e065a9fSAlexander Stetsenko break;
3864e065a9fSAlexander Stetsenko default:
3874e065a9fSAlexander Stetsenko ;
3884e065a9fSAlexander Stetsenko }
3894e065a9fSAlexander Stetsenko }
3904e065a9fSAlexander Stetsenko
3914e065a9fSAlexander Stetsenko if (status)
3924e065a9fSAlexander Stetsenko goto errout;
3934e065a9fSAlexander Stetsenko
3944e065a9fSAlexander Stetsenko /* Not found mandatory SMB2_PREAUTH_INTEGRITY_CAPS ctx */
3954e065a9fSAlexander Stetsenko if (found_preauth_ctx != 1 || found_encrypt_ctx > 1) {
3964e065a9fSAlexander Stetsenko status = NT_STATUS_INVALID_PARAMETER;
3974e065a9fSAlexander Stetsenko goto errout;
3984e065a9fSAlexander Stetsenko }
3994e065a9fSAlexander Stetsenko
400dee7ba86SAlexander Stetsenko if (!found_sha512) {
4014e065a9fSAlexander Stetsenko status = STATUS_PREAUTH_HASH_OVERLAP;
4024e065a9fSAlexander Stetsenko goto errout;
4034e065a9fSAlexander Stetsenko }
4044e065a9fSAlexander Stetsenko
4054e065a9fSAlexander Stetsenko s->smb31_preauth_hashid = SMB3_HASH_SHA512;
4064e065a9fSAlexander Stetsenko
407dee7ba86SAlexander Stetsenko if (!found_cipher)
4084e065a9fSAlexander Stetsenko s->smb31_enc_cipherid = 0;
4094e065a9fSAlexander Stetsenko
410ab017dbaSGordon Ross /* Initialize out = in */
411ab017dbaSGordon Ross nego->neg_out_ctxs = nego->neg_in_ctxs;
412ab017dbaSGordon Ross
4134e065a9fSAlexander Stetsenko errout:
4144e065a9fSAlexander Stetsenko return (status);
4154e065a9fSAlexander Stetsenko }
4164e065a9fSAlexander Stetsenko
4174e065a9fSAlexander Stetsenko static int
smb31_encode_neg_ctxs(smb_request_t * sr)418b716e3d0SGordon Ross smb31_encode_neg_ctxs(smb_request_t *sr)
4194e065a9fSAlexander Stetsenko {
4204e065a9fSAlexander Stetsenko smb_session_t *s = sr->session;
421b716e3d0SGordon Ross smb2_arg_negotiate_t *nego = sr->arg.other;
422b716e3d0SGordon Ross smb2_neg_ctxs_t *neg_ctxs = &nego->neg_out_ctxs;
4234e065a9fSAlexander Stetsenko smb2_preauth_caps_t *picap = &neg_ctxs->preauth_ctx.preauth_caps;
4244e065a9fSAlexander Stetsenko smb2_encrypt_caps_t *encap = &neg_ctxs->encrypt_ctx.encrypt_caps;
4254e065a9fSAlexander Stetsenko uint16_t salt_len = sizeof (picap->picap_salt);
4264e065a9fSAlexander Stetsenko uint32_t preauth_ctx_len = 6 + salt_len;
4274e065a9fSAlexander Stetsenko uint32_t enc_ctx_len = 4;
4284e065a9fSAlexander Stetsenko uint32_t neg_ctx_off = NEG_CTX_OFFSET_OFFSET +
4294e065a9fSAlexander Stetsenko P2ROUNDUP(sr->sr_cfg->skc_negtok_len, 8);
4304e065a9fSAlexander Stetsenko uint32_t rc;
4314e065a9fSAlexander Stetsenko
4324e065a9fSAlexander Stetsenko if ((rc = smb_mbc_put_align(&sr->reply, 8)) != 0)
4334e065a9fSAlexander Stetsenko return (rc);
4344e065a9fSAlexander Stetsenko
4354e065a9fSAlexander Stetsenko ASSERT3S(neg_ctx_off, ==, sr->reply.chain_offset);
4364e065a9fSAlexander Stetsenko
4374e065a9fSAlexander Stetsenko picap->picap_hash_id = s->smb31_preauth_hashid;
4384e065a9fSAlexander Stetsenko picap->picap_salt_len = salt_len;
4394e065a9fSAlexander Stetsenko
4404e065a9fSAlexander Stetsenko (void) random_get_pseudo_bytes(picap->picap_salt, salt_len);
4414e065a9fSAlexander Stetsenko
4424e065a9fSAlexander Stetsenko rc = smb_mbc_encodef(
4434e065a9fSAlexander Stetsenko &sr->reply, "ww4.",
4444e065a9fSAlexander Stetsenko SMB2_PREAUTH_INTEGRITY_CAPS,
4454e065a9fSAlexander Stetsenko preauth_ctx_len
4464e065a9fSAlexander Stetsenko /* 4. */); /* reserved */
4474e065a9fSAlexander Stetsenko if (rc != 0)
4484e065a9fSAlexander Stetsenko return (rc);
4494e065a9fSAlexander Stetsenko
4504e065a9fSAlexander Stetsenko rc = smb_mbc_encodef(
4514e065a9fSAlexander Stetsenko &sr->reply, "www#c",
4524e065a9fSAlexander Stetsenko 1, /* hash algo count */
4534e065a9fSAlexander Stetsenko salt_len, /* salt length */
4544e065a9fSAlexander Stetsenko s->smb31_preauth_hashid, /* hash id */
4554e065a9fSAlexander Stetsenko salt_len, /* salt length */
4564e065a9fSAlexander Stetsenko picap->picap_salt);
457ab017dbaSGordon Ross if (rc != 0)
4584e065a9fSAlexander Stetsenko return (rc);
4594e065a9fSAlexander Stetsenko
460ab017dbaSGordon Ross /*
461ab017dbaSGordon Ross * If we did not get SMB2_ENCRYPTION_CAPS, don't send one.
462ab017dbaSGordon Ross */
463ab017dbaSGordon Ross if (encap->encap_cipher_count == 0)
464ab017dbaSGordon Ross return (0);
465ab017dbaSGordon Ross
466ab017dbaSGordon Ross /*
467ab017dbaSGordon Ross * Encode SMB2_ENCRYPTION_CAPS response.
468ab017dbaSGordon Ross */
4694e065a9fSAlexander Stetsenko if ((rc = smb_mbc_put_align(&sr->reply, 8)) != 0)
4704e065a9fSAlexander Stetsenko return (rc);
4714e065a9fSAlexander Stetsenko
4724e065a9fSAlexander Stetsenko rc = smb_mbc_encodef(
4734e065a9fSAlexander Stetsenko &sr->reply, "ww4.",
4744e065a9fSAlexander Stetsenko SMB2_ENCRYPTION_CAPS,
4754e065a9fSAlexander Stetsenko enc_ctx_len
4764e065a9fSAlexander Stetsenko /* 4. */); /* reserved */
4774e065a9fSAlexander Stetsenko
4784e065a9fSAlexander Stetsenko rc = smb_mbc_encodef(
4794e065a9fSAlexander Stetsenko &sr->reply, "ww",
4804e065a9fSAlexander Stetsenko 1, /* cipher count */
4814e065a9fSAlexander Stetsenko s->smb31_enc_cipherid); /* encrypt. cipher id */
4824e065a9fSAlexander Stetsenko
4834e065a9fSAlexander Stetsenko return (rc);
4844e065a9fSAlexander Stetsenko }
4854e065a9fSAlexander Stetsenko
486b716e3d0SGordon Ross /*
487b716e3d0SGordon Ross * Helper for the (SMB1) smb_com_negotiate(). This is the
488b716e3d0SGordon Ross * very unusual protocol interaction where an SMB1 negotiate
489b716e3d0SGordon Ross * gets an SMB2 negotiate response. This is the normal way
490b716e3d0SGordon Ross * clients first find out if the server supports SMB2.
491b716e3d0SGordon Ross *
492b716e3d0SGordon Ross * Note: This sends an SMB2 reply _itself_ and then returns
493b716e3d0SGordon Ross * SDRC_NO_REPLY so the caller will not send an SMB1 reply.
494b716e3d0SGordon Ross * Also, this is called directly from the reader thread, so
495b716e3d0SGordon Ross * we know this is the only thread using this session.
496b716e3d0SGordon Ross * Otherwise, this is similar to smb2_newrq_negotiate().
497b716e3d0SGordon Ross *
498b716e3d0SGordon Ross * The caller frees this request.
499b716e3d0SGordon Ross */
500b716e3d0SGordon Ross smb_sdrc_t
smb1_negotiate_smb2(smb_request_t * sr)501b716e3d0SGordon Ross smb1_negotiate_smb2(smb_request_t *sr)
502b716e3d0SGordon Ross {
503b716e3d0SGordon Ross smb_session_t *s = sr->session;
504b716e3d0SGordon Ross smb_arg_negotiate_t *negprot = sr->sr_negprot;
505b716e3d0SGordon Ross uint16_t smb2_version;
506b716e3d0SGordon Ross
507b716e3d0SGordon Ross /*
508b716e3d0SGordon Ross * Note: In the SMB1 negotiate command handler, we
509b716e3d0SGordon Ross * agreed with one of the SMB2 dialects. If that
510b716e3d0SGordon Ross * dialect was "SMB 2.002", we'll respond here with
511b716e3d0SGordon Ross * version 0x202 and negotiation is done. If that
512b716e3d0SGordon Ross * dialect was "SMB 2.???", we'll respond here with
513b716e3d0SGordon Ross * the "wildcard" version 0x2FF, and the client will
514b716e3d0SGordon Ross * come back with an SMB2 negotiate.
515b716e3d0SGordon Ross */
516b716e3d0SGordon Ross switch (negprot->ni_dialect) {
517b716e3d0SGordon Ross case DIALECT_SMB2002: /* SMB 2.002 (a.k.a. SMB2.0) */
518b716e3d0SGordon Ross smb2_version = SMB_VERS_2_002;
519b716e3d0SGordon Ross s->dialect = smb2_version;
520b716e3d0SGordon Ross s->s_state = SMB_SESSION_STATE_NEGOTIATED;
521b716e3d0SGordon Ross /* Allow normal SMB2 requests now. */
522b716e3d0SGordon Ross s->newrq_func = smb2sr_newrq;
523b716e3d0SGordon Ross break;
524b716e3d0SGordon Ross case DIALECT_SMB2XXX: /* SMB 2.??? (wildcard vers) */
525b716e3d0SGordon Ross /*
526b716e3d0SGordon Ross * Expecting an SMB2 negotiate next, so keep the
527b716e3d0SGordon Ross * initial s->newrq_func.
528b716e3d0SGordon Ross */
529b716e3d0SGordon Ross smb2_version = 0x2FF;
530b716e3d0SGordon Ross break;
531b716e3d0SGordon Ross default:
532b716e3d0SGordon Ross return (SDRC_DROP_VC);
533b716e3d0SGordon Ross }
534b716e3d0SGordon Ross
535b716e3d0SGordon Ross /*
536b716e3d0SGordon Ross * We did not decode an SMB2 header, so make sure
537b716e3d0SGordon Ross * the SMB2 header fields are initialized.
538b716e3d0SGordon Ross * (Most are zero from smb_request_alloc.)
539b716e3d0SGordon Ross * Also, the SMB1 common dispatch code reserved space
540b716e3d0SGordon Ross * for an SMB1 header, which we need to undo here.
541b716e3d0SGordon Ross */
542b716e3d0SGordon Ross sr->smb2_reply_hdr = sr->reply.chain_offset = 0;
543b716e3d0SGordon Ross sr->smb2_cmd_code = SMB2_NEGOTIATE;
544b716e3d0SGordon Ross sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
545b716e3d0SGordon Ross
546b716e3d0SGordon Ross /*
547b716e3d0SGordon Ross * Also setup SMB2 negotiate args (empty here).
548b716e3d0SGordon Ross * SMB1 args free'd by smb_srm_fini(sr)
549b716e3d0SGordon Ross */
550b716e3d0SGordon Ross sr->arg.other = smb_srm_zalloc(sr, sizeof (smb2_arg_negotiate_t));
551b716e3d0SGordon Ross
552b716e3d0SGordon Ross (void) smb2_encode_header(sr, B_FALSE);
553b716e3d0SGordon Ross if (smb2_negotiate_common(sr, smb2_version) != 0)
554b716e3d0SGordon Ross sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
555b716e3d0SGordon Ross if (sr->smb2_status != 0)
556b716e3d0SGordon Ross smb2sr_put_error(sr, sr->smb2_status);
557b716e3d0SGordon Ross (void) smb2_encode_header(sr, B_TRUE);
558b716e3d0SGordon Ross
559b716e3d0SGordon Ross smb2_send_reply(sr);
560b716e3d0SGordon Ross
561b716e3d0SGordon Ross /*
562b716e3d0SGordon Ross * We sent the reply, so tell the SMB1 dispatch
563b716e3d0SGordon Ross * it should NOT (also) send a reply.
564b716e3d0SGordon Ross */
565b716e3d0SGordon Ross return (SDRC_NO_REPLY);
566b716e3d0SGordon Ross }
567b716e3d0SGordon Ross
568b716e3d0SGordon Ross /*
569b716e3d0SGordon Ross * SMB2 Negotiate gets special handling. This is called directly by
570b716e3d0SGordon Ross * the reader thread (see smbsr_newrq_initial) with what _should_ be
571b716e3d0SGordon Ross * an SMB2 Negotiate. Only the "\feSMB" header has been checked
572b716e3d0SGordon Ross * when this is called, so this needs to check the SMB command,
573b716e3d0SGordon Ross * if it's Negotiate execute it, then send the reply, etc.
574b716e3d0SGordon Ross *
575b716e3d0SGordon Ross * Since this is called directly from the reader thread, we
576b716e3d0SGordon Ross * know this is the only thread currently using this session.
577b716e3d0SGordon Ross * This has to duplicate some of what smb2sr_work does as a
578b716e3d0SGordon Ross * result of bypassing the normal dispatch mechanism.
579b716e3d0SGordon Ross *
580b716e3d0SGordon Ross * The caller always frees this request.
581b716e3d0SGordon Ross *
582b716e3d0SGordon Ross * Return value is 0 for success, and anything else will
583b716e3d0SGordon Ross * terminate the reader thread (drop the connection).
584b716e3d0SGordon Ross */
585a90cf9f2SGordon Ross int
smb2_newrq_negotiate(smb_request_t * sr)586a90cf9f2SGordon Ross smb2_newrq_negotiate(smb_request_t *sr)
587a90cf9f2SGordon Ross {
588a90cf9f2SGordon Ross smb_session_t *s = sr->session;
589b716e3d0SGordon Ross smb2_arg_negotiate_t *nego;
5901160dcf7SMatt Barden int rc;
591b716e3d0SGordon Ross uint32_t nctx_status = 0;
592ebc5aadbSAndrew Stormont uint32_t status = 0;
593b716e3d0SGordon Ross uint32_t neg_ctx_off;
594b716e3d0SGordon Ross uint16_t neg_ctx_cnt;
595a90cf9f2SGordon Ross uint16_t struct_size;
596b716e3d0SGordon Ross uint16_t dialect_cnt;
597a90cf9f2SGordon Ross uint16_t best_version;
5984e065a9fSAlexander Stetsenko
599b716e3d0SGordon Ross nego = smb_srm_zalloc(sr, sizeof (smb2_arg_negotiate_t));
600b716e3d0SGordon Ross sr->arg.other = nego; // for dtrace
601a90cf9f2SGordon Ross
602a90cf9f2SGordon Ross sr->smb2_cmd_hdr = sr->command.chain_offset;
603a90cf9f2SGordon Ross rc = smb2_decode_header(sr);
604a90cf9f2SGordon Ross if (rc != 0)
605a90cf9f2SGordon Ross return (rc);
606a90cf9f2SGordon Ross
607ebc5aadbSAndrew Stormont if (sr->smb2_hdr_flags & SMB2_FLAGS_SERVER_TO_REDIR)
608ebc5aadbSAndrew Stormont return (-1);
609ebc5aadbSAndrew Stormont
610a90cf9f2SGordon Ross if ((sr->smb2_cmd_code != SMB2_NEGOTIATE) ||
611a90cf9f2SGordon Ross (sr->smb2_next_command != 0))
61293bc28dbSGordon Ross return (-1);
613a90cf9f2SGordon Ross
614a90cf9f2SGordon Ross /*
615a90cf9f2SGordon Ross * Decode SMB2 Negotiate (fixed-size part)
616a90cf9f2SGordon Ross */
617a90cf9f2SGordon Ross rc = smb_mbc_decodef(
618b716e3d0SGordon Ross &sr->command, "www..l16clw..",
619a90cf9f2SGordon Ross &struct_size, /* w */
620b716e3d0SGordon Ross &dialect_cnt, /* w */
6211160dcf7SMatt Barden &s->cli_secmode, /* w */
622a90cf9f2SGordon Ross /* reserved (..) */
6231160dcf7SMatt Barden &s->capabilities, /* l */
624b716e3d0SGordon Ross s->clnt_uuid, /* 16c */
625b716e3d0SGordon Ross &neg_ctx_off, /* l */
626b716e3d0SGordon Ross &neg_ctx_cnt); /* w */
627b716e3d0SGordon Ross /* reserverd (..) */
628a90cf9f2SGordon Ross if (rc != 0)
629a90cf9f2SGordon Ross return (rc);
630ebc5aadbSAndrew Stormont if (struct_size != 36)
63193bc28dbSGordon Ross return (-1);
632a90cf9f2SGordon Ross
633a90cf9f2SGordon Ross /*
634a90cf9f2SGordon Ross * Decode SMB2 Negotiate (variable part)
635ebc5aadbSAndrew Stormont *
636ebc5aadbSAndrew Stormont * Be somewhat tolerant while decoding the variable part
637ebc5aadbSAndrew Stormont * so we can return errors instead of dropping the client.
6384e065a9fSAlexander Stetsenko * Will limit decoding to the size of cli_dialects here,
639b716e3d0SGordon Ross * and do error checks on the decoded dialect_cnt after the
640ebc5aadbSAndrew Stormont * dtrace start probe.
641a90cf9f2SGordon Ross */
642b716e3d0SGordon Ross if (dialect_cnt > SMB2_NEGOTIATE_MAX_DIALECTS)
643b716e3d0SGordon Ross nego->neg_dialect_cnt = SMB2_NEGOTIATE_MAX_DIALECTS;
644b716e3d0SGordon Ross else
645b716e3d0SGordon Ross nego->neg_dialect_cnt = dialect_cnt;
646b716e3d0SGordon Ross if (nego->neg_dialect_cnt > 0) {
647b716e3d0SGordon Ross rc = smb_mbc_decodef(&sr->command, "#w",
648b716e3d0SGordon Ross nego->neg_dialect_cnt,
649b716e3d0SGordon Ross nego->neg_dialects);
650b716e3d0SGordon Ross if (rc != 0)
651b716e3d0SGordon Ross return (rc); // short msg
6524e065a9fSAlexander Stetsenko }
6534e065a9fSAlexander Stetsenko
654b716e3d0SGordon Ross best_version = smb2_find_best_dialect(s, nego->neg_dialects,
655b716e3d0SGordon Ross nego->neg_dialect_cnt);
6564e065a9fSAlexander Stetsenko
6574e065a9fSAlexander Stetsenko if (best_version >= SMB_VERS_3_11) {
658b716e3d0SGordon Ross nego->neg_in_ctxs.offset = neg_ctx_off;
659b716e3d0SGordon Ross nego->neg_in_ctxs.count = neg_ctx_cnt;
660b716e3d0SGordon Ross nctx_status = smb31_decode_neg_ctxs(sr);
661b716e3d0SGordon Ross /* check nctx_status below */
662ebc5aadbSAndrew Stormont }
66393bc28dbSGordon Ross
66493bc28dbSGordon Ross DTRACE_SMB2_START(op__Negotiate, smb_request_t *, sr);
665a90cf9f2SGordon Ross
666b716e3d0SGordon Ross sr->smb2_credit_response = 1;
667ebc5aadbSAndrew Stormont sr->smb2_hdr_flags |= SMB2_FLAGS_SERVER_TO_REDIR;
668ebc5aadbSAndrew Stormont (void) smb2_encode_header(sr, B_FALSE);
669ebc5aadbSAndrew Stormont
670b716e3d0SGordon Ross /*
671b716e3d0SGordon Ross * NOW start validating things (NOT before here)
672b716e3d0SGordon Ross */
6734e065a9fSAlexander Stetsenko
674ebc5aadbSAndrew Stormont /*
675ebc5aadbSAndrew Stormont * [MS-SMB2] 3.3.5.2.4 Verifying the Signature
676ebc5aadbSAndrew Stormont * "If the SMB2 header of the SMB2 NEGOTIATE request has the
677ebc5aadbSAndrew Stormont * SMB2_FLAGS_SIGNED bit set in the Flags field, the server
678ebc5aadbSAndrew Stormont * MUST fail the request with STATUS_INVALID_PARAMETER."
679ebc5aadbSAndrew Stormont */
680ebc5aadbSAndrew Stormont if ((sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0) {
681ebc5aadbSAndrew Stormont sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED;
682ebc5aadbSAndrew Stormont status = NT_STATUS_INVALID_PARAMETER;
683ebc5aadbSAndrew Stormont goto errout;
684ebc5aadbSAndrew Stormont }
685ebc5aadbSAndrew Stormont
686b716e3d0SGordon Ross /*
687b716e3d0SGordon Ross * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
688b716e3d0SGordon Ross * "If the DialectCount of the SMB2 NEGOTIATE Request is 0, the
689b716e3d0SGordon Ross * server MUST fail the request with STATUS_INVALID_PARAMETER."
690b716e3d0SGordon Ross * Checking the decoded value here, not the constrained one.
691b716e3d0SGordon Ross */
692b716e3d0SGordon Ross if (dialect_cnt == 0 ||
693b716e3d0SGordon Ross dialect_cnt > SMB2_NEGOTIATE_MAX_DIALECTS) {
694b716e3d0SGordon Ross status = NT_STATUS_INVALID_PARAMETER;
695b716e3d0SGordon Ross goto errout;
696b716e3d0SGordon Ross }
697b716e3d0SGordon Ross
698b716e3d0SGordon Ross /*
699b716e3d0SGordon Ross * We decoded the offered dialects above, and
700b716e3d0SGordon Ross * determined which was the highest we support.
701b716e3d0SGordon Ross *
702b716e3d0SGordon Ross * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
703b716e3d0SGordon Ross * "If a common dialect is not found, the server MUST fail
704b716e3d0SGordon Ross * the request with STATUS_NOT_SUPPORTED."
705b716e3d0SGordon Ross */
706b716e3d0SGordon Ross if (best_version == 0) {
707b716e3d0SGordon Ross status = NT_STATUS_NOT_SUPPORTED;
708b716e3d0SGordon Ross goto errout;
709b716e3d0SGordon Ross }
710b716e3d0SGordon Ross
711b716e3d0SGordon Ross /*
712b716e3d0SGordon Ross * Check for problems with the negotiate contexts.
713b716e3d0SGordon Ross */
714b716e3d0SGordon Ross if (nctx_status != 0) {
715b716e3d0SGordon Ross status = nctx_status;
716b716e3d0SGordon Ross goto errout;
717b716e3d0SGordon Ross }
718a90cf9f2SGordon Ross
719a90cf9f2SGordon Ross /* Allow normal SMB2 requests now. */
720b716e3d0SGordon Ross s->dialect = best_version;
721a90cf9f2SGordon Ross s->s_state = SMB_SESSION_STATE_NEGOTIATED;
722a90cf9f2SGordon Ross s->newrq_func = smb2sr_newrq;
723a90cf9f2SGordon Ross
724ebc5aadbSAndrew Stormont if (smb2_negotiate_common(sr, best_version) != 0)
725ebc5aadbSAndrew Stormont status = NT_STATUS_INTERNAL_ERROR;
726a90cf9f2SGordon Ross
7274e065a9fSAlexander Stetsenko if (s->dialect >= SMB_VERS_3_11 && status == 0) {
728b716e3d0SGordon Ross if (smb31_encode_neg_ctxs(sr) != 0)
7294e065a9fSAlexander Stetsenko status = NT_STATUS_INTERNAL_ERROR;
7304e065a9fSAlexander Stetsenko }
7314e065a9fSAlexander Stetsenko
7323e2c0c09SMatt Barden errout:
733ebc5aadbSAndrew Stormont sr->smb2_status = status;
73493bc28dbSGordon Ross DTRACE_SMB2_DONE(op__Negotiate, smb_request_t *, sr);
73593bc28dbSGordon Ross
736ebc5aadbSAndrew Stormont if (sr->smb2_status != 0)
737ebc5aadbSAndrew Stormont smb2sr_put_error(sr, sr->smb2_status);
738ebc5aadbSAndrew Stormont (void) smb2_encode_header(sr, B_TRUE);
739ebc5aadbSAndrew Stormont
7404e065a9fSAlexander Stetsenko if (s->dialect >= SMB_VERS_3_11 && sr->smb2_status == 0) {
7414e065a9fSAlexander Stetsenko ASSERT3U(s->smb31_preauth_hashid, !=, 0);
7424e065a9fSAlexander Stetsenko if (smb31_preauth_sha512_calc(sr, &sr->reply,
7434e065a9fSAlexander Stetsenko s->smb31_preauth_hashval,
7444e065a9fSAlexander Stetsenko s->smb31_preauth_hashval) != 0)
7454e065a9fSAlexander Stetsenko cmn_err(CE_WARN, "(1) Preauth hash calculation "
7464e065a9fSAlexander Stetsenko "failed");
7474e065a9fSAlexander Stetsenko }
7484e065a9fSAlexander Stetsenko
74993bc28dbSGordon Ross smb2_send_reply(sr);
75093bc28dbSGordon Ross
75193bc28dbSGordon Ross return (rc);
752a90cf9f2SGordon Ross }
753a90cf9f2SGordon Ross
754a90cf9f2SGordon Ross /*
755a90cf9f2SGordon Ross * Common parts of SMB2 Negotiate, used for both the
756a90cf9f2SGordon Ross * SMB1-to-SMB2 style, and straight SMB2 style.
75793bc28dbSGordon Ross * Do negotiation decisions and encode the reply.
75893bc28dbSGordon Ross * The caller does the network send.
75993bc28dbSGordon Ross *
760ebc5aadbSAndrew Stormont * Return value is 0 for success, else error.
761a90cf9f2SGordon Ross */
762a90cf9f2SGordon Ross static int
smb2_negotiate_common(smb_request_t * sr,uint16_t version)763a90cf9f2SGordon Ross smb2_negotiate_common(smb_request_t *sr, uint16_t version)
764a90cf9f2SGordon Ross {
765a90cf9f2SGordon Ross timestruc_t boot_tv, now_tv;
766a90cf9f2SGordon Ross smb_session_t *s = sr->session;
767ab017dbaSGordon Ross smb2_arg_negotiate_t *nego = sr->arg.other;
768a90cf9f2SGordon Ross int rc;
769aa321b3cSDan McDonald uint32_t max_rwsize;
770a90cf9f2SGordon Ross uint16_t secmode;
7714e065a9fSAlexander Stetsenko uint16_t neg_ctx_cnt = 0;
7724e065a9fSAlexander Stetsenko uint32_t neg_ctx_off = 0;
773a90cf9f2SGordon Ross
774a90cf9f2SGordon Ross /*
775a90cf9f2SGordon Ross * Negotiation itself. First the Security Mode.
776a90cf9f2SGordon Ross */
777a90cf9f2SGordon Ross secmode = SMB2_NEGOTIATE_SIGNING_ENABLED;
778ebc5aadbSAndrew Stormont if (sr->sr_cfg->skc_signing_required)
779a90cf9f2SGordon Ross secmode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
7801160dcf7SMatt Barden s->srv_secmode = secmode;
781a90cf9f2SGordon Ross
782a90cf9f2SGordon Ross s->cmd_max_bytes = smb2_tcp_bufsize;
783a90cf9f2SGordon Ross s->reply_max_bytes = smb2_tcp_bufsize;
784a90cf9f2SGordon Ross
785a90cf9f2SGordon Ross /*
786a90cf9f2SGordon Ross * "The number of credits held by the client MUST be considered
787a90cf9f2SGordon Ross * as 1 when the connection is established." [MS-SMB2]
788a90cf9f2SGordon Ross * We leave credits at 1 until the first successful
789a90cf9f2SGordon Ross * session setup is completed.
790a90cf9f2SGordon Ross */
791a90cf9f2SGordon Ross s->s_cur_credits = s->s_max_credits = 1;
792a90cf9f2SGordon Ross sr->smb2_credit_response = 1;
793a90cf9f2SGordon Ross
794a90cf9f2SGordon Ross boot_tv.tv_sec = smb_get_boottime();
795a90cf9f2SGordon Ross boot_tv.tv_nsec = 0;
796a90cf9f2SGordon Ross now_tv.tv_sec = gethrestime_sec();
797a90cf9f2SGordon Ross now_tv.tv_nsec = 0;
798a90cf9f2SGordon Ross
799a90cf9f2SGordon Ross /*
800c51c88bdSMatt Barden * If the version is 0x2FF, we haven't completed negotiate.
801c51c88bdSMatt Barden * Don't initialize until we have our final request.
802c51c88bdSMatt Barden */
803c51c88bdSMatt Barden if (version != 0x2FF)
804c51c88bdSMatt Barden smb2_sign_init_mech(s);
8054e065a9fSAlexander Stetsenko if (version >= 0x311)
8064e065a9fSAlexander Stetsenko smb31_preauth_init_mech(s);
807c51c88bdSMatt Barden
808c51c88bdSMatt Barden /*
8091160dcf7SMatt Barden * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
8101160dcf7SMatt Barden *
8118d94f651SGordon Ross * The SMB2.x capabilities are returned without regard for
8128d94f651SGordon Ross * what capabilities the client provided in the request.
8138d94f651SGordon Ross * The SMB3.x capabilities returned are the traditional
814ab017dbaSGordon Ross * logical AND of server and client capabilities, except
815ab017dbaSGordon Ross * for the SMB2.x capabilities which are what the server
816ab017dbaSGordon Ross * supports (regardless of the client capabilities).
8178d94f651SGordon Ross *
8188d94f651SGordon Ross * One additional check: If KCF is missing something we
8198d94f651SGordon Ross * require for encryption, turn off that capability.
8201160dcf7SMatt Barden */
821700daa96SAndrew Stormont if (s->dialect < SMB_VERS_2_1) {
822700daa96SAndrew Stormont /* SMB 2.002 */
823700daa96SAndrew Stormont s->srv_cap = smb2srv_capabilities & SMB2_CAP_DFS;
824700daa96SAndrew Stormont } else if (s->dialect < SMB_VERS_3_0) {
8258d94f651SGordon Ross /* SMB 2.x */
8268d94f651SGordon Ross s->srv_cap = smb2srv_capabilities & SMB_2X_CAPS;
8278d94f651SGordon Ross } else {
8288d94f651SGordon Ross /* SMB 3.0 or later */
8298d94f651SGordon Ross s->srv_cap = smb2srv_capabilities &
8308d94f651SGordon Ross (SMB_2X_CAPS | s->capabilities);
831ab017dbaSGordon Ross
832ab017dbaSGordon Ross if (s->dialect < SMB_VERS_3_11)
833ab017dbaSGordon Ross s->smb31_enc_cipherid = SMB3_CIPHER_AES128_CCM;
834ab017dbaSGordon Ross /* else from negotiate context */
835ab017dbaSGordon Ross
8368d94f651SGordon Ross if ((s->srv_cap & SMB2_CAP_ENCRYPTION) != 0 &&
8378d94f651SGordon Ross smb3_encrypt_init_mech(s) != 0) {
8388d94f651SGordon Ross s->srv_cap &= ~SMB2_CAP_ENCRYPTION;
8394e065a9fSAlexander Stetsenko }
8404e065a9fSAlexander Stetsenko
8414e065a9fSAlexander Stetsenko if (s->dialect >= SMB_VERS_3_11) {
842ab017dbaSGordon Ross smb2_encrypt_caps_t *encap =
843ab017dbaSGordon Ross &nego->neg_in_ctxs.encrypt_ctx.encrypt_caps;
844ab017dbaSGordon Ross
845ab017dbaSGordon Ross neg_ctx_cnt = 1; // always have preauth
846ab017dbaSGordon Ross
847ab017dbaSGordon Ross if (encap->encap_cipher_count != 0)
848ab017dbaSGordon Ross neg_ctx_cnt++;
849ab017dbaSGordon Ross
8504e065a9fSAlexander Stetsenko neg_ctx_off = NEG_CTX_OFFSET_OFFSET +
8514e065a9fSAlexander Stetsenko P2ROUNDUP(sr->sr_cfg->skc_negtok_len, 8);
8524e065a9fSAlexander Stetsenko
8534e065a9fSAlexander Stetsenko ASSERT3U(s->smb31_preauth_hashid, !=, 0);
8544e065a9fSAlexander Stetsenko
8554e065a9fSAlexander Stetsenko if (smb31_preauth_sha512_calc(sr, &sr->command,
8564e065a9fSAlexander Stetsenko s->smb31_preauth_hashval,
8574e065a9fSAlexander Stetsenko s->smb31_preauth_hashval) != 0)
8584e065a9fSAlexander Stetsenko cmn_err(CE_WARN, "(0) Preauth hash calculation "
8594e065a9fSAlexander Stetsenko "failed");
8608d94f651SGordon Ross }
8618d94f651SGordon Ross }
8621160dcf7SMatt Barden
8631160dcf7SMatt Barden /*
864aa321b3cSDan McDonald * See notes above smb2_max_rwsize, smb2_old_rwsize
865aa321b3cSDan McDonald */
866aa321b3cSDan McDonald if (s->capabilities & SMB2_CAP_LARGE_MTU)
867aa321b3cSDan McDonald max_rwsize = smb2_max_rwsize;
868aa321b3cSDan McDonald else
869aa321b3cSDan McDonald max_rwsize = smb2_old_rwsize;
870aa321b3cSDan McDonald
871a90cf9f2SGordon Ross rc = smb_mbc_encodef(
872a90cf9f2SGordon Ross &sr->reply,
873a90cf9f2SGordon Ross "wwww#cllllTTwwl#c",
874a90cf9f2SGordon Ross 65, /* StructSize */ /* w */
8751160dcf7SMatt Barden s->srv_secmode, /* w */
876a90cf9f2SGordon Ross version, /* w */
8774e065a9fSAlexander Stetsenko neg_ctx_cnt, /* w */
878a90cf9f2SGordon Ross UUID_LEN, /* # */
879a90cf9f2SGordon Ross &s->s_cfg.skc_machine_uuid, /* c */
8801160dcf7SMatt Barden s->srv_cap, /* l */
881a90cf9f2SGordon Ross smb2_max_trans, /* l */
882aa321b3cSDan McDonald max_rwsize, /* l */
883aa321b3cSDan McDonald max_rwsize, /* l */
884a90cf9f2SGordon Ross &now_tv, /* T */
885a90cf9f2SGordon Ross &boot_tv, /* T */
886a90cf9f2SGordon Ross 128, /* SecBufOff */ /* w */
887a90cf9f2SGordon Ross sr->sr_cfg->skc_negtok_len, /* w */
8884e065a9fSAlexander Stetsenko neg_ctx_off, /* l */
889a90cf9f2SGordon Ross sr->sr_cfg->skc_negtok_len, /* # */
890a90cf9f2SGordon Ross sr->sr_cfg->skc_negtok); /* c */
891a90cf9f2SGordon Ross
892ab017dbaSGordon Ross /* Note: smb31_encode_neg_ctxs() follows in caller */
8934e065a9fSAlexander Stetsenko
89493bc28dbSGordon Ross /* smb2_send_reply(sr); in caller */
895a90cf9f2SGordon Ross
896a90cf9f2SGordon Ross (void) ksocket_setsockopt(s->sock, SOL_SOCKET,
897a90cf9f2SGordon Ross SO_SNDBUF, (const void *)&smb2_tcp_bufsize,
898a90cf9f2SGordon Ross sizeof (smb2_tcp_bufsize), CRED());
899a90cf9f2SGordon Ross (void) ksocket_setsockopt(s->sock, SOL_SOCKET,
900a90cf9f2SGordon Ross SO_RCVBUF, (const void *)&smb2_tcp_bufsize,
901a90cf9f2SGordon Ross sizeof (smb2_tcp_bufsize), CRED());
902a90cf9f2SGordon Ross
903a90cf9f2SGordon Ross return (rc);
904a90cf9f2SGordon Ross }
905a90cf9f2SGordon Ross
906a90cf9f2SGordon Ross /*
907a90cf9f2SGordon Ross * SMB2 Dispatch table handler, which will run if we see an
908a90cf9f2SGordon Ross * SMB2_NEGOTIATE after the initial negotiation is done.
909a90cf9f2SGordon Ross * That would be a protocol error.
910a90cf9f2SGordon Ross */
911a90cf9f2SGordon Ross smb_sdrc_t
smb2_negotiate(smb_request_t * sr)912a90cf9f2SGordon Ross smb2_negotiate(smb_request_t *sr)
913a90cf9f2SGordon Ross {
914a90cf9f2SGordon Ross sr->smb2_status = NT_STATUS_INVALID_PARAMETER;
915a90cf9f2SGordon Ross return (SDRC_ERROR);
916a90cf9f2SGordon Ross }
917a90cf9f2SGordon Ross
918a90cf9f2SGordon Ross /*
919a90cf9f2SGordon Ross * VALIDATE_NEGOTIATE_INFO [MS-SMB2] 2.2.32.6
920a90cf9f2SGordon Ross */
921a90cf9f2SGordon Ross uint32_t
smb2_nego_validate(smb_request_t * sr,smb_fsctl_t * fsctl)92255f0a249SGordon Ross smb2_nego_validate(smb_request_t *sr, smb_fsctl_t *fsctl)
923a90cf9f2SGordon Ross {
924a90cf9f2SGordon Ross smb_session_t *s = sr->session;
925a90cf9f2SGordon Ross int rc;
926a90cf9f2SGordon Ross
927a90cf9f2SGordon Ross /*
928a90cf9f2SGordon Ross * The spec. says to parse the VALIDATE_NEGOTIATE_INFO here
929a90cf9f2SGordon Ross * and verify that the original negotiate was not modified.
930a90cf9f2SGordon Ross *
931a90cf9f2SGordon Ross * One interesting requirement here is that we MUST reply
932a90cf9f2SGordon Ross * with exactly the same information as we returned in our
933a90cf9f2SGordon Ross * original reply to the SMB2 negotiate on this session.
934a90cf9f2SGordon Ross * If we don't the client closes the connection.
935a90cf9f2SGordon Ross */
936a90cf9f2SGordon Ross
9371160dcf7SMatt Barden uint32_t capabilities;
9384e065a9fSAlexander Stetsenko uint16_t secmode;
9394e065a9fSAlexander Stetsenko uint16_t num_dialects;
9404e065a9fSAlexander Stetsenko uint16_t dialects[SMB2_NEGOTIATE_MAX_DIALECTS];
9411160dcf7SMatt Barden uint8_t clnt_guid[16];
9421160dcf7SMatt Barden
9434e065a9fSAlexander Stetsenko if (s->dialect >= SMB_VERS_3_11)
9444e065a9fSAlexander Stetsenko goto drop;
9454e065a9fSAlexander Stetsenko
946715c0bc6SAndrew Stormont /*
947715c0bc6SAndrew Stormont * [MS-SMB2] 3.3.5.2.4 Verifying the Signature
948715c0bc6SAndrew Stormont *
949715c0bc6SAndrew Stormont * If the dialect is SMB3 and the message was successfully
950715c0bc6SAndrew Stormont * decrypted we MUST skip processing of the signature.
951715c0bc6SAndrew Stormont */
952715c0bc6SAndrew Stormont if (!sr->encrypted && (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) == 0)
9534ad35fa3SMatt Barden goto drop;
9544ad35fa3SMatt Barden
9551160dcf7SMatt Barden if (fsctl->InputCount < 24)
9561160dcf7SMatt Barden goto drop;
9571160dcf7SMatt Barden
9581160dcf7SMatt Barden (void) smb_mbc_decodef(fsctl->in_mbc, "l16cww",
9591160dcf7SMatt Barden &capabilities, /* l */
9601160dcf7SMatt Barden &clnt_guid, /* 16c */
9611160dcf7SMatt Barden &secmode, /* w */
9621160dcf7SMatt Barden &num_dialects); /* w */
9631160dcf7SMatt Barden
9644e065a9fSAlexander Stetsenko if (num_dialects == 0 || num_dialects > SMB2_NEGOTIATE_MAX_DIALECTS)
9654e065a9fSAlexander Stetsenko goto drop;
9661160dcf7SMatt Barden if (secmode != s->cli_secmode)
9671160dcf7SMatt Barden goto drop;
9681160dcf7SMatt Barden if (capabilities != s->capabilities)
9691160dcf7SMatt Barden goto drop;
9701160dcf7SMatt Barden if (memcmp(clnt_guid, s->clnt_uuid, sizeof (clnt_guid)) != 0)
9711160dcf7SMatt Barden goto drop;
9721160dcf7SMatt Barden
9731160dcf7SMatt Barden rc = smb_mbc_decodef(fsctl->in_mbc, "#w", num_dialects, dialects);
9741160dcf7SMatt Barden if (rc != 0)
9751160dcf7SMatt Barden goto drop;
9761160dcf7SMatt Barden
977b716e3d0SGordon Ross /*
978b716e3d0SGordon Ross * MS-SMB2 says we should compare the dialects array with the
979b716e3d0SGordon Ross * one sent previously, but that appears to be unnecessary
980b716e3d0SGordon Ross * as long as we end up with the same dialect.
981b716e3d0SGordon Ross */
982b716e3d0SGordon Ross if (smb2_find_best_dialect(s, dialects, num_dialects) != s->dialect)
9831160dcf7SMatt Barden goto drop;
9841160dcf7SMatt Barden
985a90cf9f2SGordon Ross rc = smb_mbc_encodef(
986a90cf9f2SGordon Ross fsctl->out_mbc, "l#cww",
9871160dcf7SMatt Barden s->srv_cap, /* l */
988a90cf9f2SGordon Ross UUID_LEN, /* # */
989a90cf9f2SGordon Ross &s->s_cfg.skc_machine_uuid, /* c */
9901160dcf7SMatt Barden s->srv_secmode, /* w */
991a90cf9f2SGordon Ross s->dialect); /* w */
9921160dcf7SMatt Barden if (rc == 0)
9931160dcf7SMatt Barden return (rc);
994a90cf9f2SGordon Ross
9951160dcf7SMatt Barden drop:
9961160dcf7SMatt Barden smb_session_disconnect(s);
9971160dcf7SMatt Barden return (NT_STATUS_ACCESS_DENIED);
998a90cf9f2SGordon Ross }
999