1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
14 * Copyright 2022 RackTop Systems, Inc.
15 */
16
17 /*
18 * Dispatch function for SMB2_OPLOCK_BREAK
19 */
20
21 #include <smbsrv/smb2_kproto.h>
22 #include <smbsrv/smb_oplock.h>
23
24 #define BATCH_OR_EXCL (OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE)
25
26 /* StructSize for the two "break" message formats. */
27 #define SSZ_OPLOCK 24
28 #define SSZ_LEASE 36
29
30 /*
31 * SMB2 Oplock Break Acknowledgement
32 * [MS-SMB2] 3.3.5.22.1 Processing an Oplock Acknowledgment
33 * Called via smb2_disp_table[]
34 * This is an "Ack" from the client.
35 */
36 smb_sdrc_t
smb2_oplock_break_ack(smb_request_t * sr)37 smb2_oplock_break_ack(smb_request_t *sr)
38 {
39 smb_arg_olbrk_t *olbrk = &sr->arg.olbrk;
40 smb_node_t *node;
41 smb_ofile_t *ofile;
42 smb_oplock_grant_t *og;
43 smb2fid_t smb2fid;
44 uint32_t status;
45 uint32_t NewLevel;
46 uint8_t smbOplockLevel;
47 int rc = 0;
48 uint16_t StructSize;
49
50 /*
51 * Decode the SMB2 Oplock Break Ack (24 bytes) or
52 * Lease Break Ack (36 bytes), starting with just
53 * the StructSize, which tells us what this is.
54 */
55 rc = smb_mbc_decodef(&sr->smb_data, "w", &StructSize);
56 if (rc != 0)
57 return (SDRC_ERROR);
58
59 if (StructSize == SSZ_LEASE) {
60 /* See smb2_lease.c */
61 return (smb2_lease_break_ack(sr));
62 }
63 if (StructSize != SSZ_OPLOCK)
64 return (SDRC_ERROR);
65
66 /*
67 * Decode an SMB2 Oplock Break Ack.
68 * [MS-SMB2] 2.2.24.1
69 * Note: Struct size decoded above.
70 */
71 rc = smb_mbc_decodef(
72 &sr->smb_data, "b5.qq",
73 &smbOplockLevel, /* b */
74 /* reserved 5. */
75 &smb2fid.persistent, /* q */
76 &smb2fid.temporal); /* q */
77 if (rc != 0)
78 return (SDRC_ERROR);
79
80 /*
81 * Convert SMB oplock level to internal form.
82 */
83 switch (smbOplockLevel) {
84 case SMB2_OPLOCK_LEVEL_NONE: /* 0x00 */
85 NewLevel = OPLOCK_LEVEL_NONE;
86 break;
87 case SMB2_OPLOCK_LEVEL_II: /* 0x01 */
88 NewLevel = OPLOCK_LEVEL_TWO;
89 break;
90 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* 0x08 */
91 NewLevel = OPLOCK_LEVEL_ONE;
92 break;
93 case SMB2_OPLOCK_LEVEL_BATCH: /* 0x09 */
94 NewLevel = OPLOCK_LEVEL_BATCH;
95 break;
96
97 /* Note: _LEVEL_LEASE is not valid here. */
98 case SMB2_OPLOCK_LEVEL_LEASE: /* 0xFF */
99 default:
100 /*
101 * Impossible NewLevel here, will cause
102 * NT_STATUS_INVALID_PARAMETER below.
103 */
104 NewLevel = OPLOCK_LEVEL_GRANULAR;
105 break;
106 }
107
108 /* for dtrace */
109 olbrk->NewLevel = NewLevel;
110
111 /* Find the ofile */
112 status = smb2sr_lookup_fid(sr, &smb2fid);
113 /* Success or NT_STATUS_FILE_CLOSED */
114
115 DTRACE_SMB2_START(op__OplockBreak, smb_request_t *, sr);
116
117 if (status != 0) {
118 /* lookup fid failed */
119 goto errout;
120 }
121
122 if (NewLevel == OPLOCK_LEVEL_GRANULAR) {
123 /* Switch above got invalid smbOplockLevel */
124 status = NT_STATUS_INVALID_PARAMETER;
125 goto errout;
126 }
127
128 /* Success, so have sr->fid_ofile */
129 ofile = sr->fid_ofile;
130 og = &ofile->f_oplock;
131 node = ofile->f_node;
132
133 smb_llist_enter(&node->n_ofile_list, RW_READER);
134 mutex_enter(&node->n_oplock.ol_mutex);
135
136 if (og->og_breaking == B_FALSE) {
137 /*
138 * This is an unsolicited Ack. (There is no
139 * outstanding oplock break in progress now.)
140 * There are WPTS tests that care which error
141 * is returned. See [MS-SMB2] 3.3.5.22.1
142 */
143 if (NewLevel >= (og->og_state & OPLOCK_LEVEL_TYPE_MASK)) {
144 status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
145 goto unlock_out;
146 }
147 status = NT_STATUS_INVALID_DEVICE_STATE;
148 goto unlock_out;
149 }
150
151 /*
152 * Process the oplock break ack.
153 *
154 * Clear breaking flags before we ack,
155 * because ack might set those.
156 */
157 ofile->f_oplock.og_breaking = B_FALSE;
158 cv_broadcast(&ofile->f_oplock.og_ack_cv);
159
160 status = smb_oplock_ack_break(sr, ofile, &NewLevel);
161
162 ofile->f_oplock.og_state = NewLevel;
163 if (ofile->dh_persist)
164 smb2_dh_update_oplock(sr, ofile);
165
166 unlock_out:
167 mutex_exit(&node->n_oplock.ol_mutex);
168 smb_llist_exit(&node->n_ofile_list);
169
170 errout:
171 sr->smb2_status = status;
172 DTRACE_SMB2_DONE(op__OplockBreak, smb_request_t *, sr);
173 if (status) {
174 smb2sr_put_error(sr, status);
175 return (SDRC_SUCCESS);
176 }
177
178 /*
179 * Convert internal oplock state back to SMB form.
180 */
181 switch (NewLevel & OPLOCK_LEVEL_TYPE_MASK) {
182 case OPLOCK_LEVEL_NONE:
183 smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
184 break;
185 case OPLOCK_LEVEL_TWO:
186 smbOplockLevel = SMB2_OPLOCK_LEVEL_II;
187 break;
188 case OPLOCK_LEVEL_ONE:
189 smbOplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
190 break;
191 case OPLOCK_LEVEL_BATCH:
192 smbOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
193 break;
194 case OPLOCK_LEVEL_GRANULAR:
195 default:
196 smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
197 break;
198 }
199
200 /*
201 * Encode an SMB2 Oplock Break Ack response
202 * [MS-SMB2] 2.2.25.1
203 */
204 (void) smb_mbc_encodef(
205 &sr->reply, "wb5.qq",
206 SSZ_OPLOCK, /* w */
207 smbOplockLevel, /* b */
208 /* reserved 5. */
209 smb2fid.persistent, /* q */
210 smb2fid.temporal); /* q */
211
212 return (SDRC_SUCCESS);
213 }
214
215 /*
216 * Compose an SMB2 Oplock Break Notification packet, including
217 * the SMB2 header and everything, in sr->reply.
218 * The caller will send it and free the request.
219 */
220 static void
smb2_oplock_break_notification(smb_request_t * sr,uint32_t NewLevel)221 smb2_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel)
222 {
223 smb_ofile_t *ofile = sr->fid_ofile;
224 smb2fid_t smb2fid;
225 uint16_t StructSize;
226 uint8_t OplockLevel;
227
228 /*
229 * Convert internal level to SMB2
230 */
231 switch (NewLevel) {
232 default:
233 ASSERT(0);
234 /* FALLTHROUGH */
235 case OPLOCK_LEVEL_NONE:
236 OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
237 break;
238 case OPLOCK_LEVEL_TWO:
239 OplockLevel = SMB2_OPLOCK_LEVEL_II;
240 break;
241 }
242
243 /*
244 * SMB2 Header
245 */
246 sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
247 sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
248 sr->smb_tid = 0;
249 sr->smb_pid = 0;
250 sr->smb2_ssnid = 0;
251 sr->smb2_messageid = UINT64_MAX;
252 (void) smb2_encode_header(sr, B_FALSE);
253
254 /*
255 * SMB2 Oplock Break, variable part
256 */
257 StructSize = 24;
258 smb2fid.persistent = ofile->f_persistid;
259 smb2fid.temporal = ofile->f_fid;
260 (void) smb_mbc_encodef(
261 &sr->reply, "wb5.qq",
262 StructSize, /* w */
263 OplockLevel, /* b */
264 /* reserved 5. */
265 smb2fid.persistent, /* q */
266 smb2fid.temporal); /* q */
267 }
268
269 /*
270 * Send an oplock break over the wire, or if we can't,
271 * then process the oplock break locally.
272 *
273 * [MS-SMB2] 3.3.4.6 Object Store Indicates an Oplock Break
274 *
275 * Note: When "AckRequired" is set, and we're for any reason
276 * unable to communicate with the client so that they do an
277 * "oplock break ACK", then we absolutely MUST do a local ACK
278 * for this break indication (or close the ofile).
279 *
280 * The file-system level oplock code (smb_cmn_oplock.c)
281 * requires these ACK calls to clear "breaking" flags.
282 *
283 * This is called either from smb_oplock_async_break via a
284 * taskq job scheduled in smb_oplock_ind_break, or from the
285 * smb2sr_append_postwork() mechanism when we're doing a
286 * "break in ack", via smb_oplock_ind_break_in_ack.
287 *
288 * This runs much like other smb_request_t handlers, in the
289 * context of a worker task that calls with no locks held.
290 *
291 * Note that we have sr->fid_ofile here but all the other
292 * normal sr members may be NULL: uid_user, tid_tree.
293 * Also sr->session may or may not be the same session as
294 * the ofile came from (ofile->f_session) depending on
295 * whether this is a "live" open or an orphaned DH,
296 * where ofile->f_session will be NULL.
297 */
298 void
smb2_oplock_send_break(smb_request_t * sr)299 smb2_oplock_send_break(smb_request_t *sr)
300 {
301 smb_ofile_t *ofile = sr->fid_ofile;
302 smb_node_t *node = ofile->f_node;
303 uint32_t NewLevel = sr->arg.olbrk.NewLevel;
304 boolean_t AckReq = sr->arg.olbrk.AckRequired;
305 uint32_t status;
306 int rc;
307
308 /*
309 * Build the break message in sr->reply.
310 * It's free'd in smb_request_free().
311 * Always SMB2 oplock here (no lease)
312 */
313 sr->reply.max_bytes = MLEN;
314 smb2_oplock_break_notification(sr, NewLevel);
315
316 /*
317 * Try to send the break message to the client.
318 * If connected, this IF body will be true.
319 */
320 if (sr->session == ofile->f_session)
321 rc = smb_session_send(sr->session, 0, &sr->reply);
322 else
323 rc = ENOTCONN;
324
325 if (rc != 0) {
326 /*
327 * We were unable to send the oplock break request,
328 * presumably because the connection is gone.
329 *
330 * [MS-SMB2] 3.3.4.6 Object Store Indicates an Oplock Break
331 * If no connection is available, Open.IsResilient is FALSE,
332 * Open.IsDurable is FALSE, and Open.IsPersistent is FALSE,
333 * the server SHOULD close the Open as specified in...
334 */
335 if (ofile->dh_persist == B_FALSE &&
336 ofile->dh_vers != SMB2_RESILIENT &&
337 (ofile->dh_vers == SMB2_NOT_DURABLE ||
338 (NewLevel & OPLOCK_LEVEL_BATCH) == 0)) {
339 smb_ofile_close(ofile, 0);
340 return;
341 }
342 /* Keep this (durable) open. */
343 if (!AckReq)
344 return;
345 /* Do local Ack below. */
346 } else {
347 /*
348 * OK, we were able to send the break message.
349 * If no ack. required, we're done.
350 */
351 if (!AckReq)
352 return;
353
354 /*
355 * We're expecting an ACK. Wait in this thread
356 * so we can log clients that don't respond.
357 * Note: this can also fail for other reasons
358 * such as client disconnect or server shutdown.
359 */
360 status = smb_oplock_wait_ack(sr, NewLevel);
361 if (status == 0)
362 return;
363
364 DTRACE_PROBE2(wait__ack__failed, smb_request_t *, sr,
365 uint32_t, status);
366
367 /*
368 * Will do local ack below. Note, after timeout,
369 * do a break to none or "no caching" regardless
370 * of what the passed in cache level was.
371 */
372 NewLevel = OPLOCK_LEVEL_NONE;
373 }
374
375 /*
376 * Do the ack locally.
377 */
378 smb_llist_enter(&node->n_ofile_list, RW_READER);
379 mutex_enter(&node->n_oplock.ol_mutex);
380
381 ofile->f_oplock.og_breaking = B_FALSE;
382 cv_broadcast(&ofile->f_oplock.og_ack_cv);
383
384 status = smb_oplock_ack_break(sr, ofile, &NewLevel);
385
386 ofile->f_oplock.og_state = NewLevel;
387 if (ofile->dh_persist)
388 smb2_dh_update_oplock(sr, ofile);
389
390 mutex_exit(&node->n_oplock.ol_mutex);
391 smb_llist_exit(&node->n_ofile_list);
392
393 #ifdef DEBUG
394 if (status != 0) {
395 cmn_err(CE_NOTE, "clnt %s local oplock ack, status=0x%x",
396 sr->session->ip_addr_str, status);
397 }
398 #endif
399 }
400
401 /*
402 * Client has an open handle and requests an oplock.
403 * Convert SMB2 oplock request info in to internal form,
404 * call common oplock code, convert result to SMB2.
405 *
406 * If necessary, "go async" here.
407 */
408 void
smb2_oplock_acquire(smb_request_t * sr)409 smb2_oplock_acquire(smb_request_t *sr)
410 {
411 smb_arg_open_t *op = &sr->arg.open;
412 smb_ofile_t *ofile = sr->fid_ofile;
413 uint32_t status;
414
415 /* Only disk trees get oplocks. */
416 ASSERT((sr->tid_tree->t_res_type & STYPE_MASK) == STYPE_DISKTREE);
417
418 /* Only plain files... */
419 if (!smb_node_is_file(ofile->f_node)) {
420 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
421 return;
422 }
423
424 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
425 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
426 return;
427 }
428
429 /*
430 * SMB2: Convert to internal form.
431 */
432 switch (op->op_oplock_level) {
433 case SMB2_OPLOCK_LEVEL_BATCH:
434 op->op_oplock_state = OPLOCK_LEVEL_BATCH;
435 break;
436 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
437 op->op_oplock_state = OPLOCK_LEVEL_ONE;
438 break;
439 case SMB2_OPLOCK_LEVEL_II:
440 op->op_oplock_state = OPLOCK_LEVEL_TWO;
441 break;
442 case SMB2_OPLOCK_LEVEL_LEASE:
443 ASSERT(0); /* Handled elsewhere */
444 /* FALLTHROUGH */
445 case SMB2_OPLOCK_LEVEL_NONE:
446 default:
447 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
448 return;
449 }
450
451 /*
452 * Tree options may force shared oplocks,
453 * in which case we reduce the request.
454 * Can't get here with LEVEL_NONE, so
455 * this can only decrease the level.
456 */
457 if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
458 op->op_oplock_state = OPLOCK_LEVEL_TWO;
459 }
460
461 /*
462 * Try exclusive first, if requested
463 */
464 if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) {
465 status = smb_oplock_request(sr, ofile,
466 &op->op_oplock_state);
467 } else {
468 status = NT_STATUS_OPLOCK_NOT_GRANTED;
469 }
470
471 /*
472 * If exclusive failed (or the tree forced shared oplocks)
473 * try for a shared oplock (Level II)
474 */
475 if (status == NT_STATUS_OPLOCK_NOT_GRANTED) {
476 op->op_oplock_state = OPLOCK_LEVEL_TWO;
477 status = smb_oplock_request(sr, ofile,
478 &op->op_oplock_state);
479 }
480
481 /*
482 * Keep track of what we got (ofile->f_oplock.og_state etc)
483 * so we'll know what we had when sending a break later.
484 * The og_dialect here is the oplock dialect, not the
485 * SMB dialect. No lease here, so SMB 2.0.
486 */
487 switch (status) {
488 case NT_STATUS_SUCCESS:
489 case NT_STATUS_OPLOCK_BREAK_IN_PROGRESS:
490 ofile->f_oplock.og_dialect = SMB_VERS_2_002;
491 ofile->f_oplock.og_state = op->op_oplock_state;
492 ofile->f_oplock.og_breakto = op->op_oplock_state;
493 ofile->f_oplock.og_breaking = B_FALSE;
494 if (ofile->dh_persist) {
495 smb2_dh_update_oplock(sr, ofile);
496 }
497 break;
498
499 case NT_STATUS_OPLOCK_NOT_GRANTED:
500 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
501 return;
502
503 default:
504 /* Caller did not check args sufficiently? */
505 cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x",
506 sr->session->ip_addr_str, status);
507 DTRACE_PROBE2(other__error, smb_request_t *, sr,
508 uint32_t, status);
509 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
510 return;
511 }
512
513 /*
514 * Only success cases get here
515 * Convert internal oplock state to SMB2
516 */
517 if (op->op_oplock_state & OPLOCK_LEVEL_GRANULAR) {
518 ASSERT(0);
519 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
520 } else if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) {
521 op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
522 } else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) {
523 op->op_oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
524 } else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) {
525 op->op_oplock_level = SMB2_OPLOCK_LEVEL_II;
526 } else {
527 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
528 }
529
530 /*
531 * An smb_oplock_reqest call may have returned the
532 * status code that says we should wait.
533 */
534 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
535 (void) smb2sr_go_async(sr);
536 (void) smb_oplock_wait_break(sr, ofile->f_node, 0);
537 }
538 }
539
540 /*
541 * smb2_oplock_reconnect() Helper for smb2_dh_reconnect
542 * Get oplock state into op->op_oplock_level etc.
543 *
544 * Similar to the end of smb2_lease_acquire (for leases) or
545 * the end of smb2_oplock_acquire (for old-style oplocks).
546 */
547 void
smb2_oplock_reconnect(smb_request_t * sr)548 smb2_oplock_reconnect(smb_request_t *sr)
549 {
550 smb_arg_open_t *op = &sr->arg.open;
551 smb_ofile_t *ofile = sr->fid_ofile;
552
553 op->op_oplock_state = ofile->f_oplock.og_state;
554 if (ofile->f_lease != NULL) {
555 smb_lease_t *ls = ofile->f_lease;
556
557 op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
558 op->lease_state = ls->ls_state &
559 OPLOCK_LEVEL_CACHE_MASK;
560 op->lease_flags = (ls->ls_breaking != 0) ?
561 SMB2_LEASE_FLAG_BREAK_IN_PROGRESS : 0;
562 op->lease_epoch = ls->ls_epoch;
563 op->lease_version = ls->ls_version;
564 } else {
565 switch (op->op_oplock_state & OPLOCK_LEVEL_TYPE_MASK) {
566 default:
567 case OPLOCK_LEVEL_NONE:
568 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
569 break;
570 case OPLOCK_LEVEL_TWO:
571 op->op_oplock_level = SMB2_OPLOCK_LEVEL_II;
572 break;
573 case OPLOCK_LEVEL_ONE:
574 op->op_oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
575 break;
576 case OPLOCK_LEVEL_BATCH:
577 op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
578 break;
579 }
580 }
581 }
582