1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2393bc28dbSGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * Notes on the virtual circuit (VC) values in the SMB Negotiate
28da6c28aaSamw  * response and SessionSetupAndx request.
29da6c28aaSamw  *
30da6c28aaSamw  * A virtual circuit (VC) represents a connection between a client and a
31da6c28aaSamw  * server using a reliable, session oriented transport protocol, such as
32da6c28aaSamw  * NetBIOS or TCP/IP. Originally, each SMB session was restricted to a
33da6c28aaSamw  * single underlying transport connection, i.e. a single NetBIOS session,
34da6c28aaSamw  * which limited performance for raw data transfers.
35da6c28aaSamw  *
36da6c28aaSamw  * The intention behind multiple VCs was to improve performance by
37da6c28aaSamw  * allowing parallelism over each NetBIOS session. For example, raw data
38da6c28aaSamw  * could be transmitted using a different VC from other types of SMB
39da6c28aaSamw  * requests to remove the interleaving restriction while a raw transfer
40da6c28aaSamw  * is in progress. So the MaxNumberVcs field was added to the negotiate
41da6c28aaSamw  * response to make the number of VCs configurable and to allow servers
42da6c28aaSamw  * to specify how many they were prepared to support per session
43da6c28aaSamw  * connection. This turned out to be difficult to manage and, with
44da6c28aaSamw  * technology improvements, it has become obsolete.
45da6c28aaSamw  *
46da6c28aaSamw  * Servers should set the MaxNumberVcs value in the Negotiate response
47da6c28aaSamw  * to 1. Clients should probably ignore it. If a server receives a
48da6c28aaSamw  * SessionSetupAndx with a VC value of 0, it should close all other
49da6c28aaSamw  * VCs to that client. If it receives a non-zero VC, it should leave
50da6c28aaSamw  * other VCs in tact.
51da6c28aaSamw  *
52da6c28aaSamw  */
53da6c28aaSamw 
54da6c28aaSamw /*
55da6c28aaSamw  * SMB: negotiate
56da6c28aaSamw  *
57da6c28aaSamw  * Client Request                Description
58da6c28aaSamw  * ============================  =======================================
59da6c28aaSamw  *
60da6c28aaSamw  * UCHAR WordCount;              Count of parameter words = 0
61da6c28aaSamw  * USHORT ByteCount;             Count of data bytes; min = 2
62da6c28aaSamw  * struct {
63da6c28aaSamw  *    UCHAR BufferFormat;        0x02 -- Dialect
64da6c28aaSamw  *    UCHAR DialectName[];       ASCII null-terminated string
65da6c28aaSamw  * } Dialects[];
66da6c28aaSamw  *
67da6c28aaSamw  * The Client sends a list of dialects that it can communicate with.  The
68da6c28aaSamw  * response is a selection of one of those dialects (numbered 0 through n)
69da6c28aaSamw  * or -1 (hex FFFF) indicating that none of the dialects were acceptable.
70da6c28aaSamw  * The negotiate message is binding on the virtual circuit and must be
71da6c28aaSamw  * sent.  One and only one negotiate message may be sent, subsequent
72da6c28aaSamw  * negotiate requests will be rejected with an error response and no action
73da6c28aaSamw  * will be taken.
74da6c28aaSamw  *
75da6c28aaSamw  * The protocol does not impose any particular structure to the dialect
76da6c28aaSamw  * strings.  Implementors of particular protocols may choose to include,
77da6c28aaSamw  * for example, version numbers in the string.
78da6c28aaSamw  *
79da6c28aaSamw  * If the server does not understand any of the dialect strings, or if PC
80da6c28aaSamw  * NETWORK PROGRAM 1.0 is the chosen dialect, the response format is
81da6c28aaSamw  *
82da6c28aaSamw  * Server Response               Description
83da6c28aaSamw  * ============================  =======================================
84da6c28aaSamw  *
85da6c28aaSamw  * UCHAR WordCount;              Count of parameter words = 1
86da6c28aaSamw  * USHORT DialectIndex;          Index of selected dialect
87da6c28aaSamw  * USHORT ByteCount;             Count of data bytes = 0
88da6c28aaSamw  *
89da6c28aaSamw  * If the chosen dialect is greater than core up to and including
90da6c28aaSamw  * LANMAN2.1, the protocol response format is
91da6c28aaSamw  *
92da6c28aaSamw  * Server Response               Description
93da6c28aaSamw  * ============================  =======================================
94da6c28aaSamw  *
95da6c28aaSamw  * UCHAR WordCount;              Count of parameter words = 13
96da6c28aaSamw  * USHORT  DialectIndex;         Index of selected dialect
97da6c28aaSamw  * USHORT  SecurityMode;         Security mode:
98da6c28aaSamw  *                               bit 0: 0 = share, 1 = user
99da6c28aaSamw  *                               bit 1: 1 = use challenge/response
100da6c28aaSamw  *                               authentication
101da6c28aaSamw  * USHORT  MaxBufferSize;        Max transmit buffer size (>= 1024)
102da6c28aaSamw  * USHORT  MaxMpxCount;          Max pending multiplexed requests
103da6c28aaSamw  * USHORT  MaxNumberVcs;         Max VCs between client and server
104da6c28aaSamw  * USHORT  RawMode;              Raw modes supported:
105da6c28aaSamw  *                                bit 0: 1 = Read Raw supported
106da6c28aaSamw  *                                bit 1: 1 = Write Raw supported
107da6c28aaSamw  * ULONG SessionKey;             Unique token identifying this session
108da6c28aaSamw  * SMB_TIME ServerTime;          Current time at server
109da6c28aaSamw  * SMB_DATE ServerDate;          Current date at server
110da6c28aaSamw  * USHORT ServerTimeZone;        Current time zone at server
111da6c28aaSamw  * USHORT  EncryptionKeyLength;  MBZ if this is not LM2.1
112da6c28aaSamw  * USHORT  Reserved;             MBZ
113da6c28aaSamw  * USHORT  ByteCount             Count of data bytes
114da6c28aaSamw  * UCHAR EncryptionKey[];        The challenge encryption key
115da6c28aaSamw  * STRING PrimaryDomain[];       The server's primary domain
116da6c28aaSamw  *
117da6c28aaSamw  * MaxBufferSize is the size of the largest message which the client can
118da6c28aaSamw  * legitimately send to the server
119da6c28aaSamw  *
120da6c28aaSamw  * If  bit0 of the Flags field is set in the negotiate response, this
121da6c28aaSamw  * indicates the server supports the SMB_COM_LOCK_AND_READ and
122da6c28aaSamw  * SMB_COM_WRITE_AND_UNLOCK client requests.
123da6c28aaSamw  *
124da6c28aaSamw  * If the SecurityMode field indicates the server is running in user mode,
125da6c28aaSamw  * the client must send appropriate SMB_COM_SESSION_SETUP_ANDX requests
126da6c28aaSamw  * before the server will allow the client to access resources.   If the
127da6c28aaSamw  * SecurityMode fields indicates the client should use challenge/response
128da6c28aaSamw  * authentication, the client should use the authentication mechanism
129da6c28aaSamw  * specified in section 2.10.
130da6c28aaSamw  *
131da6c28aaSamw  * Clients should submit no more than MaxMpxCount distinct unanswered SMBs
132da6c28aaSamw  * to the server when using multiplexed reads or writes (see sections 5.13
133da6c28aaSamw  * and 5.25)
134da6c28aaSamw  *
135da6c28aaSamw  * Clients using the  "MICROSOFT NETWORKS 1.03" dialect use a different
136da6c28aaSamw  * form of raw reads than documented here, and servers are better off
137da6c28aaSamw  * setting RawMode in this response to 0 for such sessions.
138da6c28aaSamw  *
139da6c28aaSamw  * If the negotiated dialect is "DOS LANMAN2.1" or "LANMAN2.1", then
140da6c28aaSamw  * PrimaryDomain string should be included in this response.
141da6c28aaSamw  *
142da6c28aaSamw  * If the negotiated dialect is NT LM 0.12, the response format is
143da6c28aaSamw  *
144da6c28aaSamw  * Server Response            Description
145da6c28aaSamw  * ========================== =========================================
146da6c28aaSamw  *
147da6c28aaSamw  * UCHAR WordCount;           Count of parameter words = 17
148da6c28aaSamw  * USHORT DialectIndex;       Index of selected dialect
149da6c28aaSamw  * UCHAR SecurityMode;        Security mode:
150da6c28aaSamw  *                             bit 0: 0 = share, 1 = user
151da6c28aaSamw  *                             bit 1: 1 = encrypt passwords
152da6c28aaSamw  * USHORT MaxMpxCount;        Max pending multiplexed requests
153da6c28aaSamw  * USHORT MaxNumberVcs;       Max VCs between client and server
154da6c28aaSamw  * ULONG MaxBufferSize;       Max transmit buffer size
155da6c28aaSamw  * ULONG MaxRawSize;          Maximum raw buffer size
156da6c28aaSamw  * ULONG SessionKey;          Unique token identifying this session
157da6c28aaSamw  * ULONG Capabilities;        Server capabilities
158da6c28aaSamw  * ULONG SystemTimeLow;       System (UTC) time of the server (low).
159da6c28aaSamw  * ULONG SystemTimeHigh;      System (UTC) time of the server (high).
160da6c28aaSamw  * USHORT ServerTimeZone;     Time zone of server (min from UTC)
161da6c28aaSamw  * UCHAR EncryptionKeyLength; Length of encryption key.
162da6c28aaSamw  * USHORT ByteCount;          Count of data bytes
163da6c28aaSamw  * UCHAR EncryptionKey[];     The challenge encryption key
164da6c28aaSamw  * UCHAR OemDomainName[];     The name of the domain (in OEM chars)
165da6c28aaSamw  *
166da6c28aaSamw  * In addition to the definitions above, MaxBufferSize is the size of the
167da6c28aaSamw  * largest message which the client can legitimately send to the server.
168da6c28aaSamw  * If the client is using a connectionless protocol,  MaxBufferSize must be
169da6c28aaSamw  * set to the smaller of the server's internal buffer size and the amount
170da6c28aaSamw  * of data which can be placed in a response packet.
171da6c28aaSamw  *
172da6c28aaSamw  * MaxRawSize specifies the maximum message size the server can send or
173da6c28aaSamw  * receive for SMB_COM_WRITE_RAW or SMB_COM_READ_RAW.
174da6c28aaSamw  *
175da6c28aaSamw  * Connectionless clients must set Sid to 0 in the SMB request header.
176da6c28aaSamw  *
177da6c28aaSamw  * Capabilities allows the server to tell the client what it supports.
178bbf6f00cSJordan Brown  * The bit definitions defined in smb.h. Bit 0x2000 used to be set in
179da6c28aaSamw  * the negotiate response capabilities but it caused problems with
180da6c28aaSamw  * Windows 2000. It is probably not valid, it doesn't appear in the
181da6c28aaSamw  * CIFS spec.
182da6c28aaSamw  *
183da6c28aaSamw  * 4.1.1.1   Errors
184da6c28aaSamw  *
185da6c28aaSamw  * SUCCESS/SUCCESS
186da6c28aaSamw  * ERRSRV/ERRerror
187da6c28aaSamw  */
188da6c28aaSamw #include <sys/types.h>
189da6c28aaSamw #include <sys/socket.h>
190da6c28aaSamw #include <netinet/in.h>
191bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
192da6c28aaSamw #include <smbsrv/smbinfo.h>
193da6c28aaSamw 
1948622ec45SGordon Ross static const smb_xlate_t smb_dialect[] = {
195148c5f43SAlan Wright 	{ DIALECT_UNKNOWN,		"DIALECT_UNKNOWN" },
196148c5f43SAlan Wright 	{ PC_NETWORK_PROGRAM_1_0,	"PC NETWORK PROGRAM 1.0" },
197148c5f43SAlan Wright 	{ PCLAN1_0,			"PCLAN1.0" },
198148c5f43SAlan Wright 	{ MICROSOFT_NETWORKS_1_03,	"MICROSOFT NETWORKS 1.03" },
199148c5f43SAlan Wright 	{ MICROSOFT_NETWORKS_3_0,	"MICROSOFT NETWORKS 3.0" },
200148c5f43SAlan Wright 	{ LANMAN1_0,			"LANMAN1.0" },
201148c5f43SAlan Wright 	{ LM1_2X002,			"LM1.2X002" },
202148c5f43SAlan Wright 	{ DOS_LM1_2X002,		"DOS LM1.2X002" },
203148c5f43SAlan Wright 	{ DOS_LANMAN2_1,		"DOS LANMAN2.1" },
204148c5f43SAlan Wright 	{ LANMAN2_1,			"LANMAN2.1" },
205148c5f43SAlan Wright 	{ Windows_for_Workgroups_3_1a,	"Windows for Workgroups 3.1a" },
206a90cf9f2SGordon Ross 	{ NT_LM_0_12,			"NT LM 0.12" },
207a90cf9f2SGordon Ross 	{ DIALECT_SMB2002,		"SMB 2.002" },
208a90cf9f2SGordon Ross 	{ DIALECT_SMB2XXX,		"SMB 2.???" },
209148c5f43SAlan Wright };
210a90cf9f2SGordon Ross static int smb_ndialects = sizeof (smb_dialect) / sizeof (smb_dialect[0]);
211148c5f43SAlan Wright 
212da6c28aaSamw /*
213da6c28aaSamw  * Maximum buffer size for DOS: chosen to be the same as NT.
214da6c28aaSamw  * Do not change this value, DOS is very sensitive to it.
215da6c28aaSamw  */
216da6c28aaSamw #define	SMB_DOS_MAXBUF			0x1104
217da6c28aaSamw 
218da6c28aaSamw /*
219da6c28aaSamw  * The DOS TCP rcvbuf is set to 8700 because DOS 6.1 seems to have problems
220da6c28aaSamw  * with other values. DOS 6.1 seems to depend on a window value of 8700 to
221da6c28aaSamw  * send the next set of data. If we return a window value of 40KB, after
222da6c28aaSamw  * sending 8700 bytes of data, it will start the next set of data from 40KB
223da6c28aaSamw  * instead of 8.7k. Why 8.7k? We have no idea; it is the value that NT uses.
224da6c28aaSamw  * September 2000.
225da6c28aaSamw  *
226da6c28aaSamw  * IR104720 Increased smb_nt_tcp_rcvbuf from 40KB to just under 1MB to allow
227da6c28aaSamw  * for a larger TCP window sizei based on observations of Windows 2000 and
228da6c28aaSamw  * performance testing. March 2003.
229da6c28aaSamw  */
230faa1795aSjb static uint32_t	smb_dos_tcp_rcvbuf = 8700;
231faa1795aSjb static uint32_t	smb_nt_tcp_rcvbuf = 1048560;	/* scale factor of 4 */
232da6c28aaSamw 
233a90cf9f2SGordon Ross /*
234a90cf9f2SGordon Ross  * Maximum number of simultaneously pending SMB requests allowed on
235a90cf9f2SGordon Ross  * one connection.  This is like "credits" in SMB2, but SMB1 uses a
236a90cf9f2SGordon Ross  * fixed limit, having no way to request an increase like SMB2 does.
237a90cf9f2SGordon Ross  * Note: Some older clients only handle the low byte of this value,
238a90cf9f2SGordon Ross  * so this value should be less than 256.
239a90cf9f2SGordon Ross  */
240a90cf9f2SGordon Ross static uint16_t smb_maxmpxcount = 64;
241a90cf9f2SGordon Ross 
242148c5f43SAlan Wright static int smb_xlate_dialect(const char *);
243da6c28aaSamw 
24412b65585SGordon Ross /*
24512b65585SGordon Ross  * "Capabilities" offered by SMB1 Negotiate Protocol.
24612b65585SGordon Ross  * See smb.h for descriptions.
24712b65585SGordon Ross  *
24812b65585SGordon Ross  * CAP_RAW_MODE, CAP_MPX_MODE are obsolete.
24912b65585SGordon Ross  * UNICODE support is required for long share names,
25012b65585SGordon Ross  * long file names and streams.
25112b65585SGordon Ross  *
25212b65585SGordon Ross  * For testing, one can patch this, i.e. remove the high bit to
25312b65585SGordon Ross  * temporarily disable extended security, etc.
25412b65585SGordon Ross  */
25512b65585SGordon Ross uint32_t smb1srv_capabilities =
25612b65585SGordon Ross 	CAP_UNICODE |
25712b65585SGordon Ross 	CAP_LARGE_FILES |
25812b65585SGordon Ross 	CAP_NT_SMBS |
25912b65585SGordon Ross 	CAP_RPC_REMOTE_APIS |
26012b65585SGordon Ross 	CAP_STATUS32 |
26112b65585SGordon Ross 	CAP_LEVEL_II_OPLOCKS |
26212b65585SGordon Ross 	CAP_LOCK_AND_READ |
26312b65585SGordon Ross 	CAP_NT_FIND |
26412b65585SGordon Ross 	CAP_DFS |
26512b65585SGordon Ross 	CAP_INFOLEVEL_PASSTHRU |
26612b65585SGordon Ross 	CAP_LARGE_READX |
26712b65585SGordon Ross 	CAP_LARGE_WRITEX |
26812b65585SGordon Ross 	CAP_EXTENDED_SECURITY;
2699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
270a90cf9f2SGordon Ross /*
271a90cf9f2SGordon Ross  * SMB Negotiate gets special handling.  This is called directly by
272a90cf9f2SGordon Ross  * the reader thread (see smbsr_newrq_initial) with what _should_ be
273a90cf9f2SGordon Ross  * an SMB1 Negotiate.  Only the "\ffSMB" header has been checked
274a90cf9f2SGordon Ross  * when this is called, so this needs to check the SMB command,
275a90cf9f2SGordon Ross  * if it's Negotiate execute it, then send the reply, etc.
276a90cf9f2SGordon Ross  *
277a90cf9f2SGordon Ross  * Since this is called directly from the reader thread, we
278a90cf9f2SGordon Ross  * know this is the only thread currently using this session.
279a90cf9f2SGordon Ross  * This has to duplicate some of what smb1sr_work does as a
280a90cf9f2SGordon Ross  * result of bypassing the normal dispatch mechanism.
281a90cf9f2SGordon Ross  *
282a90cf9f2SGordon Ross  * The caller always frees this request.
28393bc28dbSGordon Ross  *
28493bc28dbSGordon Ross  * Return value is 0 for success, and anything else will
28593bc28dbSGordon Ross  * terminate the reader thread (drop the connection).
286a90cf9f2SGordon Ross  */
287a90cf9f2SGordon Ross int
smb1_newrq_negotiate(smb_request_t * sr)288a90cf9f2SGordon Ross smb1_newrq_negotiate(smb_request_t *sr)
289a90cf9f2SGordon Ross {
290a90cf9f2SGordon Ross 	smb_sdrc_t	sdrc;
291a90cf9f2SGordon Ross 	uint16_t	pid_hi, pid_lo;
292a90cf9f2SGordon Ross 
293a90cf9f2SGordon Ross 	/*
294a90cf9f2SGordon Ross 	 * Decode the header
295a90cf9f2SGordon Ross 	 */
296a90cf9f2SGordon Ross 	if (smb_mbc_decodef(&sr->command, SMB_HEADER_ED_FMT,
297a90cf9f2SGordon Ross 	    &sr->smb_com,
298a90cf9f2SGordon Ross 	    &sr->smb_rcls,
299a90cf9f2SGordon Ross 	    &sr->smb_reh,
300a90cf9f2SGordon Ross 	    &sr->smb_err,
301a90cf9f2SGordon Ross 	    &sr->smb_flg,
302a90cf9f2SGordon Ross 	    &sr->smb_flg2,
303a90cf9f2SGordon Ross 	    &pid_hi,
304a90cf9f2SGordon Ross 	    sr->smb_sig,
305a90cf9f2SGordon Ross 	    &sr->smb_tid,
306a90cf9f2SGordon Ross 	    &pid_lo,
307a90cf9f2SGordon Ross 	    &sr->smb_uid,
308a90cf9f2SGordon Ross 	    &sr->smb_mid) != 0)
309a90cf9f2SGordon Ross 		return (-1);
310a90cf9f2SGordon Ross 	if (sr->smb_com != SMB_COM_NEGOTIATE)
311a90cf9f2SGordon Ross 		return (-1);
312a90cf9f2SGordon Ross 
313a90cf9f2SGordon Ross 	sr->smb_pid = (pid_hi << 16) | pid_lo;
314a90cf9f2SGordon Ross 
315a90cf9f2SGordon Ross 	/*
316a90cf9f2SGordon Ross 	 * Reserve space for the reply header.
317a90cf9f2SGordon Ross 	 */
318a90cf9f2SGordon Ross 	(void) smb_mbc_encodef(&sr->reply, "#.", SMB_HEADER_LEN);
319a90cf9f2SGordon Ross 	sr->first_smb_com = sr->smb_com;
320a90cf9f2SGordon Ross 
321a90cf9f2SGordon Ross 	if (smb_mbc_decodef(&sr->command, "b", &sr->smb_wct) != 0)
322a90cf9f2SGordon Ross 		return (-1);
323a90cf9f2SGordon Ross 	(void) MBC_SHADOW_CHAIN(&sr->smb_vwv, &sr->command,
324a90cf9f2SGordon Ross 	    sr->command.chain_offset, sr->smb_wct * 2);
325a90cf9f2SGordon Ross 
326a90cf9f2SGordon Ross 	if (smb_mbc_decodef(&sr->command, "#.w", sr->smb_wct*2, &sr->smb_bcc))
327a90cf9f2SGordon Ross 		return (-1);
328a90cf9f2SGordon Ross 	(void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command,
329a90cf9f2SGordon Ross 	    sr->command.chain_offset, sr->smb_bcc);
330a90cf9f2SGordon Ross 
331a90cf9f2SGordon Ross 	sr->command.chain_offset += sr->smb_bcc;
332a90cf9f2SGordon Ross 	if (sr->command.chain_offset > sr->command.max_bytes)
333a90cf9f2SGordon Ross 		return (-1);
334a90cf9f2SGordon Ross 
335a90cf9f2SGordon Ross 	/* Store pointers for later */
336a90cf9f2SGordon Ross 	sr->cur_reply_offset = sr->reply.chain_offset;
337a90cf9f2SGordon Ross 
338a90cf9f2SGordon Ross 	sdrc = smb_pre_negotiate(sr);
339a90cf9f2SGordon Ross 	if (sdrc == SDRC_SUCCESS)
340a90cf9f2SGordon Ross 		sdrc = smb_com_negotiate(sr);
341a90cf9f2SGordon Ross 	smb_post_negotiate(sr);
342a90cf9f2SGordon Ross 
343a90cf9f2SGordon Ross 	if (sdrc != SDRC_NO_REPLY)
344a90cf9f2SGordon Ross 		smbsr_send_reply(sr);
345a90cf9f2SGordon Ross 	if (sdrc == SDRC_DROP_VC)
346a90cf9f2SGordon Ross 		return (-1);
347a90cf9f2SGordon Ross 
348a90cf9f2SGordon Ross 	return (0);
349a90cf9f2SGordon Ross }
350a90cf9f2SGordon Ross 
351faa1795aSjb smb_sdrc_t
smb_pre_negotiate(smb_request_t * sr)352faa1795aSjb smb_pre_negotiate(smb_request_t *sr)
353faa1795aSjb {
354a90cf9f2SGordon Ross 	smb_kmod_cfg_t		*skc;
355148c5f43SAlan Wright 	smb_arg_negotiate_t	*negprot;
356148c5f43SAlan Wright 	int			dialect;
357148c5f43SAlan Wright 	int			pos;
358148c5f43SAlan Wright 	int			rc = 0;
359148c5f43SAlan Wright 
360a90cf9f2SGordon Ross 	skc = &sr->session->s_cfg;
361148c5f43SAlan Wright 	negprot = smb_srm_zalloc(sr, sizeof (smb_arg_negotiate_t));
362148c5f43SAlan Wright 	negprot->ni_index = -1;
363148c5f43SAlan Wright 	sr->sr_negprot = negprot;
364148c5f43SAlan Wright 
365148c5f43SAlan Wright 	for (pos = 0; smbsr_decode_data_avail(sr); pos++) {
366148c5f43SAlan Wright 		if (smbsr_decode_data(sr, "%L", sr, &negprot->ni_name) != 0) {
367148c5f43SAlan Wright 			smbsr_error(sr, 0, ERRSRV, ERRerror);
368148c5f43SAlan Wright 			rc = -1;
369148c5f43SAlan Wright 			break;
370148c5f43SAlan Wright 		}
371148c5f43SAlan Wright 
372148c5f43SAlan Wright 		if ((dialect = smb_xlate_dialect(negprot->ni_name)) < 0)
373148c5f43SAlan Wright 			continue;
374148c5f43SAlan Wright 
375a90cf9f2SGordon Ross 		/*
376a90cf9f2SGordon Ross 		 * Conditionally recognize the SMB2 dialects.
377a90cf9f2SGordon Ross 		 */
378a90cf9f2SGordon Ross 		if (dialect >= DIALECT_SMB2002 &&
379a90cf9f2SGordon Ross 		    skc->skc_max_protocol < SMB_VERS_2_BASE)
380a90cf9f2SGordon Ross 			continue;
381a90cf9f2SGordon Ross 
382*3e2c0c09SMatt Barden 		/*
383*3e2c0c09SMatt Barden 		 * We may not support SMB1; skip those dialects if true.
384*3e2c0c09SMatt Barden 		 */
385*3e2c0c09SMatt Barden 		if (dialect < DIALECT_SMB2002 &&
386*3e2c0c09SMatt Barden 		    skc->skc_min_protocol > SMB_VERS_1)
387*3e2c0c09SMatt Barden 			continue;
388*3e2c0c09SMatt Barden 
389*3e2c0c09SMatt Barden 		if (dialect == DIALECT_SMB2002 &&
390*3e2c0c09SMatt Barden 		    skc->skc_min_protocol > SMB_VERS_2_002)
391*3e2c0c09SMatt Barden 			continue;
392*3e2c0c09SMatt Barden 
393148c5f43SAlan Wright 		if (negprot->ni_dialect < dialect) {
394148c5f43SAlan Wright 			negprot->ni_dialect = dialect;
395148c5f43SAlan Wright 			negprot->ni_index = pos;
396148c5f43SAlan Wright 		}
397148c5f43SAlan Wright 	}
398148c5f43SAlan Wright 
39993bc28dbSGordon Ross 	DTRACE_SMB_START(op__Negotiate, smb_request_t *, sr);
400a90cf9f2SGordon Ross 
401148c5f43SAlan Wright 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
402faa1795aSjb }
403faa1795aSjb 
404faa1795aSjb void
smb_post_negotiate(smb_request_t * sr)405faa1795aSjb smb_post_negotiate(smb_request_t *sr)
406faa1795aSjb {
407148c5f43SAlan Wright 	smb_arg_negotiate_t	*negprot = sr->sr_negprot;
408148c5f43SAlan Wright 
40993bc28dbSGordon Ross 	DTRACE_SMB_DONE(op__Negotiate, smb_request_t *, sr);
410148c5f43SAlan Wright 
411148c5f43SAlan Wright 	bzero(negprot, sizeof (smb_arg_negotiate_t));
412faa1795aSjb }
413da6c28aaSamw 
4147b59d02dSjb smb_sdrc_t
smb_com_negotiate(smb_request_t * sr)415faa1795aSjb smb_com_negotiate(smb_request_t *sr)
416da6c28aaSamw {
4171160dcf7SMatt Barden 	smb_session_t		*session = sr->session;
418148c5f43SAlan Wright 	smb_arg_negotiate_t	*negprot = sr->sr_negprot;
419148c5f43SAlan Wright 	uint16_t		secmode;
420da6c28aaSamw 	uint32_t		sesskey;
421148c5f43SAlan Wright 	char			*nbdomain;
422148c5f43SAlan Wright 	uint8_t			*wcbuf;
423148c5f43SAlan Wright 	int			wclen;
424b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_msgbuf_t		mb;
425148c5f43SAlan Wright 	int			rc;
426da6c28aaSamw 
427a90cf9f2SGordon Ross 	if (session->s_state != SMB_SESSION_STATE_ESTABLISHED) {
428da6c28aaSamw 		/* The protocol has already been negotiated. */
429dc20a302Sas 		smbsr_error(sr, 0, ERRSRV, ERRerror);
430faa1795aSjb 		return (SDRC_ERROR);
431da6c28aaSamw 	}
432da6c28aaSamw 
433*3e2c0c09SMatt Barden 	if (negprot->ni_index < 0) {
434*3e2c0c09SMatt Barden 		cmn_err(CE_NOTE, "clnt %s no supported dialect",
435*3e2c0c09SMatt Barden 		    sr->session->ip_addr_str);
436*3e2c0c09SMatt Barden 		smbsr_error(sr, 0, ERRSRV, ERRerror);
437*3e2c0c09SMatt Barden 		return (SDRC_DROP_VC);
438*3e2c0c09SMatt Barden 	}
439*3e2c0c09SMatt Barden 
440a90cf9f2SGordon Ross 	/*
441a90cf9f2SGordon Ross 	 * Special case for negotiating SMB2 from SMB1.  The client
442a90cf9f2SGordon Ross 	 * includes the  "SMB 2..." dialects in the SMB1 negotiate,
443a90cf9f2SGordon Ross 	 * and if SMB2 is enabled, we choose one of those and then
444a90cf9f2SGordon Ross 	 * send an SMB2 reply to that SMB1 request.  Yes, it's very
445a90cf9f2SGordon Ross 	 * strange, but this SMB1 request can have an SMB2 reply!
446a90cf9f2SGordon Ross 	 * To accomplish this, we let the SMB2 code send the reply
447a90cf9f2SGordon Ross 	 * and return the special code SDRC_NO_REPLY to the SMB1
448a90cf9f2SGordon Ross 	 * dispatch logic so it will NOT send an SMB1 reply.
449a90cf9f2SGordon Ross 	 * (Or possibly send an SMB1 error reply.)
450a90cf9f2SGordon Ross 	 */
451a90cf9f2SGordon Ross 	if (negprot->ni_dialect >= DIALECT_SMB2002) {
452a90cf9f2SGordon Ross 		rc = smb1_negotiate_smb2(sr);
453a90cf9f2SGordon Ross 		ASSERT(rc == SDRC_NO_REPLY ||
454a90cf9f2SGordon Ross 		    rc == SDRC_DROP_VC || rc == SDRC_ERROR);
455a90cf9f2SGordon Ross 		return (rc);
456a90cf9f2SGordon Ross 	}
457a90cf9f2SGordon Ross 
4581160dcf7SMatt Barden 	session->srv_secmode = NEGOTIATE_ENCRYPT_PASSWORDS |
45912b65585SGordon Ross 	    NEGOTIATE_USER_SECURITY;
4601160dcf7SMatt Barden 	secmode = session->srv_secmode;
461a90cf9f2SGordon Ross 	sesskey = session->sesskey;
462da6c28aaSamw 
463a90cf9f2SGordon Ross 	negprot->ni_servertime.tv_sec = gethrestime_sec();
464a90cf9f2SGordon Ross 	negprot->ni_servertime.tv_nsec = 0;
465148c5f43SAlan Wright 	negprot->ni_tzcorrection = sr->sr_gmtoff / 60;
466a90cf9f2SGordon Ross 	negprot->ni_maxmpxcount = smb_maxmpxcount;
467f9bc6dadSDmitry.Savitsky@nexenta.com 	negprot->ni_keylen = SMB_CHALLENGE_SZ;
468a90cf9f2SGordon Ross 	bcopy(&session->challenge_key, negprot->ni_key, SMB_CHALLENGE_SZ);
469148c5f43SAlan Wright 	nbdomain = sr->sr_cfg->skc_nbdomain;
470da6c28aaSamw 
47112b65585SGordon Ross 	negprot->ni_capabilities = smb1srv_capabilities;
472148c5f43SAlan Wright 
473148c5f43SAlan Wright 	switch (negprot->ni_dialect) {
474da6c28aaSamw 	case PC_NETWORK_PROGRAM_1_0:	/* core */
475a90cf9f2SGordon Ross 		(void) ksocket_setsockopt(session->sock, SOL_SOCKET,
4760f1702c5SYu Xiangning 		    SO_RCVBUF, (const void *)&smb_dos_tcp_rcvbuf,
4770f1702c5SYu Xiangning 		    sizeof (smb_dos_tcp_rcvbuf), CRED());
478148c5f43SAlan Wright 		rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
479148c5f43SAlan Wright 		    negprot->ni_index, 0);
480da6c28aaSamw 		break;
481da6c28aaSamw 
482da6c28aaSamw 	case Windows_for_Workgroups_3_1a:
483da6c28aaSamw 	case PCLAN1_0:
484da6c28aaSamw 	case MICROSOFT_NETWORKS_1_03:
485da6c28aaSamw 	case MICROSOFT_NETWORKS_3_0:
486da6c28aaSamw 	case LANMAN1_0:
487da6c28aaSamw 	case LM1_2X002:
488da6c28aaSamw 	case DOS_LM1_2X002:
489a90cf9f2SGordon Ross 		(void) ksocket_setsockopt(session->sock, SOL_SOCKET,
4900f1702c5SYu Xiangning 		    SO_RCVBUF, (const void *)&smb_dos_tcp_rcvbuf,
4910f1702c5SYu Xiangning 		    sizeof (smb_dos_tcp_rcvbuf), CRED());
492da6c28aaSamw 		sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK;
4937b59d02dSjb 		rc = smbsr_encode_result(sr, 13, VAR_BCC,
4943db3f65cSamw 		    "bwwwwwwlYww2.w#c",
495148c5f43SAlan Wright 		    13,				/* wct */
496148c5f43SAlan Wright 		    negprot->ni_index,		/* dialect index */
497148c5f43SAlan Wright 		    secmode,			/* security mode */
498148c5f43SAlan Wright 		    SMB_DOS_MAXBUF,		/* max buffer size */
499148c5f43SAlan Wright 		    1,				/* max MPX */
500148c5f43SAlan Wright 		    1,				/* max VCs */
501a90cf9f2SGordon Ross 		    0,				/* read/write raw */
502148c5f43SAlan Wright 		    sesskey,			/* session key */
503148c5f43SAlan Wright 		    negprot->ni_servertime.tv_sec, /* server date/time */
504148c5f43SAlan Wright 		    negprot->ni_tzcorrection,
505148c5f43SAlan Wright 		    (uint16_t)negprot->ni_keylen, /* encryption key length */
506148c5f43SAlan Wright 						/* reserved field handled 2. */
507da6c28aaSamw 		    VAR_BCC,
508148c5f43SAlan Wright 		    (int)negprot->ni_keylen,
509148c5f43SAlan Wright 		    negprot->ni_key);		/* encryption key */
510da6c28aaSamw 		break;
511da6c28aaSamw 
512da6c28aaSamw 	case DOS_LANMAN2_1:
513da6c28aaSamw 	case LANMAN2_1:
514a90cf9f2SGordon Ross 		(void) ksocket_setsockopt(session->sock, SOL_SOCKET,
5150f1702c5SYu Xiangning 		    SO_RCVBUF, (const void *)&smb_dos_tcp_rcvbuf,
5160f1702c5SYu Xiangning 		    sizeof (smb_dos_tcp_rcvbuf), CRED());
517da6c28aaSamw 		sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK;
5187b59d02dSjb 		rc = smbsr_encode_result(sr, 13, VAR_BCC,
5193db3f65cSamw 		    "bwwwwwwlYww2.w#cs",
520148c5f43SAlan Wright 		    13,				/* wct */
521148c5f43SAlan Wright 		    negprot->ni_index,		/* dialect index */
522148c5f43SAlan Wright 		    secmode,			/* security mode */
523148c5f43SAlan Wright 		    SMB_DOS_MAXBUF,		/* max buffer size */
524148c5f43SAlan Wright 		    1,				/* max MPX */
525148c5f43SAlan Wright 		    1,				/* max VCs */
526a90cf9f2SGordon Ross 		    0,				/* read/write raw */
527148c5f43SAlan Wright 		    sesskey,			/* session key */
528148c5f43SAlan Wright 		    negprot->ni_servertime.tv_sec, /* server date/time */
529148c5f43SAlan Wright 		    negprot->ni_tzcorrection,
530148c5f43SAlan Wright 		    (uint16_t)negprot->ni_keylen, /* encryption key length */
531148c5f43SAlan Wright 						/* reserved field handled 2. */
532da6c28aaSamw 		    VAR_BCC,
533148c5f43SAlan Wright 		    (int)negprot->ni_keylen,
534148c5f43SAlan Wright 		    negprot->ni_key,		/* encryption key */
535148c5f43SAlan Wright 		    nbdomain);
536da6c28aaSamw 		break;
537da6c28aaSamw 
538da6c28aaSamw 	case NT_LM_0_12:
539a90cf9f2SGordon Ross 		(void) ksocket_setsockopt(session->sock, SOL_SOCKET,
5400f1702c5SYu Xiangning 		    SO_RCVBUF, (const void *)&smb_nt_tcp_rcvbuf,
5410f1702c5SYu Xiangning 		    sizeof (smb_nt_tcp_rcvbuf), CRED());
542da6c28aaSamw 
543da6c28aaSamw 		/*
54412b65585SGordon Ross 		 * Allow SMB signatures if using encrypted passwords
545da6c28aaSamw 		 */
54612b65585SGordon Ross 		if ((secmode & NEGOTIATE_ENCRYPT_PASSWORDS) &&
547faa1795aSjb 		    sr->sr_cfg->skc_signing_enable) {
548da6c28aaSamw 			secmode |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
549faa1795aSjb 			if (sr->sr_cfg->skc_signing_required)
550da6c28aaSamw 				secmode |=
551da6c28aaSamw 				    NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
552da6c28aaSamw 
5531160dcf7SMatt Barden 			session->srv_secmode = secmode;
554da6c28aaSamw 		}
555da6c28aaSamw 
55612b65585SGordon Ross 		/*
55712b65585SGordon Ross 		 * Does the client want Extended Security?
55812b65585SGordon Ross 		 * (and if we have it enabled)
55912b65585SGordon Ross 		 * If so, handle as if a different dialect.
56012b65585SGordon Ross 		 */
56112b65585SGordon Ross 		if ((sr->smb_flg2 & SMB_FLAGS2_EXT_SEC) != 0 &&
56212b65585SGordon Ross 		    (negprot->ni_capabilities & CAP_EXTENDED_SECURITY) != 0)
56312b65585SGordon Ross 			goto NT_LM_0_12_ext_sec;
56412b65585SGordon Ross 
56512b65585SGordon Ross 		/* Else deny knowledge of extended security. */
56612b65585SGordon Ross 		sr->smb_flg2 &= ~SMB_FLAGS2_EXT_SEC;
56712b65585SGordon Ross 		negprot->ni_capabilities &= ~CAP_EXTENDED_SECURITY;
56812b65585SGordon Ross 
569b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/*
570148c5f43SAlan Wright 		 * nbdomain is not expected to be aligned.
571b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * Use temporary buffer to avoid alignment padding
572b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 */
573148c5f43SAlan Wright 		wclen = smb_wcequiv_strlen(nbdomain) + sizeof (smb_wchar_t);
574148c5f43SAlan Wright 		wcbuf = smb_srm_zalloc(sr, wclen);
575148c5f43SAlan Wright 		smb_msgbuf_init(&mb, wcbuf, wclen, SMB_MSGBUF_UNICODE);
576148c5f43SAlan Wright 		if (smb_msgbuf_encode(&mb, "U", nbdomain) < 0) {
577b89a8333Snatalie li - Sun Microsystems - Irvine United States 			smb_msgbuf_term(&mb);
578b89a8333Snatalie li - Sun Microsystems - Irvine United States 			smbsr_error(sr, 0, ERRSRV, ERRerror);
579b89a8333Snatalie li - Sun Microsystems - Irvine United States 			return (SDRC_ERROR);
580b89a8333Snatalie li - Sun Microsystems - Irvine United States 		}
581b89a8333Snatalie li - Sun Microsystems - Irvine United States 
5827b59d02dSjb 		rc = smbsr_encode_result(sr, 17, VAR_BCC,
583b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    "bwbwwllllTwbw#c#c",
584148c5f43SAlan Wright 		    17,				/* wct */
585148c5f43SAlan Wright 		    negprot->ni_index,		/* dialect index */
586148c5f43SAlan Wright 		    secmode,			/* security mode */
587148c5f43SAlan Wright 		    negprot->ni_maxmpxcount,	/* max MPX */
588148c5f43SAlan Wright 		    1,				/* max VCs */
589da6c28aaSamw 		    (DWORD)smb_maxbufsize,	/* max buffer size */
590148c5f43SAlan Wright 		    0xFFFF,			/* max raw size */
591148c5f43SAlan Wright 		    sesskey,			/* session key */
592148c5f43SAlan Wright 		    negprot->ni_capabilities,
593148c5f43SAlan Wright 		    &negprot->ni_servertime,	/* system time */
594148c5f43SAlan Wright 		    negprot->ni_tzcorrection,
595148c5f43SAlan Wright 		    negprot->ni_keylen,		/* encryption key length */
596da6c28aaSamw 		    VAR_BCC,
597148c5f43SAlan Wright 		    (int)negprot->ni_keylen,
598148c5f43SAlan Wright 		    negprot->ni_key,		/* encryption key */
599148c5f43SAlan Wright 		    wclen,
600148c5f43SAlan Wright 		    wcbuf);			/* nbdomain (unicode) */
601b89a8333Snatalie li - Sun Microsystems - Irvine United States 
602b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_msgbuf_term(&mb);
603da6c28aaSamw 		break;
604da6c28aaSamw 
60512b65585SGordon Ross NT_LM_0_12_ext_sec:
60612b65585SGordon Ross 		/*
60712b65585SGordon Ross 		 * This is the "Extended Security" variant of
60812b65585SGordon Ross 		 * dialect NT_LM_0_12.
60912b65585SGordon Ross 		 */
61012b65585SGordon Ross 		rc = smbsr_encode_result(sr, 17, VAR_BCC,
61112b65585SGordon Ross 		    "bwbwwllllTwbw#c#c",
61212b65585SGordon Ross 		    17,				/* wct */
61312b65585SGordon Ross 		    negprot->ni_index,		/* dialect index */
61412b65585SGordon Ross 		    secmode,			/* security mode */
61512b65585SGordon Ross 		    negprot->ni_maxmpxcount,	/* max MPX */
61612b65585SGordon Ross 		    1,				/* max VCs */
61712b65585SGordon Ross 		    (DWORD)smb_maxbufsize,	/* max buffer size */
61812b65585SGordon Ross 		    0xFFFF,			/* max raw size */
61912b65585SGordon Ross 		    sesskey,			/* session key */
62012b65585SGordon Ross 		    negprot->ni_capabilities,
62112b65585SGordon Ross 		    &negprot->ni_servertime,	/* system time */
62212b65585SGordon Ross 		    negprot->ni_tzcorrection,
62312b65585SGordon Ross 		    0,		/* encryption key length (MBZ) */
62412b65585SGordon Ross 		    VAR_BCC,
62512b65585SGordon Ross 		    UUID_LEN,
62612b65585SGordon Ross 		    sr->sr_cfg->skc_machine_uuid,
62712b65585SGordon Ross 		    sr->sr_cfg->skc_negtok_len,
62812b65585SGordon Ross 		    sr->sr_cfg->skc_negtok);
62912b65585SGordon Ross 		break;
63012b65585SGordon Ross 
63112b65585SGordon Ross 
632da6c28aaSamw 	default:
633148c5f43SAlan Wright 		rc = smbsr_encode_result(sr, 1, 0, "bww", 1, -1, 0);
634a90cf9f2SGordon Ross 		break;
635da6c28aaSamw 	}
636da6c28aaSamw 
6377b59d02dSjb 	if (rc != 0)
638faa1795aSjb 		return (SDRC_ERROR);
6397b59d02dSjb 
640da6c28aaSamw 	/*
641a90cf9f2SGordon Ross 	 * Save the agreed dialect. Note that the state is also
642da6c28aaSamw 	 * used to detect and reject attempts to re-negotiate.
643da6c28aaSamw 	 */
644a90cf9f2SGordon Ross 	session->dialect = negprot->ni_dialect;
645a90cf9f2SGordon Ross 	session->s_state = SMB_SESSION_STATE_NEGOTIATED;
646a90cf9f2SGordon Ross 
647a90cf9f2SGordon Ross 	/* Allow normal SMB1 requests now. */
648a90cf9f2SGordon Ross 	session->newrq_func = smb1sr_newrq;
649a90cf9f2SGordon Ross 
650faa1795aSjb 	return (SDRC_SUCCESS);
651da6c28aaSamw }
652da6c28aaSamw 
653148c5f43SAlan Wright static int
smb_xlate_dialect(const char * dialect)654148c5f43SAlan Wright smb_xlate_dialect(const char *dialect)
655148c5f43SAlan Wright {
6568622ec45SGordon Ross 	const smb_xlate_t *dp;
657148c5f43SAlan Wright 	int		i;
658148c5f43SAlan Wright 
659a90cf9f2SGordon Ross 	for (i = 0; i < smb_ndialects; ++i) {
660148c5f43SAlan Wright 		dp = &smb_dialect[i];
661148c5f43SAlan Wright 
662148c5f43SAlan Wright 		if (strcmp(dp->str, dialect) == 0)
663148c5f43SAlan Wright 			return (dp->code);
664148c5f43SAlan Wright 	}
665da6c28aaSamw 
666148c5f43SAlan Wright 	return (-1);
667da6c28aaSamw }
668