1a90cf9f2SGordon Ross /* 2a90cf9f2SGordon Ross * This file and its contents are supplied under the terms of the 3a90cf9f2SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0. 4a90cf9f2SGordon Ross * You may only use this file in accordance with the terms of version 5a90cf9f2SGordon Ross * 1.0 of the CDDL. 6a90cf9f2SGordon Ross * 7a90cf9f2SGordon Ross * A full copy of the text of the CDDL should have accompanied this 8a90cf9f2SGordon Ross * source. A copy of the CDDL is also available via the Internet at 9a90cf9f2SGordon Ross * http://www.illumos.org/license/CDDL. 10a90cf9f2SGordon Ross */ 11a90cf9f2SGordon Ross 12a90cf9f2SGordon Ross /* 13*0897f7fbSGordon Ross * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 14a90cf9f2SGordon Ross */ 15a90cf9f2SGordon Ross 16a90cf9f2SGordon Ross /* 17a90cf9f2SGordon Ross * Dispatch function for SMB2_LOCK 18a90cf9f2SGordon Ross */ 19a90cf9f2SGordon Ross 20a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h> 21a90cf9f2SGordon Ross 22*0897f7fbSGordon Ross typedef struct SMB2_LOCK_ELEMENT { 23a90cf9f2SGordon Ross uint64_t Offset; 24a90cf9f2SGordon Ross uint64_t Length; 25a90cf9f2SGordon Ross uint32_t Flags; 26a90cf9f2SGordon Ross uint32_t reserved; 27*0897f7fbSGordon Ross } lock_elem_t; 28a90cf9f2SGordon Ross 29*0897f7fbSGordon Ross static uint32_t smb2_unlock(smb_request_t *); 30*0897f7fbSGordon Ross static uint32_t smb2_locks(smb_request_t *); 31a90cf9f2SGordon Ross static smb_sdrc_t smb2_lock_async(smb_request_t *); 32a90cf9f2SGordon Ross 33a90cf9f2SGordon Ross /* 34a90cf9f2SGordon Ross * This is a somewhat arbitrary sanity limit on the length of the 35a90cf9f2SGordon Ross * SMB2_LOCK_ELEMENT array. It usually has length one or two. 36a90cf9f2SGordon Ross */ 37a90cf9f2SGordon Ross int smb2_lock_max_elem = 1024; 38a90cf9f2SGordon Ross 39a90cf9f2SGordon Ross smb_sdrc_t 40a90cf9f2SGordon Ross smb2_lock(smb_request_t *sr) 41a90cf9f2SGordon Ross { 42*0897f7fbSGordon Ross lock_elem_t *lvec, *lk; 43a90cf9f2SGordon Ross smb2fid_t smb2fid; 44a90cf9f2SGordon Ross uint32_t LockSequence; 45a90cf9f2SGordon Ross uint32_t status; 46a90cf9f2SGordon Ross uint16_t StructSize; 47a90cf9f2SGordon Ross uint16_t LockCount; 48a90cf9f2SGordon Ross uint16_t i; 49*0897f7fbSGordon Ross int rc; 50a90cf9f2SGordon Ross 51a90cf9f2SGordon Ross /* 52a90cf9f2SGordon Ross * SMB2 Lock request 53a90cf9f2SGordon Ross */ 54a90cf9f2SGordon Ross rc = smb_mbc_decodef( 55a90cf9f2SGordon Ross &sr->smb_data, "wwlqq", 56a90cf9f2SGordon Ross &StructSize, /* w */ 57a90cf9f2SGordon Ross &LockCount, /* w */ 58a90cf9f2SGordon Ross &LockSequence, /* l */ 59a90cf9f2SGordon Ross &smb2fid.persistent, /* q */ 60a90cf9f2SGordon Ross &smb2fid.temporal); /* q */ 61a90cf9f2SGordon Ross if (rc || StructSize != 48) 62a90cf9f2SGordon Ross return (SDRC_ERROR); 63a90cf9f2SGordon Ross 64a90cf9f2SGordon Ross status = smb2sr_lookup_fid(sr, &smb2fid); 65a90cf9f2SGordon Ross if (status) 66a90cf9f2SGordon Ross goto errout; 67a90cf9f2SGordon Ross if (sr->fid_ofile->f_node == NULL || LockCount == 0) { 68a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 69a90cf9f2SGordon Ross goto errout; 70a90cf9f2SGordon Ross } 71a90cf9f2SGordon Ross if (LockCount > smb2_lock_max_elem) { 72a90cf9f2SGordon Ross status = NT_STATUS_INSUFFICIENT_RESOURCES; 73a90cf9f2SGordon Ross goto errout; 74a90cf9f2SGordon Ross } 75a90cf9f2SGordon Ross 76a90cf9f2SGordon Ross /* 77*0897f7fbSGordon Ross * Parse the array of SMB2_LOCK_ELEMENT structs. 78*0897f7fbSGordon Ross * This array is free'd in smb_srm_fini. 79a90cf9f2SGordon Ross */ 80*0897f7fbSGordon Ross lvec = smb_srm_zalloc(sr, LockCount * sizeof (*lvec)); 81a90cf9f2SGordon Ross for (i = 0; i < LockCount; i++) { 82*0897f7fbSGordon Ross lk = &lvec[i]; 83a90cf9f2SGordon Ross rc = smb_mbc_decodef( 84a90cf9f2SGordon Ross &sr->smb_data, "qqll", 85*0897f7fbSGordon Ross &lk->Offset, /* q */ 86*0897f7fbSGordon Ross &lk->Length, /* q */ 87*0897f7fbSGordon Ross &lk->Flags, /* l */ 88*0897f7fbSGordon Ross &lk->reserved); /* l */ 89a90cf9f2SGordon Ross if (rc) { 90a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 91a90cf9f2SGordon Ross goto errout; 92a90cf9f2SGordon Ross } 93*0897f7fbSGordon Ross } 94a90cf9f2SGordon Ross 95a90cf9f2SGordon Ross /* 96*0897f7fbSGordon Ross * [MS-SMB2] 3.3.5.14 97*0897f7fbSGordon Ross * If the flags of the [first element of] the Locks array 98*0897f7fbSGordon Ross * [has] SMB2_LOCKFLAG_UNLOCK set, the server MUST process 99*0897f7fbSGordon Ross * the lock array as a series of unlocks. Otherwise, it 100*0897f7fbSGordon Ross * MUST process the lock array as a series of lock requests. 101a90cf9f2SGordon Ross */ 102*0897f7fbSGordon Ross sr->arg.lock.lvec = lvec; 103*0897f7fbSGordon Ross sr->arg.lock.lcnt = LockCount; 104*0897f7fbSGordon Ross sr->arg.lock.lseq = LockSequence; 105*0897f7fbSGordon Ross if (lvec[0].Flags & SMB2_LOCKFLAG_UNLOCK) { 106*0897f7fbSGordon Ross status = smb2_unlock(sr); 107*0897f7fbSGordon Ross } else { 108*0897f7fbSGordon Ross status = smb2_locks(sr); 109a90cf9f2SGordon Ross } 110a90cf9f2SGordon Ross if (status) 111a90cf9f2SGordon Ross goto errout; 112a90cf9f2SGordon Ross 113a90cf9f2SGordon Ross /* 114a90cf9f2SGordon Ross * SMB2 Lock reply (sync) 115a90cf9f2SGordon Ross */ 116a90cf9f2SGordon Ross (void) smb_mbc_encodef( 117a90cf9f2SGordon Ross &sr->reply, "w..", 118*0897f7fbSGordon Ross 4); /* StructSize w */ 119a90cf9f2SGordon Ross /* reserved .. */ 120a90cf9f2SGordon Ross return (SDRC_SUCCESS); 121a90cf9f2SGordon Ross 122a90cf9f2SGordon Ross errout: 123a90cf9f2SGordon Ross smb2sr_put_error(sr, status); 124a90cf9f2SGordon Ross return (SDRC_SUCCESS); 125a90cf9f2SGordon Ross } 126a90cf9f2SGordon Ross 127*0897f7fbSGordon Ross /* 128*0897f7fbSGordon Ross * Process what should be an array of unlock requests. 129*0897f7fbSGordon Ross */ 130*0897f7fbSGordon Ross static uint32_t 131*0897f7fbSGordon Ross smb2_unlock(smb_request_t *sr) 132*0897f7fbSGordon Ross { 133*0897f7fbSGordon Ross lock_elem_t *lk; 134*0897f7fbSGordon Ross lock_elem_t *lvec = sr->arg.lock.lvec; 135*0897f7fbSGordon Ross uint32_t LockCount = sr->arg.lock.lcnt; 136*0897f7fbSGordon Ross uint32_t LockSequence = sr->arg.lock.lseq; 137*0897f7fbSGordon Ross uint32_t status = 0; 138*0897f7fbSGordon Ross uint32_t pid = 0; /* SMB2 ignores lock PIDs. */ 139*0897f7fbSGordon Ross int i; 140*0897f7fbSGordon Ross 141*0897f7fbSGordon Ross for (i = 0; i < LockCount; i++) { 142*0897f7fbSGordon Ross lk = &lvec[i]; 143*0897f7fbSGordon Ross 144*0897f7fbSGordon Ross if (lk->Flags != SMB2_LOCKFLAG_UNLOCK) { 145*0897f7fbSGordon Ross status = NT_STATUS_INVALID_PARAMETER; 146*0897f7fbSGordon Ross break; 147*0897f7fbSGordon Ross } 148*0897f7fbSGordon Ross 149*0897f7fbSGordon Ross status = smb_unlock_range(sr, lk->Offset, lk->Length, pid); 150*0897f7fbSGordon Ross if (status != 0) 151*0897f7fbSGordon Ross break; 152*0897f7fbSGordon Ross } 153*0897f7fbSGordon Ross (void) LockSequence; /* todo */ 154*0897f7fbSGordon Ross 155*0897f7fbSGordon Ross return (status); 156*0897f7fbSGordon Ross } 157*0897f7fbSGordon Ross 158*0897f7fbSGordon Ross /* 159*0897f7fbSGordon Ross * Process what should be an array of lock requests. 160*0897f7fbSGordon Ross */ 161*0897f7fbSGordon Ross static uint32_t 162*0897f7fbSGordon Ross smb2_locks(smb_request_t *sr) 163*0897f7fbSGordon Ross { 164*0897f7fbSGordon Ross lock_elem_t *lk; 165*0897f7fbSGordon Ross lock_elem_t *lvec = sr->arg.lock.lvec; 166*0897f7fbSGordon Ross uint32_t LockCount = sr->arg.lock.lcnt; 167*0897f7fbSGordon Ross uint32_t i; 168*0897f7fbSGordon Ross uint32_t ltype; 169*0897f7fbSGordon Ross uint32_t pid = 0; /* SMB2 ignores lock PIDs */ 170*0897f7fbSGordon Ross uint32_t timeout = 0; 171*0897f7fbSGordon Ross uint32_t status = 0; 172*0897f7fbSGordon Ross 173*0897f7fbSGordon Ross for (i = 0; i < LockCount; i++) { 174*0897f7fbSGordon Ross lk = &lvec[i]; 175*0897f7fbSGordon Ross 176*0897f7fbSGordon Ross switch (lk->Flags) { 177*0897f7fbSGordon Ross 178*0897f7fbSGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK: 179*0897f7fbSGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK: 180*0897f7fbSGordon Ross /* 181*0897f7fbSGordon Ross * Blocking locks have special rules: 182*0897f7fbSGordon Ross * Must be exactly one element, else 183*0897f7fbSGordon Ross * invalid parameter. 184*0897f7fbSGordon Ross */ 185*0897f7fbSGordon Ross if (i == 0 && LockCount == 1) { 186*0897f7fbSGordon Ross status = smb2sr_go_async(sr, smb2_lock_async); 187*0897f7fbSGordon Ross return (status); 188*0897f7fbSGordon Ross } 189*0897f7fbSGordon Ross /* FALLTHROUGH */ 190*0897f7fbSGordon Ross case SMB2_LOCKFLAG_UNLOCK: 191*0897f7fbSGordon Ross default: 192*0897f7fbSGordon Ross status = NT_STATUS_INVALID_PARAMETER; 193*0897f7fbSGordon Ross goto end_loop; 194*0897f7fbSGordon Ross 195*0897f7fbSGordon Ross /* BEGIN CSTYLED */ 196*0897f7fbSGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK | 197*0897f7fbSGordon Ross SMB2_LOCKFLAG_FAIL_IMMEDIATELY: 198*0897f7fbSGordon Ross /* END CSTYLED */ 199*0897f7fbSGordon Ross ltype = SMB_LOCK_TYPE_READONLY; 200*0897f7fbSGordon Ross break; 201*0897f7fbSGordon Ross 202*0897f7fbSGordon Ross /* BEGIN CSTYLED */ 203*0897f7fbSGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK | 204*0897f7fbSGordon Ross SMB2_LOCKFLAG_FAIL_IMMEDIATELY: 205*0897f7fbSGordon Ross /* END CSTYLED */ 206*0897f7fbSGordon Ross ltype = SMB_LOCK_TYPE_READWRITE; 207*0897f7fbSGordon Ross break; 208*0897f7fbSGordon Ross } 209*0897f7fbSGordon Ross 210*0897f7fbSGordon Ross status = smb_lock_range(sr, lk->Offset, lk->Length, pid, 211*0897f7fbSGordon Ross ltype, timeout); 212*0897f7fbSGordon Ross if (status != 0) { 213*0897f7fbSGordon Ross goto end_loop; 214*0897f7fbSGordon Ross } 215*0897f7fbSGordon Ross } 216*0897f7fbSGordon Ross 217*0897f7fbSGordon Ross end_loop: 218*0897f7fbSGordon Ross if (status != 0) { 219*0897f7fbSGordon Ross /* 220*0897f7fbSGordon Ross * Oh... we have to rollback. 221*0897f7fbSGordon Ross */ 222*0897f7fbSGordon Ross while (i > 0) { 223*0897f7fbSGordon Ross --i; 224*0897f7fbSGordon Ross lk = &lvec[i]; 225*0897f7fbSGordon Ross (void) smb_unlock_range(sr, 226*0897f7fbSGordon Ross lk->Offset, lk->Length, pid); 227*0897f7fbSGordon Ross } 228*0897f7fbSGordon Ross } 229*0897f7fbSGordon Ross 230*0897f7fbSGordon Ross return (status); 231*0897f7fbSGordon Ross } 232*0897f7fbSGordon Ross 233*0897f7fbSGordon Ross /* 234*0897f7fbSGordon Ross * Async handler for blocking lock requests. 235*0897f7fbSGordon Ross * Always exactly one lock request here. 236*0897f7fbSGordon Ross */ 237a90cf9f2SGordon Ross static smb_sdrc_t 238a90cf9f2SGordon Ross smb2_lock_async(smb_request_t *sr) 239a90cf9f2SGordon Ross { 240*0897f7fbSGordon Ross lock_elem_t *lk = sr->arg.lock.lvec; 241*0897f7fbSGordon Ross uint32_t LockCount = sr->arg.lock.lcnt; 242a90cf9f2SGordon Ross uint32_t status; 243*0897f7fbSGordon Ross uint32_t ltype; 244*0897f7fbSGordon Ross uint32_t pid = 0; /* SMB2 ignores lock PIDs */ 245*0897f7fbSGordon Ross uint32_t timeout = UINT_MAX; 246a90cf9f2SGordon Ross 247*0897f7fbSGordon Ross ASSERT(sr->fid_ofile->f_node != NULL); 248*0897f7fbSGordon Ross ASSERT(LockCount == 1); 249a90cf9f2SGordon Ross 250*0897f7fbSGordon Ross switch (lk->Flags) { 251*0897f7fbSGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK: 252*0897f7fbSGordon Ross ltype = SMB_LOCK_TYPE_READONLY; 253*0897f7fbSGordon Ross break; 254*0897f7fbSGordon Ross 255*0897f7fbSGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK: 256*0897f7fbSGordon Ross ltype = SMB_LOCK_TYPE_READWRITE; 257*0897f7fbSGordon Ross break; 258*0897f7fbSGordon Ross 259*0897f7fbSGordon Ross default: 260*0897f7fbSGordon Ross ASSERT(0); 261a90cf9f2SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 262a90cf9f2SGordon Ross goto errout; 263a90cf9f2SGordon Ross } 264a90cf9f2SGordon Ross 265*0897f7fbSGordon Ross status = smb_lock_range(sr, lk->Offset, lk->Length, pid, 266*0897f7fbSGordon Ross ltype, timeout); 267*0897f7fbSGordon Ross if (status != 0) 268a90cf9f2SGordon Ross goto errout; 269a90cf9f2SGordon Ross 270a90cf9f2SGordon Ross /* 271a90cf9f2SGordon Ross * SMB2 Lock reply (async) 272a90cf9f2SGordon Ross */ 273a90cf9f2SGordon Ross (void) smb_mbc_encodef( 274a90cf9f2SGordon Ross &sr->reply, "w..", 275*0897f7fbSGordon Ross 4); /* StructSize w */ 276a90cf9f2SGordon Ross /* reserved .. */ 277a90cf9f2SGordon Ross return (SDRC_SUCCESS); 278a90cf9f2SGordon Ross 279a90cf9f2SGordon Ross errout: 280a90cf9f2SGordon Ross smb2sr_put_error(sr, status); 281a90cf9f2SGordon Ross return (SDRC_SUCCESS); 282a90cf9f2SGordon Ross } 283