xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c (revision 33c72b7598992897b94815b1f47b7b8077e53808)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 /*
28  * SMB: locking_andx
29  *
30  * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
31  *
32  *  Client Request                     Description
33  *  ================================== =================================
34  *
35  *  UCHAR WordCount;                   Count of parameter words = 8
36  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF = none
37  *  UCHAR AndXReserved;                Reserved (must be 0)
38  *  USHORT AndXOffset;                 Offset to next command WordCount
39  *  USHORT Fid;                        File handle
40  *  UCHAR LockType;                    See LockType table below
41  *  UCHAR OplockLevel;                 The new oplock level
42  *  ULONG Timeout;                     Milliseconds to wait for unlock
43  *  USHORT NumberOfUnlocks;            Num. unlock range structs following
44  *  USHORT NumberOfLocks;              Num. lock range structs following
45  *  USHORT ByteCount;                  Count of data bytes
46  *  LOCKING_ANDX_RANGE Unlocks[];      Unlock ranges
47  *  LOCKING_ANDX_RANGE Locks[];        Lock ranges
48  *
49  *  LockType Flag Name            Value Description
50  *  ============================  ===== ================================
51  *
52  *  LOCKING_ANDX_SHARED_LOCK      0x01  Read-only lock
53  *  LOCKING_ANDX_OPLOCK_RELEASE   0x02  Oplock break notification
54  *  LOCKING_ANDX_CHANGE_LOCKTYPE  0x04  Change lock type
55  *  LOCKING_ANDX_CANCEL_LOCK      0x08  Cancel outstanding request
56  *  LOCKING_ANDX_LARGE_FILES      0x10  Large file locking format
57  *
58  *  LOCKING_ANDX_RANGE Format
59  *  =====================================================================
60  *
61  *  USHORT Pid;                        PID of process "owning" lock
62  *  ULONG Offset;                      Offset to bytes to [un]lock
63  *  ULONG Length;                      Number of bytes to [un]lock
64  *
65  *  Large File LOCKING_ANDX_RANGE Format
66  *  =====================================================================
67  *
68  *  USHORT Pid;                        PID of process "owning" lock
69  *  USHORT Pad;                        Pad to DWORD align (mbz)
70  *  ULONG OffsetHigh;                  Offset to bytes to [un]lock
71  *                                      (high)
72  *  ULONG OffsetLow;                   Offset to bytes to [un]lock (low)
73  *  ULONG LengthHigh;                  Number of bytes to [un]lock
74  *                                      (high)
75  *  ULONG LengthLow;                   Number of bytes to [un]lock (low)
76  *
77  *  Server Response                    Description
78  *  ================================== =================================
79  *
80  *  UCHAR WordCount;                   Count of parameter words = 2
81  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF =
82  *                                      none
83  *  UCHAR AndXReserved;                Reserved (must be 0)
84  *  USHORT AndXOffset;                 Offset to next command WordCount
85  *  USHORT ByteCount;                  Count of data bytes = 0
86  *
87  * Locking is a simple mechanism for excluding other processes read/write
88  * access to regions of a file.  The locked regions can be anywhere in the
89  * logical file.  Locking beyond end-of-file is permitted.  Any process
90  * using the Fid specified in this request's Fid has access to the locked
91  * bytes, other processes will be denied the locking of the same bytes.
92  *
93  * The proper method for using locks is not to rely on being denied read or
94  * write access on any of the read/write protocols but rather to attempt
95  * the locking protocol and proceed with the read/write only if the locks
96  * succeeded.
97  *
98  * Locking a range of bytes will fail if any subranges or overlapping
99  * ranges are locked.  In other words, if any of the specified bytes are
100  * already locked, the lock will fail.
101  *
102  * If NumberOfUnlocks is non-zero, the Unlocks vector contains
103  * NumberOfUnlocks elements.  Each element requests that a lock at Offset
104  * of Length be released.  If NumberOfLocks is nonzero, the Locks vector
105  * contains NumberOfLocks elements.  Each element requests the acquisition
106  * of a lock at Offset of Length.
107  *
108  * Timeout is the maximum amount of time to wait for the byte range(s)
109  * specified to become unlocked.  A timeout value of 0 indicates that the
110  * server should fail immediately if any lock range specified is locked.  A
111  *
112  * timeout value of -1 indicates that the server should wait as long as it
113  * takes for each byte range specified to become unlocked so that it may be
114  * again locked by this protocol.  Any other value of smb_timeout specifies
115  * the maximum number of milliseconds to wait for all lock range(s)
116  * specified to become available.
117  *
118  * If any of the lock ranges timeout because of the area to be locked is
119  * already locked (or the lock fails), the other ranges in the protocol
120  * request which were successfully locked as a result of this protocol will
121  * be unlocked (either all requested ranges will be locked when this
122  * protocol returns to the client or none).
123  *
124  * If LockType has the LOCKING_ANDX_SHARED_LOCK flag set, the lock is
125  * specified as a shared lock.  Locks for both read and write (where
126  * LOCKING_ANDX_SHARED_LOCK is clear) should be prohibited, but other
127  * shared locks should be permitted.  If shared locks can not be supported
128  * by a server, the server should map the lock to a lock for both read and
129  * write.  Closing a file with locks still in force causes the locks to be
130  * released in no defined order.
131  *
132  * If LockType has the LOCKING_ANDX_LARGE_FILES flag set and if the
133  * negotiated protocol is NT LM 0.12 or later, then the Locks and Unlocks
134  * vectors are in the Large File LOCKING_ANDX_RANGE format.  This allows
135  * specification of 64 bit offsets for very large files.
136  *
137  * If the one and only member of the Locks vector has the
138  * LOCKING_ANDX_CANCEL_LOCK flag set in the LockType field, the client is
139  * requesting the server to cancel a previously requested, but not yet
140  * responded to, lock.
141  *
142  * If LockType has the LOCKING_ANDX_CHANGE_LOCKTYPE flag set, the client is
143  * requesting that the server atomically change the lock type from a shared
144  * lock to an exclusive lock or vice versa.  If the server can not do this
145  * in an atomic fashion, the server must reject this request.  NT and W95
146  * servers do not support this capability.
147  *
148  * Oplocks are described in the "Opportunistic Locks" section elsewhere in
149  * this document.  A client requests an oplock by setting the appropriate
150  * bit in the SMB_COM_OPEN_ANDX request when the file is being opened in a
151  * mode which is not exclusive.  The server responds by setting the
152  * appropriate bit in the response SMB indicating whether or not the oplock
153  * was granted.  By granting the oplock, the server tells the client the
154  * file is currently only being used by this one client process at the
155  * current time.  The client can therefore safely do read ahead and write
156  * behind as well as local caching of file locks knowing that the file will
157  * not be accessed/changed in any way by another process while the oplock
158  * is in effect.  The client will be notified when any other process
159  * attempts to open or modify the oplocked file.
160  *
161  * When another user attempts to open or otherwise modify the file which a
162  * client has oplocked, the server delays the second attempt and notifies
163  * the client via an SMB_LOCKING_ANDX SMB asynchronously sent from the
164  * server to the client.  This message has the LOCKING_ANDX_OPLOCK_RELEASE
165  * flag set indicating to the client that the oplock is being broken.
166  *
167  * OplockLevel indicates the type of oplock the client now owns. If
168  * OplockLevel is 0, the client possesses no oplocks on the file at all, if
169  * OplockLevel is 1 the client possesses a Level II oplock.  The client is
170  * expected to flush any dirty buffers to the server, submit any file locks
171  * and respond to the server with either an SMB_LOCKING_ANDX SMB having the
172  * LOCKING_ANDX_OPLOCK_RELEASE flag set, or with a file close if the file
173  * is no longer in use by the client.  If the client sends an
174  * SMB_LOCKING_ANDX SMB with the LOCKING_ANDX_OPLOCK_RELEASE flag set and
175  * NumberOfLocks is zero, the server does not send a response.  Since a
176  * close being sent to the server and break oplock notification from the
177  * server could cross on the wire, if the client gets an oplock
178  * notification on a file which it does not have open, that notification
179  * should be ignored.
180  *
181  * Due to timing, the client could get an "oplock broken" notification in a
182  * user's data buffer as a result of this notification crossing on the wire
183  * with a SMB_COM_READ_RAW request.  The client must detect this (use
184  * length of msg, "FFSMB", MID of -1 and Command of SMB_COM_LOCKING_ANDX)
185  * and honor the "oplock broken" notification as usual.  The server must
186  * also note on receipt of an SMB_COM_READ_RAW request that there is an
187  * outstanding (unanswered) "oplock broken" notification to the client and
188  * return a zero length response denoting failure of the read raw request.
189  * The client should (after responding to the "oplock broken"
190  * notification), use a standard read protocol to redo the read request.
191  * This allows a file to actually contain data matching an "oplock broken"
192  * notification and still be read correctly.
193  *
194  * The entire message sent and received including the optional second
195  * protocol must fit in the negotiated maximum transfer size.  The
196  * following are the only valid SMB commands for AndXCommand for
197  * SMB_COM_LOCKING_ANDX:
198  *
199  *     SMB_COM_READ       SMB_COM_READ_ANDX
200  *     SMB_COM_WRITE      SMB_COM_WRITE_ANDX
201  *     SMB_COM_FLUSH
202  *
203  * 4.2.6.1   Errors
204  *
205  * ERRDOS/ERRbadfile
206  * ERRDOS/ERRbadfid
207  * ERRDOS/ERRlock
208  * ERRDOS/ERRinvdevice
209  * ERRSRV/ERRinvid
210  * ERRSRV/ERRbaduid
211  */
212 
213 #include <smbsrv/smb_kproto.h>
214 
215 /*
216  * This is a somewhat arbitrary sanity limit on the length of the
217  * SMB2_LOCK_ELEMENT array.  It usually has length one or two.
218  */
219 int smb_lock_max_elem = 1024;
220 
221 smb_sdrc_t
222 smb_pre_locking_andx(smb_request_t *sr)
223 {
224 	DTRACE_SMB_START(op__LockingX, smb_request_t *, sr);
225 	return (SDRC_SUCCESS);
226 }
227 
228 void
229 smb_post_locking_andx(smb_request_t *sr)
230 {
231 	DTRACE_SMB_DONE(op__LockingX, smb_request_t *, sr);
232 }
233 
234 struct lreq {
235 	uint64_t off;
236 	uint64_t len;
237 	uint32_t pid;
238 	uint32_t reserved;
239 };
240 
241 smb_sdrc_t
242 smb_com_locking_andx(smb_request_t *sr)
243 {
244 	unsigned short	i;
245 	unsigned char	lock_type;	/* See lock_type table above */
246 	unsigned char	oplock_level;	/* The new oplock level */
247 	uint32_t	timeout;	/* Milliseconds to wait for lock */
248 	unsigned short	unlock_num;	/* # unlock range structs */
249 	unsigned short	lock_num;	/* # lock range structs */
250 	DWORD		result;
251 	int		rc;
252 	uint32_t	ltype;
253 	uint32_t	status;
254 	smb_ofile_t	*ofile;
255 	uint16_t	tmp_pid;	/* locking uses 16-bit pids */
256 	uint32_t	lrv_tot;
257 	struct lreq	*lrv_ul;
258 	struct lreq	*lrv_lk;
259 	struct lreq	*lr;
260 
261 	rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type,
262 	    &oplock_level, &timeout, &unlock_num, &lock_num);
263 	if (rc != 0)
264 		return (SDRC_ERROR);
265 
266 	smbsr_lookup_file(sr);
267 	if (sr->fid_ofile == NULL) {
268 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
269 		return (SDRC_ERROR);
270 	}
271 	ofile = sr->fid_ofile;
272 	if (ofile->f_node == NULL) {
273 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
274 		    ERRDOS, ERROR_INVALID_PARAMETER);
275 		return (SDRC_ERROR);
276 	}
277 
278 	if (unlock_num > smb_lock_max_elem ||
279 	    lock_num > smb_lock_max_elem) {
280 		smbsr_error(sr, NT_STATUS_INSUFFICIENT_RESOURCES,
281 		    ERRDOS, ERROR_NO_SYSTEM_RESOURCES);
282 		return (SDRC_ERROR);
283 	}
284 
285 	if (lock_type & LOCKING_ANDX_SHARED_LOCK)
286 		ltype = SMB_LOCK_TYPE_READONLY;
287 	else
288 		ltype = SMB_LOCK_TYPE_READWRITE;
289 
290 	if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
291 		uint32_t NewLevel;
292 		if (oplock_level == 0)
293 			NewLevel = OPLOCK_LEVEL_NONE;
294 		else
295 			NewLevel = OPLOCK_LEVEL_TWO;
296 		status = smb_oplock_ack_break(sr, ofile, &NewLevel);
297 		if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
298 			(void) smb_oplock_wait_break(ofile->f_node, 0);
299 			status = 0;
300 		}
301 		if (unlock_num == 0 && lock_num == 0)
302 			return (SDRC_NO_REPLY);
303 	}
304 
305 	/*
306 	 * No support for changing locktype (although we could probably
307 	 * implement this)
308 	 */
309 	if (lock_type & LOCKING_ANDX_CHANGE_LOCK_TYPE) {
310 		smbsr_error(sr, 0, ERRDOS,
311 		    ERROR_ATOMIC_LOCKS_NOT_SUPPORTED);
312 		return (SDRC_ERROR);
313 	}
314 
315 	if (lock_type & LOCKING_ANDX_LARGE_FILES) {
316 		/*
317 		 * negotiated protocol should be NT LM 0.12 or later
318 		 */
319 		if (sr->session->dialect < NT_LM_0_12) {
320 			smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
321 			    ERRDOS, ERROR_INVALID_PARAMETER);
322 			return (SDRC_ERROR);
323 		}
324 	}
325 
326 	/*
327 	 * Parse the unlock, lock vectors.  Will parse all the
328 	 * unlock + lock records into one array, and then use
329 	 * pointers to the unlock and lock parts.
330 	 */
331 	lrv_tot = unlock_num + lock_num;
332 	lrv_ul = smb_srm_zalloc(sr, lrv_tot * sizeof (*lrv_ul));
333 	lrv_lk = &lrv_ul[unlock_num];
334 
335 	for (i = 0; i < lrv_tot; i++) {
336 		lr = &lrv_ul[i];
337 		if (lock_type & LOCKING_ANDX_LARGE_FILES) {
338 			rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
339 			    &tmp_pid, &lr->off, &lr->len);
340 		} else {
341 			uint32_t	offset32, length32;
342 			rc = smb_mbc_decodef(&sr->smb_data, "wll",
343 			    &tmp_pid, &offset32, &length32);
344 			lr->off = offset32;
345 			lr->len = length32;
346 		}
347 		lr->pid = tmp_pid;	/* 16-bit PID */
348 		if (rc) {
349 			/*
350 			 * This is the error returned by Windows 2000
351 			 * even when STATUS32 has been negotiated.
352 			 */
353 			smbsr_error(sr, 0, ERRSRV, ERRerror);
354 			return (SDRC_ERROR);
355 		}
356 	}
357 
358 	/*
359 	 * Cancel waiting locks.  MS-CIFS says one place that
360 	 * this cancels all waiting locks for this FID+PID,
361 	 * but smbtorture insists this cancels just one.
362 	 * Tests with Windows 7 confirms that.
363 	 */
364 	if ((lock_type & LOCKING_ANDX_CANCEL_LOCK) != 0) {
365 		lr = lrv_lk;
366 
367 		result = smb_lock_range_cancel(sr, lr->off, lr->len, lr->pid);
368 
369 		if (result != NT_STATUS_SUCCESS) {
370 			smbsr_error(sr, 0, ERRDOS,
371 			    ERROR_CANCEL_VIOLATION);
372 			return (SDRC_ERROR);
373 		}
374 		goto out;
375 	}
376 
377 	/*
378 	 * Normal unlock and lock list
379 	 */
380 	for (i = 0; i < unlock_num; i++) {
381 		lr = &lrv_ul[i];
382 
383 		result = smb_unlock_range(sr, lr->off, lr->len, lr->pid);
384 		if (result != NT_STATUS_SUCCESS) {
385 			smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
386 			    ERRDOS, ERROR_NOT_LOCKED);
387 			return (SDRC_ERROR);
388 		}
389 	}
390 	for (i = 0; i < lock_num; i++) {
391 		lr = &lrv_lk[i];
392 
393 		result = smb_lock_range(sr, lr->off, lr->len, lr->pid,
394 		    ltype, timeout);
395 		if (result != NT_STATUS_SUCCESS) {
396 			/*
397 			 * Oh... we have to rollback.
398 			 */
399 			while (i > 0) {
400 				--i;
401 				lr = &lrv_lk[i];
402 				(void) smb_unlock_range(sr,
403 				    lr->off, lr->len, lr->pid);
404 			}
405 			smb_lock_range_error(sr, result);
406 			return (SDRC_ERROR);
407 		}
408 	}
409 
410 out:
411 	if (smbsr_encode_result(sr, 2, 0, "bb.ww",
412 	    2, sr->andx_com, 0x27, 0) != 0)
413 		return (SDRC_ERROR);
414 	return (SDRC_SUCCESS);
415 }
416 
417 /*
418  * Compose an SMB1 Oplock Break Notification packet, including
419  * the SMB1 header and everything, in sr->reply.
420  * The caller will send it and free the request.
421  */
422 void
423 smb1_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel)
424 {
425 	smb_ofile_t *ofile = sr->fid_ofile;
426 	uint16_t fid;
427 	uint8_t lock_type;
428 	uint8_t oplock_level;
429 
430 	/*
431 	 * Convert internal level to SMB1
432 	 */
433 	switch (NewLevel) {
434 	default:
435 		ASSERT(0);
436 		/* FALLTHROUGH */
437 	case OPLOCK_LEVEL_NONE:
438 		oplock_level = 0;
439 		break;
440 
441 	case OPLOCK_LEVEL_TWO:
442 		oplock_level = 1;
443 		break;
444 	}
445 
446 	sr->smb_com = SMB_COM_LOCKING_ANDX;
447 	sr->smb_tid = ofile->f_tree->t_tid;
448 	sr->smb_pid = 0xFFFF;
449 	sr->smb_uid = 0;
450 	sr->smb_mid = 0xFFFF;
451 	fid = ofile->f_fid;
452 	lock_type = LOCKING_ANDX_OPLOCK_RELEASE;
453 
454 	(void) smb_mbc_encodef(
455 	    &sr->reply, "Mb19.wwwwbb3.wbb10.",
456 	    /*  "\xffSMB"		   M */
457 	    sr->smb_com,		/* b */
458 	    /* status, flags, signature	 19. */
459 	    sr->smb_tid,		/* w */
460 	    sr->smb_pid,		/* w */
461 	    sr->smb_uid,		/* w */
462 	    sr->smb_mid,		/* w */
463 	    8,		/* word count	   b */
464 	    0xFF,	/* AndX cmd	   b */
465 	    /*  AndX reserved, offset	  3. */
466 	    fid,
467 	    lock_type,
468 	    oplock_level);
469 }
470