xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c (revision 12890:16985853e3aa)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
2112508Samw@Sun.COM 
225331Samw /*
2312508Samw@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245331Samw  */
2512508Samw@Sun.COM 
265331Samw /*
275331Samw  * SMB: locking_andx
285331Samw  *
295331Samw  * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
305331Samw  *
315331Samw  *  Client Request                     Description
325331Samw  *  ================================== =================================
335331Samw  *
345331Samw  *  UCHAR WordCount;                   Count of parameter words = 8
355331Samw  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF = none
365331Samw  *  UCHAR AndXReserved;                Reserved (must be 0)
375331Samw  *  USHORT AndXOffset;                 Offset to next command WordCount
385331Samw  *  USHORT Fid;                        File handle
395331Samw  *  UCHAR LockType;                    See LockType table below
405331Samw  *  UCHAR OplockLevel;                 The new oplock level
415331Samw  *  ULONG Timeout;                     Milliseconds to wait for unlock
425331Samw  *  USHORT NumberOfUnlocks;            Num. unlock range structs following
435331Samw  *  USHORT NumberOfLocks;              Num. lock range structs following
445331Samw  *  USHORT ByteCount;                  Count of data bytes
455331Samw  *  LOCKING_ANDX_RANGE Unlocks[];      Unlock ranges
465331Samw  *  LOCKING_ANDX_RANGE Locks[];        Lock ranges
475331Samw  *
485331Samw  *  LockType Flag Name            Value Description
495331Samw  *  ============================  ===== ================================
505331Samw  *
515331Samw  *  LOCKING_ANDX_SHARED_LOCK      0x01  Read-only lock
525331Samw  *  LOCKING_ANDX_OPLOCK_RELEASE   0x02  Oplock break notification
535331Samw  *  LOCKING_ANDX_CHANGE_LOCKTYPE  0x04  Change lock type
545331Samw  *  LOCKING_ANDX_CANCEL_LOCK      0x08  Cancel outstanding request
555331Samw  *  LOCKING_ANDX_LARGE_FILES      0x10  Large file locking format
565331Samw  *
575331Samw  *  LOCKING_ANDX_RANGE Format
585331Samw  *  =====================================================================
595331Samw  *
605331Samw  *  USHORT Pid;                        PID of process "owning" lock
615331Samw  *  ULONG Offset;                      Offset to bytes to [un]lock
625331Samw  *  ULONG Length;                      Number of bytes to [un]lock
635331Samw  *
645331Samw  *  Large File LOCKING_ANDX_RANGE Format
655331Samw  *  =====================================================================
665331Samw  *
675331Samw  *  USHORT Pid;                        PID of process "owning" lock
685331Samw  *  USHORT Pad;                        Pad to DWORD align (mbz)
695331Samw  *  ULONG OffsetHigh;                  Offset to bytes to [un]lock
705331Samw  *                                      (high)
715331Samw  *  ULONG OffsetLow;                   Offset to bytes to [un]lock (low)
725331Samw  *  ULONG LengthHigh;                  Number of bytes to [un]lock
735331Samw  *                                      (high)
745331Samw  *  ULONG LengthLow;                   Number of bytes to [un]lock (low)
755331Samw  *
765331Samw  *  Server Response                    Description
775331Samw  *  ================================== =================================
785331Samw  *
795331Samw  *  UCHAR WordCount;                   Count of parameter words = 2
805331Samw  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF =
815331Samw  *                                      none
825331Samw  *  UCHAR AndXReserved;                Reserved (must be 0)
835331Samw  *  USHORT AndXOffset;                 Offset to next command WordCount
845331Samw  *  USHORT ByteCount;                  Count of data bytes = 0
855331Samw  *
865331Samw  * Locking is a simple mechanism for excluding other processes read/write
875331Samw  * access to regions of a file.  The locked regions can be anywhere in the
885331Samw  * logical file.  Locking beyond end-of-file is permitted.  Any process
895331Samw  * using the Fid specified in this request's Fid has access to the locked
905331Samw  * bytes, other processes will be denied the locking of the same bytes.
915331Samw  *
925331Samw  * The proper method for using locks is not to rely on being denied read or
935331Samw  * write access on any of the read/write protocols but rather to attempt
945331Samw  * the locking protocol and proceed with the read/write only if the locks
955331Samw  * succeeded.
965331Samw  *
975331Samw  * Locking a range of bytes will fail if any subranges or overlapping
985331Samw  * ranges are locked.  In other words, if any of the specified bytes are
995331Samw  * already locked, the lock will fail.
1005331Samw  *
1015331Samw  * If NumberOfUnlocks is non-zero, the Unlocks vector contains
1025331Samw  * NumberOfUnlocks elements.  Each element requests that a lock at Offset
1035331Samw  * of Length be released.  If NumberOfLocks is nonzero, the Locks vector
1045331Samw  * contains NumberOfLocks elements.  Each element requests the acquisition
1055331Samw  * of a lock at Offset of Length.
1065331Samw  *
1075331Samw  * Timeout is the maximum amount of time to wait for the byte range(s)
1085331Samw  * specified to become unlocked.  A timeout value of 0 indicates that the
1095331Samw  * server should fail immediately if any lock range specified is locked.  A
1105331Samw  *
1115331Samw  * timeout value of -1 indicates that the server should wait as long as it
1125331Samw  * takes for each byte range specified to become unlocked so that it may be
1135331Samw  * again locked by this protocol.  Any other value of smb_timeout specifies
1145331Samw  * the maximum number of milliseconds to wait for all lock range(s)
1155331Samw  * specified to become available.
1165331Samw  *
1175331Samw  * If any of the lock ranges timeout because of the area to be locked is
1185331Samw  * already locked (or the lock fails), the other ranges in the protocol
1195331Samw  * request which were successfully locked as a result of this protocol will
1205331Samw  * be unlocked (either all requested ranges will be locked when this
1215331Samw  * protocol returns to the client or none).
1225331Samw  *
1235331Samw  * If LockType has the LOCKING_ANDX_SHARED_LOCK flag set, the lock is
1245331Samw  * specified as a shared lock.  Locks for both read and write (where
1255331Samw  * LOCKING_ANDX_SHARED_LOCK is clear) should be prohibited, but other
1265331Samw  * shared locks should be permitted.  If shared locks can not be supported
1275331Samw  * by a server, the server should map the lock to a lock for both read and
1285331Samw  * write.  Closing a file with locks still in force causes the locks to be
1295331Samw  * released in no defined order.
1305331Samw  *
1315331Samw  * If LockType has the LOCKING_ANDX_LARGE_FILES flag set and if the
1325331Samw  * negotiated protocol is NT LM 0.12 or later, then the Locks and Unlocks
1335331Samw  * vectors are in the Large File LOCKING_ANDX_RANGE format.  This allows
1345331Samw  * specification of 64 bit offsets for very large files.
1355331Samw  *
1365331Samw  * If the one and only member of the Locks vector has the
1375331Samw  * LOCKING_ANDX_CANCEL_LOCK flag set in the LockType field, the client is
1385331Samw  * requesting the server to cancel a previously requested, but not yet
1395331Samw  * responded to, lock.
1405331Samw  *
1415331Samw  * If LockType has the LOCKING_ANDX_CHANGE_LOCKTYPE flag set, the client is
1425331Samw  * requesting that the server atomically change the lock type from a shared
1435331Samw  * lock to an exclusive lock or vice versa.  If the server can not do this
1445331Samw  * in an atomic fashion, the server must reject this request.  NT and W95
1455331Samw  * servers do not support this capability.
1465331Samw  *
1475331Samw  * Oplocks are described in the "Opportunistic Locks" section elsewhere in
1485331Samw  * this document.  A client requests an oplock by setting the appropriate
1495331Samw  * bit in the SMB_COM_OPEN_ANDX request when the file is being opened in a
1505331Samw  * mode which is not exclusive.  The server responds by setting the
1515331Samw  * appropriate bit in the response SMB indicating whether or not the oplock
1525331Samw  * was granted.  By granting the oplock, the server tells the client the
1535331Samw  * file is currently only being used by this one client process at the
1545331Samw  * current time.  The client can therefore safely do read ahead and write
1555331Samw  * behind as well as local caching of file locks knowing that the file will
1565331Samw  * not be accessed/changed in any way by another process while the oplock
1575331Samw  * is in effect.  The client will be notified when any other process
1585331Samw  * attempts to open or modify the oplocked file.
1595331Samw  *
1605331Samw  * When another user attempts to open or otherwise modify the file which a
1615331Samw  * client has oplocked, the server delays the second attempt and notifies
1625331Samw  * the client via an SMB_LOCKING_ANDX SMB asynchronously sent from the
1635331Samw  * server to the client.  This message has the LOCKING_ANDX_OPLOCK_RELEASE
1645331Samw  * flag set indicating to the client that the oplock is being broken.
1655331Samw  *
1665331Samw  * OplockLevel indicates the type of oplock the client now owns. If
1675331Samw  * OplockLevel is 0, the client possesses no oplocks on the file at all, if
1685331Samw  * OplockLevel is 1 the client possesses a Level II oplock.  The client is
1695331Samw  * expected to flush any dirty buffers to the server, submit any file locks
1705331Samw  * and respond to the server with either an SMB_LOCKING_ANDX SMB having the
1715331Samw  * LOCKING_ANDX_OPLOCK_RELEASE flag set, or with a file close if the file
1725331Samw  * is no longer in use by the client.  If the client sends an
1735331Samw  * SMB_LOCKING_ANDX SMB with the LOCKING_ANDX_OPLOCK_RELEASE flag set and
1745331Samw  * NumberOfLocks is zero, the server does not send a response.  Since a
1755331Samw  * close being sent to the server and break oplock notification from the
1765331Samw  * server could cross on the wire, if the client gets an oplock
1775331Samw  * notification on a file which it does not have open, that notification
1785331Samw  * should be ignored.
1795331Samw  *
1805331Samw  * Due to timing, the client could get an "oplock broken" notification in a
1815331Samw  * user's data buffer as a result of this notification crossing on the wire
1825331Samw  * with a SMB_COM_READ_RAW request.  The client must detect this (use
1835331Samw  * length of msg, "FFSMB", MID of -1 and Command of SMB_COM_LOCKING_ANDX)
1845331Samw  * and honor the "oplock broken" notification as usual.  The server must
1855331Samw  * also note on receipt of an SMB_COM_READ_RAW request that there is an
1865331Samw  * outstanding (unanswered) "oplock broken" notification to the client and
1875331Samw  * return a zero length response denoting failure of the read raw request.
1885331Samw  * The client should (after responding to the "oplock broken"
1895331Samw  * notification), use a standard read protocol to redo the read request.
1905331Samw  * This allows a file to actually contain data matching an "oplock broken"
1915331Samw  * notification and still be read correctly.
1925331Samw  *
1935331Samw  * The entire message sent and received including the optional second
1945331Samw  * protocol must fit in the negotiated maximum transfer size.  The
1955331Samw  * following are the only valid SMB commands for AndXCommand for
1965331Samw  * SMB_COM_LOCKING_ANDX:
1975331Samw  *
1985331Samw  *     SMB_COM_READ       SMB_COM_READ_ANDX
1995331Samw  *     SMB_COM_WRITE      SMB_COM_WRITE_ANDX
2005331Samw  *     SMB_COM_FLUSH
2015331Samw  *
2025331Samw  * 4.2.6.1   Errors
2035331Samw  *
2045331Samw  * ERRDOS/ERRbadfile
2055331Samw  * ERRDOS/ERRbadfid
2065331Samw  * ERRDOS/ERRlock
2075331Samw  * ERRDOS/ERRinvdevice
2085331Samw  * ERRSRV/ERRinvid
2095331Samw  * ERRSRV/ERRbaduid
2105331Samw  */
2115331Samw 
21210966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
2135331Samw 
2146030Sjb150015 smb_sdrc_t
smb_pre_locking_andx(smb_request_t * sr)2156139Sjb150015 smb_pre_locking_andx(smb_request_t *sr)
2166139Sjb150015 {
2176139Sjb150015 	DTRACE_SMB_1(op__LockingX__start, smb_request_t *, sr);
2186139Sjb150015 	return (SDRC_SUCCESS);
2196139Sjb150015 }
2206139Sjb150015 
2216139Sjb150015 void
smb_post_locking_andx(smb_request_t * sr)2226139Sjb150015 smb_post_locking_andx(smb_request_t *sr)
2236139Sjb150015 {
2246139Sjb150015 	DTRACE_SMB_1(op__LockingX__done, smb_request_t *, sr);
2256139Sjb150015 }
2266139Sjb150015 
2276139Sjb150015 smb_sdrc_t
smb_com_locking_andx(smb_request_t * sr)2286139Sjb150015 smb_com_locking_andx(smb_request_t *sr)
2295331Samw {
2305331Samw 	unsigned short	i;
2315331Samw 	unsigned char	lock_type;	/* See lock_type table above */
2325331Samw 	unsigned char	oplock_level;	/* The new oplock level */
2335331Samw 	uint32_t	timeout;	/* Milliseconds to wait for lock */
2345331Samw 	unsigned short	unlock_num;	/* # unlock range structs */
2355331Samw 	unsigned short	lock_num;	/* # lock range structs */
2365331Samw 	unsigned short	pid;		/* Process Id of owner */
2375331Samw 	uint32_t	offset32, length32;
2385331Samw 	uint64_t	offset64;
2395331Samw 	uint64_t	length64;
2405331Samw 	DWORD		result;
2415331Samw 	int 		rc;
2425331Samw 	uint32_t	ltype;
243*12890SJoyce.McIntosh@Sun.COM 	smb_ofile_t	*ofile;
244*12890SJoyce.McIntosh@Sun.COM 	uint8_t		brk;
2455331Samw 
2465331Samw 	rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type,
2475331Samw 	    &oplock_level, &timeout, &unlock_num, &lock_num);
2486030Sjb150015 	if (rc != 0)
2496139Sjb150015 		return (SDRC_ERROR);
2505331Samw 
2518934SJose.Borrego@Sun.COM 	smbsr_lookup_file(sr);
2525331Samw 	if (sr->fid_ofile == NULL) {
2535772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
2546139Sjb150015 		return (SDRC_ERROR);
2555331Samw 	}
256*12890SJoyce.McIntosh@Sun.COM 	ofile = sr->fid_ofile;
2575331Samw 
2585331Samw 	if (lock_type & LOCKING_ANDX_SHARED_LOCK)
2595331Samw 		ltype = SMB_LOCK_TYPE_READONLY;
2605331Samw 	else
2615331Samw 		ltype = SMB_LOCK_TYPE_READWRITE;
2625331Samw 
2635331Samw 	pid = sr->smb_pid;	/* Save the original pid */
2645331Samw 
2655331Samw 	if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
266*12890SJoyce.McIntosh@Sun.COM 		if (oplock_level == 0)
267*12890SJoyce.McIntosh@Sun.COM 			brk = SMB_OPLOCK_BREAK_TO_NONE;
268*12890SJoyce.McIntosh@Sun.COM 		else
269*12890SJoyce.McIntosh@Sun.COM 			brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
270*12890SJoyce.McIntosh@Sun.COM 		smb_oplock_ack(ofile->f_node, ofile, brk);
2715331Samw 		if (unlock_num == 0 && lock_num == 0)
2725331Samw 			return (SDRC_NO_REPLY);
2735331Samw 	}
2745331Samw 
2755331Samw 	/*
2765331Samw 	 * No support for changing locktype (although we could probably
2775331Samw 	 * implement this)
2785331Samw 	 */
2795331Samw 	if (lock_type & LOCKING_ANDX_CHANGE_LOCK_TYPE) {
28012508Samw@Sun.COM 		smbsr_error(sr, 0, ERRDOS,
28112508Samw@Sun.COM 		    ERROR_ATOMIC_LOCKS_NOT_SUPPORTED);
2826139Sjb150015 		return (SDRC_ERROR);
2835331Samw 	}
2845331Samw 
2855331Samw 	/*
2865331Samw 	 * No support for cancel lock (smbtorture expects this)
2875331Samw 	 */
2885331Samw 	if (lock_type & LOCKING_ANDX_CANCEL_LOCK) {
2895772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
2905331Samw 		    ERRDOS, ERROR_INVALID_PARAMETER);
2916139Sjb150015 		return (SDRC_ERROR);
2925331Samw 	}
2935331Samw 
2945331Samw 	if (lock_type & LOCKING_ANDX_LARGE_FILES) {
2955331Samw 		/*
2965331Samw 		 * negotiated protocol should be NT LM 0.12 or later
2975331Samw 		 */
2985331Samw 		if (sr->session->dialect < NT_LM_0_12) {
2995772Sas200622 			smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
3005331Samw 			    ERRDOS, ERROR_INVALID_PARAMETER);
3016139Sjb150015 			return (SDRC_ERROR);
3025331Samw 		}
3035331Samw 
3045331Samw 		for (i = 0; i < unlock_num; i++) {
3057052Samw 			rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
3065331Samw 			    &sr->smb_pid, &offset64, &length64);
3075331Samw 			if (rc) {
3085331Samw 				/*
3095772Sas200622 				 * This is the error returned by Windows 2000
3105772Sas200622 				 * even when STATUS32 has been negotiated.
3115331Samw 				 */
3125772Sas200622 				smbsr_error(sr, 0, ERRSRV, ERRerror);
3136139Sjb150015 				return (SDRC_ERROR);
3145331Samw 			}
3155331Samw 
3165331Samw 			result = smb_unlock_range(sr, sr->fid_ofile->f_node,
3175331Samw 			    offset64, length64);
3185331Samw 			if (result != NT_STATUS_SUCCESS) {
3195772Sas200622 				smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
32012508Samw@Sun.COM 				    ERRDOS, ERROR_NOT_LOCKED);
3216139Sjb150015 				return (SDRC_ERROR);
3225331Samw 			}
3235331Samw 		}
3245331Samw 
3255331Samw 		for (i = 0; i < lock_num; i++) {
3267052Samw 			rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
3275331Samw 			    &sr->smb_pid, &offset64, &length64);
3285331Samw 			if (rc) {
3295772Sas200622 				smbsr_error(sr, 0, ERRSRV, ERRerror);
3306139Sjb150015 				return (SDRC_ERROR);
3315331Samw 			}
3325331Samw 
3336432Sas200622 			result = smb_lock_range(sr, offset64, length64, timeout,
3346432Sas200622 			    ltype);
3355331Samw 			if (result != NT_STATUS_SUCCESS) {
3365772Sas200622 				smb_lock_range_error(sr, result);
3376139Sjb150015 				return (SDRC_ERROR);
3385331Samw 			}
3395331Samw 		}
3405331Samw 	} else {
3415331Samw 		for (i = 0; i < unlock_num; i++) {
3427052Samw 			rc = smb_mbc_decodef(&sr->smb_data, "wll", &sr->smb_pid,
3435331Samw 			    &offset32, &length32);
3445331Samw 			if (rc) {
3455772Sas200622 				smbsr_error(sr, 0, ERRSRV, ERRerror);
3466139Sjb150015 				return (SDRC_ERROR);
3475331Samw 			}
3485331Samw 
3495331Samw 			result = smb_unlock_range(sr, sr->fid_ofile->f_node,
3505331Samw 			    (uint64_t)offset32, (uint64_t)length32);
3515331Samw 			if (result != NT_STATUS_SUCCESS) {
3525772Sas200622 				smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
35312508Samw@Sun.COM 				    ERRDOS, ERROR_NOT_LOCKED);
3546139Sjb150015 				return (SDRC_ERROR);
3555331Samw 			}
3565331Samw 		}
3575331Samw 
3585331Samw 		for (i = 0; i < lock_num; i++) {
3597052Samw 			rc = smb_mbc_decodef(&sr->smb_data, "wll", &sr->smb_pid,
3605331Samw 			    &offset32, &length32);
3615331Samw 			if (rc) {
3625772Sas200622 				smbsr_error(sr, 0, ERRSRV, ERRerror);
3636139Sjb150015 				return (SDRC_ERROR);
3645331Samw 			}
3655331Samw 
3666432Sas200622 			result = smb_lock_range(sr, (uint64_t)offset32,
3676432Sas200622 			    (uint64_t)length32, timeout, ltype);
3685331Samw 			if (result != NT_STATUS_SUCCESS) {
3695772Sas200622 				smb_lock_range_error(sr, result);
3706139Sjb150015 				return (SDRC_ERROR);
3715331Samw 			}
3725331Samw 		}
3735331Samw 	}
3745331Samw 
3755331Samw 	sr->smb_pid = pid;
3766030Sjb150015 	if (smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, 7, 0))
3776139Sjb150015 		return (SDRC_ERROR);
3786139Sjb150015 	return (SDRC_SUCCESS);
3795331Samw }
380