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 /* 22*dc20a302Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27da6c28aaSamw 28da6c28aaSamw /* 29da6c28aaSamw * SMB: locking_andx 30da6c28aaSamw * 31da6c28aaSamw * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s). 32da6c28aaSamw * 33da6c28aaSamw * Client Request Description 34da6c28aaSamw * ================================== ================================= 35da6c28aaSamw * 36da6c28aaSamw * UCHAR WordCount; Count of parameter words = 8 37da6c28aaSamw * UCHAR AndXCommand; Secondary (X) command; 0xFF = none 38da6c28aaSamw * UCHAR AndXReserved; Reserved (must be 0) 39da6c28aaSamw * USHORT AndXOffset; Offset to next command WordCount 40da6c28aaSamw * USHORT Fid; File handle 41da6c28aaSamw * UCHAR LockType; See LockType table below 42da6c28aaSamw * UCHAR OplockLevel; The new oplock level 43da6c28aaSamw * ULONG Timeout; Milliseconds to wait for unlock 44da6c28aaSamw * USHORT NumberOfUnlocks; Num. unlock range structs following 45da6c28aaSamw * USHORT NumberOfLocks; Num. lock range structs following 46da6c28aaSamw * USHORT ByteCount; Count of data bytes 47da6c28aaSamw * LOCKING_ANDX_RANGE Unlocks[]; Unlock ranges 48da6c28aaSamw * LOCKING_ANDX_RANGE Locks[]; Lock ranges 49da6c28aaSamw * 50da6c28aaSamw * LockType Flag Name Value Description 51da6c28aaSamw * ============================ ===== ================================ 52da6c28aaSamw * 53da6c28aaSamw * LOCKING_ANDX_SHARED_LOCK 0x01 Read-only lock 54da6c28aaSamw * LOCKING_ANDX_OPLOCK_RELEASE 0x02 Oplock break notification 55da6c28aaSamw * LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 Change lock type 56da6c28aaSamw * LOCKING_ANDX_CANCEL_LOCK 0x08 Cancel outstanding request 57da6c28aaSamw * LOCKING_ANDX_LARGE_FILES 0x10 Large file locking format 58da6c28aaSamw * 59da6c28aaSamw * LOCKING_ANDX_RANGE Format 60da6c28aaSamw * ===================================================================== 61da6c28aaSamw * 62da6c28aaSamw * USHORT Pid; PID of process "owning" lock 63da6c28aaSamw * ULONG Offset; Offset to bytes to [un]lock 64da6c28aaSamw * ULONG Length; Number of bytes to [un]lock 65da6c28aaSamw * 66da6c28aaSamw * Large File LOCKING_ANDX_RANGE Format 67da6c28aaSamw * ===================================================================== 68da6c28aaSamw * 69da6c28aaSamw * USHORT Pid; PID of process "owning" lock 70da6c28aaSamw * USHORT Pad; Pad to DWORD align (mbz) 71da6c28aaSamw * ULONG OffsetHigh; Offset to bytes to [un]lock 72da6c28aaSamw * (high) 73da6c28aaSamw * ULONG OffsetLow; Offset to bytes to [un]lock (low) 74da6c28aaSamw * ULONG LengthHigh; Number of bytes to [un]lock 75da6c28aaSamw * (high) 76da6c28aaSamw * ULONG LengthLow; Number of bytes to [un]lock (low) 77da6c28aaSamw * 78da6c28aaSamw * Server Response Description 79da6c28aaSamw * ================================== ================================= 80da6c28aaSamw * 81da6c28aaSamw * UCHAR WordCount; Count of parameter words = 2 82da6c28aaSamw * UCHAR AndXCommand; Secondary (X) command; 0xFF = 83da6c28aaSamw * none 84da6c28aaSamw * UCHAR AndXReserved; Reserved (must be 0) 85da6c28aaSamw * USHORT AndXOffset; Offset to next command WordCount 86da6c28aaSamw * USHORT ByteCount; Count of data bytes = 0 87da6c28aaSamw * 88da6c28aaSamw * Locking is a simple mechanism for excluding other processes read/write 89da6c28aaSamw * access to regions of a file. The locked regions can be anywhere in the 90da6c28aaSamw * logical file. Locking beyond end-of-file is permitted. Any process 91da6c28aaSamw * using the Fid specified in this request's Fid has access to the locked 92da6c28aaSamw * bytes, other processes will be denied the locking of the same bytes. 93da6c28aaSamw * 94da6c28aaSamw * The proper method for using locks is not to rely on being denied read or 95da6c28aaSamw * write access on any of the read/write protocols but rather to attempt 96da6c28aaSamw * the locking protocol and proceed with the read/write only if the locks 97da6c28aaSamw * succeeded. 98da6c28aaSamw * 99da6c28aaSamw * Locking a range of bytes will fail if any subranges or overlapping 100da6c28aaSamw * ranges are locked. In other words, if any of the specified bytes are 101da6c28aaSamw * already locked, the lock will fail. 102da6c28aaSamw * 103da6c28aaSamw * If NumberOfUnlocks is non-zero, the Unlocks vector contains 104da6c28aaSamw * NumberOfUnlocks elements. Each element requests that a lock at Offset 105da6c28aaSamw * of Length be released. If NumberOfLocks is nonzero, the Locks vector 106da6c28aaSamw * contains NumberOfLocks elements. Each element requests the acquisition 107da6c28aaSamw * of a lock at Offset of Length. 108da6c28aaSamw * 109da6c28aaSamw * Timeout is the maximum amount of time to wait for the byte range(s) 110da6c28aaSamw * specified to become unlocked. A timeout value of 0 indicates that the 111da6c28aaSamw * server should fail immediately if any lock range specified is locked. A 112da6c28aaSamw * 113da6c28aaSamw * timeout value of -1 indicates that the server should wait as long as it 114da6c28aaSamw * takes for each byte range specified to become unlocked so that it may be 115da6c28aaSamw * again locked by this protocol. Any other value of smb_timeout specifies 116da6c28aaSamw * the maximum number of milliseconds to wait for all lock range(s) 117da6c28aaSamw * specified to become available. 118da6c28aaSamw * 119da6c28aaSamw * If any of the lock ranges timeout because of the area to be locked is 120da6c28aaSamw * already locked (or the lock fails), the other ranges in the protocol 121da6c28aaSamw * request which were successfully locked as a result of this protocol will 122da6c28aaSamw * be unlocked (either all requested ranges will be locked when this 123da6c28aaSamw * protocol returns to the client or none). 124da6c28aaSamw * 125da6c28aaSamw * If LockType has the LOCKING_ANDX_SHARED_LOCK flag set, the lock is 126da6c28aaSamw * specified as a shared lock. Locks for both read and write (where 127da6c28aaSamw * LOCKING_ANDX_SHARED_LOCK is clear) should be prohibited, but other 128da6c28aaSamw * shared locks should be permitted. If shared locks can not be supported 129da6c28aaSamw * by a server, the server should map the lock to a lock for both read and 130da6c28aaSamw * write. Closing a file with locks still in force causes the locks to be 131da6c28aaSamw * released in no defined order. 132da6c28aaSamw * 133da6c28aaSamw * If LockType has the LOCKING_ANDX_LARGE_FILES flag set and if the 134da6c28aaSamw * negotiated protocol is NT LM 0.12 or later, then the Locks and Unlocks 135da6c28aaSamw * vectors are in the Large File LOCKING_ANDX_RANGE format. This allows 136da6c28aaSamw * specification of 64 bit offsets for very large files. 137da6c28aaSamw * 138da6c28aaSamw * If the one and only member of the Locks vector has the 139da6c28aaSamw * LOCKING_ANDX_CANCEL_LOCK flag set in the LockType field, the client is 140da6c28aaSamw * requesting the server to cancel a previously requested, but not yet 141da6c28aaSamw * responded to, lock. 142da6c28aaSamw * 143da6c28aaSamw * If LockType has the LOCKING_ANDX_CHANGE_LOCKTYPE flag set, the client is 144da6c28aaSamw * requesting that the server atomically change the lock type from a shared 145da6c28aaSamw * lock to an exclusive lock or vice versa. If the server can not do this 146da6c28aaSamw * in an atomic fashion, the server must reject this request. NT and W95 147da6c28aaSamw * servers do not support this capability. 148da6c28aaSamw * 149da6c28aaSamw * Oplocks are described in the "Opportunistic Locks" section elsewhere in 150da6c28aaSamw * this document. A client requests an oplock by setting the appropriate 151da6c28aaSamw * bit in the SMB_COM_OPEN_ANDX request when the file is being opened in a 152da6c28aaSamw * mode which is not exclusive. The server responds by setting the 153da6c28aaSamw * appropriate bit in the response SMB indicating whether or not the oplock 154da6c28aaSamw * was granted. By granting the oplock, the server tells the client the 155da6c28aaSamw * file is currently only being used by this one client process at the 156da6c28aaSamw * current time. The client can therefore safely do read ahead and write 157da6c28aaSamw * behind as well as local caching of file locks knowing that the file will 158da6c28aaSamw * not be accessed/changed in any way by another process while the oplock 159da6c28aaSamw * is in effect. The client will be notified when any other process 160da6c28aaSamw * attempts to open or modify the oplocked file. 161da6c28aaSamw * 162da6c28aaSamw * When another user attempts to open or otherwise modify the file which a 163da6c28aaSamw * client has oplocked, the server delays the second attempt and notifies 164da6c28aaSamw * the client via an SMB_LOCKING_ANDX SMB asynchronously sent from the 165da6c28aaSamw * server to the client. This message has the LOCKING_ANDX_OPLOCK_RELEASE 166da6c28aaSamw * flag set indicating to the client that the oplock is being broken. 167da6c28aaSamw * 168da6c28aaSamw * OplockLevel indicates the type of oplock the client now owns. If 169da6c28aaSamw * OplockLevel is 0, the client possesses no oplocks on the file at all, if 170da6c28aaSamw * OplockLevel is 1 the client possesses a Level II oplock. The client is 171da6c28aaSamw * expected to flush any dirty buffers to the server, submit any file locks 172da6c28aaSamw * and respond to the server with either an SMB_LOCKING_ANDX SMB having the 173da6c28aaSamw * LOCKING_ANDX_OPLOCK_RELEASE flag set, or with a file close if the file 174da6c28aaSamw * is no longer in use by the client. If the client sends an 175da6c28aaSamw * SMB_LOCKING_ANDX SMB with the LOCKING_ANDX_OPLOCK_RELEASE flag set and 176da6c28aaSamw * NumberOfLocks is zero, the server does not send a response. Since a 177da6c28aaSamw * close being sent to the server and break oplock notification from the 178da6c28aaSamw * server could cross on the wire, if the client gets an oplock 179da6c28aaSamw * notification on a file which it does not have open, that notification 180da6c28aaSamw * should be ignored. 181da6c28aaSamw * 182da6c28aaSamw * Due to timing, the client could get an "oplock broken" notification in a 183da6c28aaSamw * user's data buffer as a result of this notification crossing on the wire 184da6c28aaSamw * with a SMB_COM_READ_RAW request. The client must detect this (use 185da6c28aaSamw * length of msg, "FFSMB", MID of -1 and Command of SMB_COM_LOCKING_ANDX) 186da6c28aaSamw * and honor the "oplock broken" notification as usual. The server must 187da6c28aaSamw * also note on receipt of an SMB_COM_READ_RAW request that there is an 188da6c28aaSamw * outstanding (unanswered) "oplock broken" notification to the client and 189da6c28aaSamw * return a zero length response denoting failure of the read raw request. 190da6c28aaSamw * The client should (after responding to the "oplock broken" 191da6c28aaSamw * notification), use a standard read protocol to redo the read request. 192da6c28aaSamw * This allows a file to actually contain data matching an "oplock broken" 193da6c28aaSamw * notification and still be read correctly. 194da6c28aaSamw * 195da6c28aaSamw * The entire message sent and received including the optional second 196da6c28aaSamw * protocol must fit in the negotiated maximum transfer size. The 197da6c28aaSamw * following are the only valid SMB commands for AndXCommand for 198da6c28aaSamw * SMB_COM_LOCKING_ANDX: 199da6c28aaSamw * 200da6c28aaSamw * SMB_COM_READ SMB_COM_READ_ANDX 201da6c28aaSamw * SMB_COM_WRITE SMB_COM_WRITE_ANDX 202da6c28aaSamw * SMB_COM_FLUSH 203da6c28aaSamw * 204da6c28aaSamw * 4.2.6.1 Errors 205da6c28aaSamw * 206da6c28aaSamw * ERRDOS/ERRbadfile 207da6c28aaSamw * ERRDOS/ERRbadfid 208da6c28aaSamw * ERRDOS/ERRlock 209da6c28aaSamw * ERRDOS/ERRinvdevice 210da6c28aaSamw * ERRSRV/ERRinvid 211da6c28aaSamw * ERRSRV/ERRbaduid 212da6c28aaSamw */ 213da6c28aaSamw 214da6c28aaSamw #include <smbsrv/smb_incl.h> 215da6c28aaSamw 216da6c28aaSamw int 217da6c28aaSamw smb_com_locking_andx(struct smb_request *sr) 218da6c28aaSamw { 219da6c28aaSamw unsigned short i; 220da6c28aaSamw unsigned char lock_type; /* See lock_type table above */ 221da6c28aaSamw unsigned char oplock_level; /* The new oplock level */ 222da6c28aaSamw uint32_t timeout; /* Milliseconds to wait for lock */ 223da6c28aaSamw unsigned short unlock_num; /* # unlock range structs */ 224da6c28aaSamw unsigned short lock_num; /* # lock range structs */ 225da6c28aaSamw unsigned short pid; /* Process Id of owner */ 226da6c28aaSamw uint32_t offset32, length32; 227da6c28aaSamw uint64_t offset64; 228da6c28aaSamw uint64_t length64; 229da6c28aaSamw DWORD result; 230da6c28aaSamw int rc; 231da6c28aaSamw uint32_t ltype; 232da6c28aaSamw 233da6c28aaSamw rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type, 234da6c28aaSamw &oplock_level, &timeout, &unlock_num, &lock_num); 235da6c28aaSamw if (rc != 0) { 236da6c28aaSamw smbsr_decode_error(sr); 237da6c28aaSamw /* NOTREACHED */ 238da6c28aaSamw } 239da6c28aaSamw 240da6c28aaSamw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 241da6c28aaSamw if (sr->fid_ofile == NULL) { 242*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 243da6c28aaSamw /* NOTREACHED */ 244da6c28aaSamw } 245da6c28aaSamw 246da6c28aaSamw if (lock_type & LOCKING_ANDX_SHARED_LOCK) 247da6c28aaSamw ltype = SMB_LOCK_TYPE_READONLY; 248da6c28aaSamw else 249da6c28aaSamw ltype = SMB_LOCK_TYPE_READWRITE; 250da6c28aaSamw 251da6c28aaSamw pid = sr->smb_pid; /* Save the original pid */ 252da6c28aaSamw 253da6c28aaSamw if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) { 254da6c28aaSamw smb_release_oplock(sr->fid_ofile, OPLOCK_RELEASE_LOCK_RELEASED); 255da6c28aaSamw 256da6c28aaSamw /* 257da6c28aaSamw * According to the protocol: 258da6c28aaSamw * 259da6c28aaSamw * If the client sends an SMB_LOCKING_ANDX request with the 260da6c28aaSamw * LOCKING_ANDX_OPLOCK_RELEASE flag set 261da6c28aaSamw * and NumberOfLocks is zero, 262da6c28aaSamw * the server does not send a response. 263da6c28aaSamw * 264da6c28aaSamw * I'm not sure if it's going to break anything if I change 265da6c28aaSamw * it according to the protocol. So, I leave it unchanged 266da6c28aaSamw * for now. 267da6c28aaSamw */ 268da6c28aaSamw if (unlock_num == 0 && lock_num == 0) 269da6c28aaSamw return (SDRC_NO_REPLY); 270da6c28aaSamw } 271da6c28aaSamw 272da6c28aaSamw /* 273da6c28aaSamw * No support for changing locktype (although we could probably 274da6c28aaSamw * implement this) 275da6c28aaSamw */ 276da6c28aaSamw if (lock_type & LOCKING_ANDX_CHANGE_LOCK_TYPE) { 277*dc20a302Sas200622 smbsr_error(sr, 0, ERRDOS, ERRnoatomiclocks); 278da6c28aaSamw /* NOT REACHED */ 279da6c28aaSamw } 280da6c28aaSamw 281da6c28aaSamw /* 282da6c28aaSamw * No support for cancel lock (smbtorture expects this) 283da6c28aaSamw */ 284da6c28aaSamw if (lock_type & LOCKING_ANDX_CANCEL_LOCK) { 285*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 286da6c28aaSamw ERRDOS, ERROR_INVALID_PARAMETER); 287da6c28aaSamw /* NOT REACHED */ 288da6c28aaSamw } 289da6c28aaSamw 290da6c28aaSamw if (lock_type & LOCKING_ANDX_LARGE_FILES) { 291da6c28aaSamw /* 292da6c28aaSamw * negotiated protocol should be NT LM 0.12 or later 293da6c28aaSamw */ 294da6c28aaSamw if (sr->session->dialect < NT_LM_0_12) { 295*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 296da6c28aaSamw ERRDOS, ERROR_INVALID_PARAMETER); 297da6c28aaSamw /* NOT REACHED */ 298da6c28aaSamw } 299da6c28aaSamw 300da6c28aaSamw for (i = 0; i < unlock_num; i++) { 301da6c28aaSamw rc = smb_decode_mbc(&sr->smb_data, "w2.QQ", 302da6c28aaSamw &sr->smb_pid, &offset64, &length64); 303da6c28aaSamw if (rc) { 304da6c28aaSamw /* 305*dc20a302Sas200622 * This is the error returned by Windows 2000 306*dc20a302Sas200622 * even when STATUS32 has been negotiated. 307da6c28aaSamw */ 308*dc20a302Sas200622 smbsr_error(sr, 0, ERRSRV, ERRerror); 309da6c28aaSamw /* NOT REACHED */ 310da6c28aaSamw } 311da6c28aaSamw 312da6c28aaSamw result = smb_unlock_range(sr, sr->fid_ofile->f_node, 313da6c28aaSamw offset64, length64); 314da6c28aaSamw if (result != NT_STATUS_SUCCESS) { 315*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 316*dc20a302Sas200622 ERRDOS, ERRnotlocked); 317da6c28aaSamw /* NOT REACHED */ 318da6c28aaSamw } 319da6c28aaSamw } 320da6c28aaSamw 321da6c28aaSamw for (i = 0; i < lock_num; i++) { 322da6c28aaSamw rc = smb_decode_mbc(&sr->smb_data, "w2.QQ", 323da6c28aaSamw &sr->smb_pid, &offset64, &length64); 324da6c28aaSamw if (rc) { 325*dc20a302Sas200622 smbsr_error(sr, 0, ERRSRV, ERRerror); 326da6c28aaSamw /* NOT REACHED */ 327da6c28aaSamw } 328da6c28aaSamw 329da6c28aaSamw result = smb_lock_range(sr, sr->fid_ofile, 330da6c28aaSamw offset64, length64, timeout, ltype); 331da6c28aaSamw if (result != NT_STATUS_SUCCESS) { 332*dc20a302Sas200622 smb_lock_range_error(sr, result); 333da6c28aaSamw /* NOT REACHED */ 334da6c28aaSamw } 335da6c28aaSamw } 336da6c28aaSamw } else { 337da6c28aaSamw for (i = 0; i < unlock_num; i++) { 338da6c28aaSamw rc = smb_decode_mbc(&sr->smb_data, "wll", &sr->smb_pid, 339da6c28aaSamw &offset32, &length32); 340da6c28aaSamw if (rc) { 341*dc20a302Sas200622 smbsr_error(sr, 0, ERRSRV, ERRerror); 342da6c28aaSamw /* NOT REACHED */ 343da6c28aaSamw } 344da6c28aaSamw 345da6c28aaSamw result = smb_unlock_range(sr, sr->fid_ofile->f_node, 346da6c28aaSamw (uint64_t)offset32, (uint64_t)length32); 347da6c28aaSamw if (result != NT_STATUS_SUCCESS) { 348*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 349*dc20a302Sas200622 ERRDOS, ERRnotlocked); 350da6c28aaSamw /* NOT REACHED */ 351da6c28aaSamw } 352da6c28aaSamw } 353da6c28aaSamw 354da6c28aaSamw for (i = 0; i < lock_num; i++) { 355da6c28aaSamw rc = smb_decode_mbc(&sr->smb_data, "wll", &sr->smb_pid, 356da6c28aaSamw &offset32, &length32); 357da6c28aaSamw if (rc) { 358*dc20a302Sas200622 smbsr_error(sr, 0, ERRSRV, ERRerror); 359da6c28aaSamw /* NOT REACHED */ 360da6c28aaSamw } 361da6c28aaSamw 362da6c28aaSamw result = smb_lock_range(sr, sr->fid_ofile, 363da6c28aaSamw (uint64_t)offset32, 364da6c28aaSamw (uint64_t)length32, 365da6c28aaSamw timeout, ltype); 366da6c28aaSamw if (result != NT_STATUS_SUCCESS) { 367*dc20a302Sas200622 smb_lock_range_error(sr, result); 368da6c28aaSamw /* NOT REACHED */ 369da6c28aaSamw } 370da6c28aaSamw } 371da6c28aaSamw } 372da6c28aaSamw 373da6c28aaSamw sr->smb_pid = pid; 374da6c28aaSamw smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, 7, 0); 375da6c28aaSamw 376da6c28aaSamw return (SDRC_NORMAL_REPLY); 377da6c28aaSamw } 378