1*a90cf9f2SGordon Ross /*
2*a90cf9f2SGordon Ross * This file and its contents are supplied under the terms of the
3*a90cf9f2SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0.
4*a90cf9f2SGordon Ross * You may only use this file in accordance with the terms of version
5*a90cf9f2SGordon Ross * 1.0 of the CDDL.
6*a90cf9f2SGordon Ross *
7*a90cf9f2SGordon Ross * A full copy of the text of the CDDL should have accompanied this
8*a90cf9f2SGordon Ross * source. A copy of the CDDL is also available via the Internet at
9*a90cf9f2SGordon Ross * http://www.illumos.org/license/CDDL.
10*a90cf9f2SGordon Ross */
11*a90cf9f2SGordon Ross
12*a90cf9f2SGordon Ross /*
13*a90cf9f2SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
14*a90cf9f2SGordon Ross */
15*a90cf9f2SGordon Ross
16*a90cf9f2SGordon Ross /*
17*a90cf9f2SGordon Ross * Dispatch function for SMB2_LOCK
18*a90cf9f2SGordon Ross */
19*a90cf9f2SGordon Ross
20*a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
21*a90cf9f2SGordon Ross
22*a90cf9f2SGordon Ross struct SMB2_LOCK_ELEMENT {
23*a90cf9f2SGordon Ross uint64_t Offset;
24*a90cf9f2SGordon Ross uint64_t Length;
25*a90cf9f2SGordon Ross uint32_t Flags;
26*a90cf9f2SGordon Ross uint32_t reserved;
27*a90cf9f2SGordon Ross };
28*a90cf9f2SGordon Ross
29*a90cf9f2SGordon Ross static smb_sdrc_t smb2_lock_async(smb_request_t *);
30*a90cf9f2SGordon Ross static uint32_t smb2_lock_exec(smb_request_t *, uint16_t);
31*a90cf9f2SGordon Ross static uint32_t smb2_lock_elem(smb_request_t *, struct SMB2_LOCK_ELEMENT *);
32*a90cf9f2SGordon Ross
33*a90cf9f2SGordon Ross /*
34*a90cf9f2SGordon Ross * This is a somewhat arbitrary sanity limit on the length of the
35*a90cf9f2SGordon Ross * SMB2_LOCK_ELEMENT array. It usually has length one or two.
36*a90cf9f2SGordon Ross */
37*a90cf9f2SGordon Ross int smb2_lock_max_elem = 1024;
38*a90cf9f2SGordon Ross
39*a90cf9f2SGordon Ross smb_sdrc_t
smb2_lock(smb_request_t * sr)40*a90cf9f2SGordon Ross smb2_lock(smb_request_t *sr)
41*a90cf9f2SGordon Ross {
42*a90cf9f2SGordon Ross struct SMB2_LOCK_ELEMENT elem;
43*a90cf9f2SGordon Ross smb2fid_t smb2fid;
44*a90cf9f2SGordon Ross uint32_t save_offset;
45*a90cf9f2SGordon Ross uint32_t LockSequence;
46*a90cf9f2SGordon Ross uint32_t status;
47*a90cf9f2SGordon Ross uint16_t StructSize;
48*a90cf9f2SGordon Ross uint16_t LockCount;
49*a90cf9f2SGordon Ross uint16_t i;
50*a90cf9f2SGordon Ross boolean_t MayBlock = B_FALSE;
51*a90cf9f2SGordon Ross int rc = 0;
52*a90cf9f2SGordon Ross
53*a90cf9f2SGordon Ross /*
54*a90cf9f2SGordon Ross * SMB2 Lock request
55*a90cf9f2SGordon Ross */
56*a90cf9f2SGordon Ross rc = smb_mbc_decodef(
57*a90cf9f2SGordon Ross &sr->smb_data, "wwlqq",
58*a90cf9f2SGordon Ross &StructSize, /* w */
59*a90cf9f2SGordon Ross &LockCount, /* w */
60*a90cf9f2SGordon Ross &LockSequence, /* l */
61*a90cf9f2SGordon Ross &smb2fid.persistent, /* q */
62*a90cf9f2SGordon Ross &smb2fid.temporal); /* q */
63*a90cf9f2SGordon Ross if (rc || StructSize != 48)
64*a90cf9f2SGordon Ross return (SDRC_ERROR);
65*a90cf9f2SGordon Ross
66*a90cf9f2SGordon Ross status = smb2sr_lookup_fid(sr, &smb2fid);
67*a90cf9f2SGordon Ross if (status)
68*a90cf9f2SGordon Ross goto errout;
69*a90cf9f2SGordon Ross if (sr->fid_ofile->f_node == NULL || LockCount == 0) {
70*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER;
71*a90cf9f2SGordon Ross goto errout;
72*a90cf9f2SGordon Ross }
73*a90cf9f2SGordon Ross if (LockCount > smb2_lock_max_elem) {
74*a90cf9f2SGordon Ross status = NT_STATUS_INSUFFICIENT_RESOURCES;
75*a90cf9f2SGordon Ross goto errout;
76*a90cf9f2SGordon Ross }
77*a90cf9f2SGordon Ross
78*a90cf9f2SGordon Ross /*
79*a90cf9f2SGordon Ross * Process the array of SMB2_LOCK_ELEMENT structs
80*a90cf9f2SGordon Ross * We do this twice. (it's always a short list)
81*a90cf9f2SGordon Ross * The first time, just validate the flags, and check
82*a90cf9f2SGordon Ross * if any of the locking request might need to block.
83*a90cf9f2SGordon Ross * The second time (either here, or in the async
84*a90cf9f2SGordon Ross * handler function) process the locks for real.
85*a90cf9f2SGordon Ross */
86*a90cf9f2SGordon Ross save_offset = sr->smb_data.chain_offset;
87*a90cf9f2SGordon Ross for (i = 0; i < LockCount; i++) {
88*a90cf9f2SGordon Ross rc = smb_mbc_decodef(
89*a90cf9f2SGordon Ross &sr->smb_data, "qqll",
90*a90cf9f2SGordon Ross &elem.Offset, /* q */
91*a90cf9f2SGordon Ross &elem.Length, /* q */
92*a90cf9f2SGordon Ross &elem.Flags, /* l */
93*a90cf9f2SGordon Ross &elem.reserved); /* l */
94*a90cf9f2SGordon Ross if (rc) {
95*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER;
96*a90cf9f2SGordon Ross goto errout;
97*a90cf9f2SGordon Ross }
98*a90cf9f2SGordon Ross
99*a90cf9f2SGordon Ross /*
100*a90cf9f2SGordon Ross * Make sure the flags are valid;
101*a90cf9f2SGordon Ross * Find out if we might block.
102*a90cf9f2SGordon Ross */
103*a90cf9f2SGordon Ross switch (elem.Flags) {
104*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK:
105*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK:
106*a90cf9f2SGordon Ross MayBlock = B_TRUE;
107*a90cf9f2SGordon Ross break;
108*a90cf9f2SGordon Ross
109*a90cf9f2SGordon Ross /* BEGIN CSTYLED */
110*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK |
111*a90cf9f2SGordon Ross SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
112*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK |
113*a90cf9f2SGordon Ross SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
114*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_UNLOCK:
115*a90cf9f2SGordon Ross /* END CSTYLED */
116*a90cf9f2SGordon Ross break;
117*a90cf9f2SGordon Ross
118*a90cf9f2SGordon Ross default:
119*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER;
120*a90cf9f2SGordon Ross goto errout;
121*a90cf9f2SGordon Ross }
122*a90cf9f2SGordon Ross }
123*a90cf9f2SGordon Ross
124*a90cf9f2SGordon Ross if (MayBlock) {
125*a90cf9f2SGordon Ross /*
126*a90cf9f2SGordon Ross * May need to block. "Go async".
127*a90cf9f2SGordon Ross */
128*a90cf9f2SGordon Ross status = smb2sr_go_async(sr, smb2_lock_async);
129*a90cf9f2SGordon Ross goto errout;
130*a90cf9f2SGordon Ross }
131*a90cf9f2SGordon Ross
132*a90cf9f2SGordon Ross sr->smb_data.chain_offset = save_offset;
133*a90cf9f2SGordon Ross status = smb2_lock_exec(sr, LockCount);
134*a90cf9f2SGordon Ross if (status)
135*a90cf9f2SGordon Ross goto errout;
136*a90cf9f2SGordon Ross
137*a90cf9f2SGordon Ross /*
138*a90cf9f2SGordon Ross * SMB2 Lock reply (sync)
139*a90cf9f2SGordon Ross */
140*a90cf9f2SGordon Ross StructSize = 4;
141*a90cf9f2SGordon Ross (void) smb_mbc_encodef(
142*a90cf9f2SGordon Ross &sr->reply, "w..",
143*a90cf9f2SGordon Ross StructSize); /* w */
144*a90cf9f2SGordon Ross /* reserved .. */
145*a90cf9f2SGordon Ross return (SDRC_SUCCESS);
146*a90cf9f2SGordon Ross
147*a90cf9f2SGordon Ross errout:
148*a90cf9f2SGordon Ross smb2sr_put_error(sr, status);
149*a90cf9f2SGordon Ross return (SDRC_SUCCESS);
150*a90cf9f2SGordon Ross }
151*a90cf9f2SGordon Ross
152*a90cf9f2SGordon Ross static smb_sdrc_t
smb2_lock_async(smb_request_t * sr)153*a90cf9f2SGordon Ross smb2_lock_async(smb_request_t *sr)
154*a90cf9f2SGordon Ross {
155*a90cf9f2SGordon Ross smb2fid_t smb2fid;
156*a90cf9f2SGordon Ross uint32_t LockSequence;
157*a90cf9f2SGordon Ross uint32_t status;
158*a90cf9f2SGordon Ross uint16_t StructSize;
159*a90cf9f2SGordon Ross uint16_t LockCount;
160*a90cf9f2SGordon Ross int rc = 0;
161*a90cf9f2SGordon Ross
162*a90cf9f2SGordon Ross /*
163*a90cf9f2SGordon Ross * Decode the lock request again. It should all decode
164*a90cf9f2SGordon Ross * exactly the same as the first time we saw it. If not,
165*a90cf9f2SGordon Ross * report an "internal error".
166*a90cf9f2SGordon Ross */
167*a90cf9f2SGordon Ross rc = smb_mbc_decodef(
168*a90cf9f2SGordon Ross &sr->smb_data, "wwlqq",
169*a90cf9f2SGordon Ross &StructSize, /* w */
170*a90cf9f2SGordon Ross &LockCount, /* w */
171*a90cf9f2SGordon Ross &LockSequence, /* l */
172*a90cf9f2SGordon Ross &smb2fid.persistent, /* q */
173*a90cf9f2SGordon Ross &smb2fid.temporal); /* q */
174*a90cf9f2SGordon Ross if (rc || StructSize != 48)
175*a90cf9f2SGordon Ross return (SDRC_ERROR);
176*a90cf9f2SGordon Ross
177*a90cf9f2SGordon Ross status = smb2sr_lookup_fid(sr, &smb2fid);
178*a90cf9f2SGordon Ross if (status)
179*a90cf9f2SGordon Ross goto errout;
180*a90cf9f2SGordon Ross if (sr->fid_ofile->f_node == NULL || LockCount == 0) {
181*a90cf9f2SGordon Ross status = NT_STATUS_INTERNAL_ERROR;
182*a90cf9f2SGordon Ross goto errout;
183*a90cf9f2SGordon Ross }
184*a90cf9f2SGordon Ross
185*a90cf9f2SGordon Ross status = smb2_lock_exec(sr, LockCount);
186*a90cf9f2SGordon Ross if (status)
187*a90cf9f2SGordon Ross goto errout;
188*a90cf9f2SGordon Ross
189*a90cf9f2SGordon Ross /*
190*a90cf9f2SGordon Ross * SMB2 Lock reply (async)
191*a90cf9f2SGordon Ross */
192*a90cf9f2SGordon Ross StructSize = 4;
193*a90cf9f2SGordon Ross (void) smb_mbc_encodef(
194*a90cf9f2SGordon Ross &sr->reply, "w..",
195*a90cf9f2SGordon Ross StructSize); /* w */
196*a90cf9f2SGordon Ross /* reserved .. */
197*a90cf9f2SGordon Ross return (SDRC_SUCCESS);
198*a90cf9f2SGordon Ross
199*a90cf9f2SGordon Ross errout:
200*a90cf9f2SGordon Ross smb2sr_put_error(sr, status);
201*a90cf9f2SGordon Ross return (SDRC_SUCCESS);
202*a90cf9f2SGordon Ross }
203*a90cf9f2SGordon Ross
204*a90cf9f2SGordon Ross /*
205*a90cf9f2SGordon Ross * Execute the vector of locks. This is the common function called by
206*a90cf9f2SGordon Ross * either the sync or async code paths. We've already decoded this
207*a90cf9f2SGordon Ross * request once when we get here, so if there are any decode errors
208*a90cf9f2SGordon Ross * then it's some kind of internal error.
209*a90cf9f2SGordon Ross */
210*a90cf9f2SGordon Ross static uint32_t
smb2_lock_exec(smb_request_t * sr,uint16_t LockCount)211*a90cf9f2SGordon Ross smb2_lock_exec(smb_request_t *sr, uint16_t LockCount)
212*a90cf9f2SGordon Ross {
213*a90cf9f2SGordon Ross struct SMB2_LOCK_ELEMENT elem;
214*a90cf9f2SGordon Ross uint32_t status = 0;
215*a90cf9f2SGordon Ross uint16_t i;
216*a90cf9f2SGordon Ross int rc;
217*a90cf9f2SGordon Ross
218*a90cf9f2SGordon Ross /*
219*a90cf9f2SGordon Ross * On entry, out position in the input data should be
220*a90cf9f2SGordon Ross * after both the SMB2 header and the fixed part of
221*a90cf9f2SGordon Ross * the SMB Lock request header (24).
222*a90cf9f2SGordon Ross */
223*a90cf9f2SGordon Ross ASSERT(sr->smb_data.chain_offset ==
224*a90cf9f2SGordon Ross (sr->smb2_cmd_hdr + SMB2_HDR_SIZE + 24));
225*a90cf9f2SGordon Ross
226*a90cf9f2SGordon Ross /*
227*a90cf9f2SGordon Ross * This is checked by our callers, but let's make sure.
228*a90cf9f2SGordon Ross */
229*a90cf9f2SGordon Ross ASSERT(sr->fid_ofile->f_node != NULL);
230*a90cf9f2SGordon Ross
231*a90cf9f2SGordon Ross for (i = 0; i < LockCount; i++) {
232*a90cf9f2SGordon Ross rc = smb_mbc_decodef(
233*a90cf9f2SGordon Ross &sr->smb_data, "qqll",
234*a90cf9f2SGordon Ross &elem.Offset, /* q */
235*a90cf9f2SGordon Ross &elem.Length, /* q */
236*a90cf9f2SGordon Ross &elem.Flags, /* l */
237*a90cf9f2SGordon Ross &elem.reserved); /* l */
238*a90cf9f2SGordon Ross if (rc) {
239*a90cf9f2SGordon Ross status = NT_STATUS_INTERNAL_ERROR;
240*a90cf9f2SGordon Ross break;
241*a90cf9f2SGordon Ross }
242*a90cf9f2SGordon Ross status = smb2_lock_elem(sr, &elem);
243*a90cf9f2SGordon Ross if (status)
244*a90cf9f2SGordon Ross break;
245*a90cf9f2SGordon Ross }
246*a90cf9f2SGordon Ross return (status);
247*a90cf9f2SGordon Ross }
248*a90cf9f2SGordon Ross
249*a90cf9f2SGordon Ross static uint32_t
smb2_lock_elem(smb_request_t * sr,struct SMB2_LOCK_ELEMENT * elem)250*a90cf9f2SGordon Ross smb2_lock_elem(smb_request_t *sr, struct SMB2_LOCK_ELEMENT *elem)
251*a90cf9f2SGordon Ross {
252*a90cf9f2SGordon Ross smb_node_t *node = sr->fid_ofile->f_node;
253*a90cf9f2SGordon Ross uint32_t status;
254*a90cf9f2SGordon Ross uint32_t ltype;
255*a90cf9f2SGordon Ross uint32_t timeout = 0;
256*a90cf9f2SGordon Ross
257*a90cf9f2SGordon Ross switch (elem->Flags) {
258*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK:
259*a90cf9f2SGordon Ross timeout = UINT_MAX;
260*a90cf9f2SGordon Ross /* FALLTHROUGH */
261*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
262*a90cf9f2SGordon Ross ltype = SMB_LOCK_TYPE_READONLY;
263*a90cf9f2SGordon Ross status = smb_lock_range(sr,
264*a90cf9f2SGordon Ross elem->Offset, elem->Length,
265*a90cf9f2SGordon Ross timeout, ltype);
266*a90cf9f2SGordon Ross break;
267*a90cf9f2SGordon Ross
268*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK:
269*a90cf9f2SGordon Ross timeout = UINT_MAX;
270*a90cf9f2SGordon Ross /* FALLTHROUGH */
271*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
272*a90cf9f2SGordon Ross ltype = SMB_LOCK_TYPE_READWRITE;
273*a90cf9f2SGordon Ross status = smb_lock_range(sr,
274*a90cf9f2SGordon Ross elem->Offset, elem->Length,
275*a90cf9f2SGordon Ross timeout, ltype);
276*a90cf9f2SGordon Ross break;
277*a90cf9f2SGordon Ross
278*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_UNLOCK:
279*a90cf9f2SGordon Ross status = smb_unlock_range(sr, node,
280*a90cf9f2SGordon Ross elem->Offset, elem->Length);
281*a90cf9f2SGordon Ross break;
282*a90cf9f2SGordon Ross
283*a90cf9f2SGordon Ross /*
284*a90cf9f2SGordon Ross * We've already checked the flags previously, so any
285*a90cf9f2SGordon Ross * surprises here are some kind of internal error.
286*a90cf9f2SGordon Ross */
287*a90cf9f2SGordon Ross default:
288*a90cf9f2SGordon Ross status = NT_STATUS_INTERNAL_ERROR;
289*a90cf9f2SGordon Ross break;
290*a90cf9f2SGordon Ross }
291*a90cf9f2SGordon Ross
292*a90cf9f2SGordon Ross return (status);
293*a90cf9f2SGordon Ross }
294