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 2014 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
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 smb_sdrc_t
216 smb_pre_locking_andx(smb_request_t *sr)
217 {
218 DTRACE_SMB_1(op__LockingX__start, smb_request_t *, sr);
219 return (SDRC_SUCCESS);
220 }
221
222 void
223 smb_post_locking_andx(smb_request_t *sr)
224 {
225 DTRACE_SMB_1(op__LockingX__done, smb_request_t *, sr);
226 }
227
228 smb_sdrc_t
229 smb_com_locking_andx(smb_request_t *sr)
230 {
231 unsigned short i;
232 unsigned char lock_type; /* See lock_type table above */
233 unsigned char oplock_level; /* The new oplock level */
234 uint32_t timeout; /* Milliseconds to wait for lock */
235 unsigned short unlock_num; /* # unlock range structs */
236 unsigned short lock_num; /* # lock range structs */
237 uint32_t save_pid; /* Process Id of owner */
238 uint32_t offset32, length32;
239 uint64_t offset64;
240 uint64_t length64;
241 DWORD result;
242 int rc;
243 uint32_t ltype;
244 smb_ofile_t *ofile;
245 uint16_t tmp_pid; /* locking uses 16-bit pids */
246 uint8_t brk;
247
248 rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type,
249 &oplock_level, &timeout, &unlock_num, &lock_num);
250 if (rc != 0)
251 return (SDRC_ERROR);
252
253 smbsr_lookup_file(sr);
254 if (sr->fid_ofile == NULL) {
255 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
256 return (SDRC_ERROR);
257 }
258 ofile = sr->fid_ofile;
259 if (ofile->f_node == NULL) {
260 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
261 ERRDOS, ERROR_INVALID_PARAMETER);
262 return (SDRC_ERROR);
263 }
264
265 if (lock_type & LOCKING_ANDX_SHARED_LOCK)
266 ltype = SMB_LOCK_TYPE_READONLY;
267 else
268 ltype = SMB_LOCK_TYPE_READWRITE;
269
270 save_pid = sr->smb_pid; /* Save the original pid */
271
272 if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
273 if (oplock_level == 0)
274 brk = SMB_OPLOCK_BREAK_TO_NONE;
275 else
276 brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
277 smb_oplock_ack(ofile->f_node, ofile, brk);
278 if (unlock_num == 0 && lock_num == 0)
279 return (SDRC_NO_REPLY);
280 }
281
282 /*
283 * No support for changing locktype (although we could probably
284 * implement this)
285 */
286 if (lock_type & LOCKING_ANDX_CHANGE_LOCK_TYPE) {
287 smbsr_error(sr, 0, ERRDOS,
288 ERROR_ATOMIC_LOCKS_NOT_SUPPORTED);
289 return (SDRC_ERROR);
290 }
291
292 /*
293 * No support for cancel lock (smbtorture expects this)
294 */
295 if (lock_type & LOCKING_ANDX_CANCEL_LOCK) {
296 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
297 ERRDOS, ERROR_INVALID_PARAMETER);
298 return (SDRC_ERROR);
299 }
300
301 if (lock_type & LOCKING_ANDX_LARGE_FILES) {
302 /*
303 * negotiated protocol should be NT LM 0.12 or later
304 */
305 if (sr->session->dialect < NT_LM_0_12) {
306 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
307 ERRDOS, ERROR_INVALID_PARAMETER);
308 return (SDRC_ERROR);
309 }
310
311 for (i = 0; i < unlock_num; i++) {
312 rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
313 &tmp_pid, &offset64, &length64);
314 if (rc) {
315 /*
316 * This is the error returned by Windows 2000
317 * even when STATUS32 has been negotiated.
318 */
319 smbsr_error(sr, 0, ERRSRV, ERRerror);
320 return (SDRC_ERROR);
321 }
322 sr->smb_pid = tmp_pid; /* NB: 16-bit */
323
324 result = smb_unlock_range(sr, sr->fid_ofile->f_node,
325 offset64, length64);
326 if (result != NT_STATUS_SUCCESS) {
327 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
328 ERRDOS, ERROR_NOT_LOCKED);
329 return (SDRC_ERROR);
330 }
331 }
332
333 for (i = 0; i < lock_num; i++) {
334 rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
335 &tmp_pid, &offset64, &length64);
336 if (rc) {
337 smbsr_error(sr, 0, ERRSRV, ERRerror);
338 return (SDRC_ERROR);
339 }
340 sr->smb_pid = tmp_pid; /* NB: 16-bit */
341
342 result = smb_lock_range(sr, offset64, length64, timeout,
343 ltype);
344 if (result != NT_STATUS_SUCCESS) {
345 smb_lock_range_error(sr, result);
346 return (SDRC_ERROR);
347 }
348 }
349 } else {
350 for (i = 0; i < unlock_num; i++) {
351 rc = smb_mbc_decodef(&sr->smb_data, "wll", &tmp_pid,
352 &offset32, &length32);
353 if (rc) {
354 smbsr_error(sr, 0, ERRSRV, ERRerror);
355 return (SDRC_ERROR);
356 }
357 sr->smb_pid = tmp_pid; /* NB: 16-bit */
358
359 result = smb_unlock_range(sr, sr->fid_ofile->f_node,
360 (uint64_t)offset32, (uint64_t)length32);
361 if (result != NT_STATUS_SUCCESS) {
362 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
363 ERRDOS, ERROR_NOT_LOCKED);
364 return (SDRC_ERROR);
365 }
366 }
367
368 for (i = 0; i < lock_num; i++) {
369 rc = smb_mbc_decodef(&sr->smb_data, "wll", &tmp_pid,
370 &offset32, &length32);
371 if (rc) {
372 smbsr_error(sr, 0, ERRSRV, ERRerror);
373 return (SDRC_ERROR);
374 }
375 sr->smb_pid = tmp_pid; /* NB: 16-bit */
376
377 result = smb_lock_range(sr, (uint64_t)offset32,
378 (uint64_t)length32, timeout, ltype);
379 if (result != NT_STATUS_SUCCESS) {
380 smb_lock_range_error(sr, result);
381 return (SDRC_ERROR);
382 }
383 }
384 }
385
386 sr->smb_pid = save_pid;
387 if (smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, 7, 0))
388 return (SDRC_ERROR);
389 return (SDRC_SUCCESS);
390 }
391
392 /*
393 * Compose an SMB1 Oplock Break Notification packet, including
394 * the SMB1 header and everything, in sr->reply.
395 * The caller will send it and free the request.
396 */
397 void
398 smb1_oplock_break_notification(smb_request_t *sr, uint8_t brk)
399 {
400 smb_ofile_t *ofile = sr->fid_ofile;
401 uint16_t fid;
402 uint8_t lock_type;
403 uint8_t oplock_level;
404
405 switch (brk) {
406 default:
407 ASSERT(0);
408 /* FALLTHROUGH */
409 case SMB_OPLOCK_BREAK_TO_NONE:
410 oplock_level = 0;
411 break;
412 case SMB_OPLOCK_BREAK_TO_LEVEL_II:
413 oplock_level = 1;
414 break;
415 }
416
417 sr->smb_com = SMB_COM_LOCKING_ANDX;
418 sr->smb_tid = ofile->f_tree->t_tid;
419 sr->smb_pid = 0xFFFF;
420 sr->smb_uid = 0;
421 sr->smb_mid = 0xFFFF;
422 fid = ofile->f_fid;
423 lock_type = LOCKING_ANDX_OPLOCK_RELEASE;
424
425 (void) smb_mbc_encodef(
426 &sr->reply, "Mb19.wwwwbb3.wbb10.",
427 /* "\xffSMB" M */
428 sr->smb_com, /* b */
429 /* status, flags, signature 19. */
430 sr->smb_tid, /* w */
431 sr->smb_pid, /* w */
432 sr->smb_uid, /* w */
|
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
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 _x;
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 */
|