1 /*
2 * CDDL HEADER START
3 *
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 2016 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <sys/sdt.h>
28 #include <smbsrv/smb_kproto.h>
29 #include <smbsrv/smb_fsops.h>
30 #include <smbsrv/netbios.h>
31
32
33 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *);
34
35
36 /*
37 * Write count bytes at the specified offset in a file. The offset is
38 * limited to 32-bits. If the count is zero, the file is truncated to
39 * the length specified by the offset.
40 *
41 * The response count indicates the actual number of bytes written, which
42 * will equal the requested count on success. If request and response
43 * counts differ but there is no error, the client will assume that the
44 * server encountered a resource issue.
45 */
46 smb_sdrc_t
47 smb_pre_write(smb_request_t *sr)
48 {
49 smb_rw_param_t *param;
50 uint32_t off;
51 uint16_t count;
52 int rc;
53
54 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
55 sr->arg.rw = param;
56 param->rw_magic = SMB_RW_MAGIC;
57
58 rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off);
59
60 param->rw_count = (uint32_t)count;
61 param->rw_offset = (uint64_t)off;
62 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
63
64 DTRACE_SMB_2(op__Write__start, smb_request_t *, sr,
65 smb_rw_param_t *, param);
66
67 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
68 }
69
70 void
71 smb_post_write(smb_request_t *sr)
72 {
73 DTRACE_SMB_2(op__Write__done, smb_request_t *, sr,
74 smb_rw_param_t *, sr->arg.rw);
75
76 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
77 }
78
79 smb_sdrc_t
80 smb_com_write(smb_request_t *sr)
81 {
82 smb_rw_param_t *param = sr->arg.rw;
83 int rc;
84
85 smbsr_lookup_file(sr);
86 if (sr->fid_ofile == NULL) {
87 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
88 return (SDRC_ERROR);
89 }
90
91 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
92
93 if (param->rw_count == 0) {
94 rc = smb_write_truncate(sr, param);
95 } else {
96 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb);
97
98 if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
99 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
100 ERRDOS, ERROR_INVALID_PARAMETER);
101 return (SDRC_ERROR);
102 }
103
104 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
105
106 rc = smb_common_write(sr, param);
107 }
108
109 if (rc != 0) {
110 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
111 smbsr_errno(sr, rc);
112 return (SDRC_ERROR);
113 }
114
115 rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
116 (uint16_t)param->rw_count, 0);
117 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
118 }
119
120 /*
121 * Write count bytes to a file and then close the file. This function
122 * can only be used to write to 32-bit offsets and the client must set
123 * WordCount (6 or 12) correctly in order to locate the data to be
124 * written. If an error occurs on the write, the file should still be
125 * closed. If Count is 0, the file is truncated (or extended) to offset.
126 *
127 * If the last_write time is non-zero, last_write should be used to set
128 * the mtime. Otherwise the file system stamps the mtime. Failure to
129 * set mtime should not result in an error response.
130 */
131 smb_sdrc_t
132 smb_pre_write_and_close(smb_request_t *sr)
133 {
134 smb_rw_param_t *param;
135 uint32_t off;
136 uint16_t count;
137 int rc;
138
139 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
140 sr->arg.rw = param;
141 param->rw_magic = SMB_RW_MAGIC;
142
143 if (sr->smb_wct == 12) {
144 rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
145 &count, &off, ¶m->rw_last_write);
146 } else {
147 rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
148 &count, &off, ¶m->rw_last_write);
149 }
150
151 param->rw_count = (uint32_t)count;
152 param->rw_offset = (uint64_t)off;
153
154 DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr,
155 smb_rw_param_t *, param);
156
157 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
158 }
159
160 void
161 smb_post_write_and_close(smb_request_t *sr)
162 {
163 DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr,
164 smb_rw_param_t *, sr->arg.rw);
165
166 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
167 }
168
169 smb_sdrc_t
170 smb_com_write_and_close(smb_request_t *sr)
171 {
172 smb_rw_param_t *param = sr->arg.rw;
173 uint16_t count;
174 int rc = 0;
175
176 smbsr_lookup_file(sr);
177 if (sr->fid_ofile == NULL) {
178 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
179 return (SDRC_ERROR);
180 }
181
182 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
183
184 if (param->rw_count == 0) {
185 rc = smb_write_truncate(sr, param);
186 } else {
187 /*
188 * There may be a bug here: should this be "3.#B"?
189 */
190 rc = smbsr_decode_data(sr, ".#B", param->rw_count,
191 ¶m->rw_vdb);
192
193 if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
194 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
195 ERRDOS, ERROR_INVALID_PARAMETER);
196 return (SDRC_ERROR);
197 }
198
199 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
200
201 rc = smb_common_write(sr, param);
202 }
203
204 if (rc != 0) {
205 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
206 smbsr_errno(sr, rc);
207 return (SDRC_ERROR);
208 }
209
210 smb_ofile_close(sr->fid_ofile, param->rw_last_write);
211
212 count = (uint16_t)param->rw_count;
213 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0);
214 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
215 }
216
217 /*
218 * Write count bytes to a file at the specified offset and then unlock
219 * them. Write behind is safe because the client should have the range
220 * locked and this request is allowed to extend the file - note that
221 * offset is limited to 32-bits.
222 *
223 * Spec advice: it is an error for count to be zero. For compatibility,
224 * we take no action and return success.
225 *
226 * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk
227 * files. Reject any attempt to use it on other shares.
228 *
229 * The response count indicates the actual number of bytes written, which
230 * will equal the requested count on success. If request and response
231 * counts differ but there is no error, the client will assume that the
232 * server encountered a resource issue.
233 */
234 smb_sdrc_t
235 smb_pre_write_and_unlock(smb_request_t *sr)
236 {
237 smb_rw_param_t *param;
238 uint32_t off;
239 uint16_t count;
240 uint16_t remcnt;
241 int rc;
242
243 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
244 sr->arg.rw = param;
245 param->rw_magic = SMB_RW_MAGIC;
246
247 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt);
248
249 param->rw_count = (uint32_t)count;
250 param->rw_offset = (uint64_t)off;
251
252 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr,
253 smb_rw_param_t *, param);
254
255 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
256 }
257
258 void
259 smb_post_write_and_unlock(smb_request_t *sr)
260 {
261 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr,
262 smb_rw_param_t *, sr->arg.rw);
263
264 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
265 }
266
267 smb_sdrc_t
268 smb_com_write_and_unlock(smb_request_t *sr)
269 {
270 smb_rw_param_t *param = sr->arg.rw;
271 uint32_t lk_pid;
272 uint32_t status;
273 int rc = 0;
274
275 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
276 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
277 return (SDRC_ERROR);
278 }
279
280 smbsr_lookup_file(sr);
281 if (sr->fid_ofile == NULL) {
282 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
283 return (SDRC_ERROR);
284 }
285
286 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
287
288 if (param->rw_count == 0) {
289 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0);
290 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
291 }
292
293
294 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb);
295
296 if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) {
297 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
298 ERRDOS, ERROR_INVALID_PARAMETER);
299 return (SDRC_ERROR);
300 }
301
302 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
303
304 if ((rc = smb_common_write(sr, param)) != 0) {
305 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
306 smbsr_errno(sr, rc);
307 return (SDRC_ERROR);
308 }
309
310
311 /* Note: SMB1 locking uses 16-bit PIDs. */
312 lk_pid = sr->smb_pid & 0xFFFF;
313
314 status = smb_unlock_range(sr, param->rw_offset,
315 (uint64_t)param->rw_count, lk_pid);
316 if (status != NT_STATUS_SUCCESS) {
317 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
318 ERRDOS, ERROR_NOT_LOCKED);
319 return (SDRC_ERROR);
320 }
321
322 rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
323 (uint16_t)param->rw_count, 0);
324 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
325 }
326
327 /*
328 * Write bytes to a file (SMB Core). This request was extended in
329 * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
330 * 14, instead of 12, and including additional offset information.
331 *
332 * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
333 * to truncate a file. A zero length merely transfers zero bytes.
334 *
335 * If bit 0 of WriteMode is set, Fid must refer to a disk file and
336 * the data must be on stable storage before responding.
337 *
338 * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5:
339 * If CAP_LARGE_WRITEX is set, the byte count may be larger than the
340 * negotiated buffer size and the server is expected to write the
341 * number of bytes specified.
342 */
343 smb_sdrc_t
344 smb_pre_write_andx(smb_request_t *sr)
345 {
346 smb_rw_param_t *param;
347 uint32_t off_low;
348 uint32_t off_high;
349 uint16_t datalen_low;
350 uint16_t datalen_high;
351 uint16_t remcnt;
352 int rc;
353
354 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
355 sr->arg.rw = param;
356 param->rw_magic = SMB_RW_MAGIC;
357
358 if (sr->smb_wct == 14) {
359 rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid,
360 &off_low, ¶m->rw_mode, &remcnt, &datalen_high,
361 &datalen_low, ¶m->rw_dsoff, &off_high);
362
363 if (param->rw_dsoff >= 63)
364 param->rw_dsoff -= 63;
365 param->rw_offset = ((uint64_t)off_high << 32) | off_low;
366 } else if (sr->smb_wct == 12) {
367 rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid,
368 &off_low, ¶m->rw_mode, &remcnt, &datalen_high,
369 &datalen_low, ¶m->rw_dsoff);
370
371 if (param->rw_dsoff >= 59)
372 param->rw_dsoff -= 59;
373 param->rw_offset = (uint64_t)off_low;
374 /* off_high not present */
375 } else {
376 rc = -1;
377 }
378
379 param->rw_count = (uint32_t)datalen_low;
380
381 /*
382 * Work-around a Win7 bug, where it fails to set the
383 * CAP_LARGE_WRITEX flag during session setup. Assume
384 * a large write if the data remaining is >= 64k.
385 */
386 if ((sr->session->capabilities & CAP_LARGE_WRITEX) != 0 ||
387 (sr->smb_data.max_bytes > (sr->smb_data.chain_offset + 0xFFFF)))
388 param->rw_count |= ((uint32_t)datalen_high << 16);
389
390 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr,
391 smb_rw_param_t *, param);
392
393 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
394 }
395
396 void
397 smb_post_write_andx(smb_request_t *sr)
398 {
399 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr,
400 smb_rw_param_t *, sr->arg.rw);
401
402 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
403 }
404
405 smb_sdrc_t
406 smb_com_write_andx(smb_request_t *sr)
407 {
408 smb_rw_param_t *param = sr->arg.rw;
409 uint16_t count_high;
410 uint16_t count_low;
411 int rc;
412
413 ASSERT(param);
414 ASSERT(param->rw_magic == SMB_RW_MAGIC);
415
416 smbsr_lookup_file(sr);
417 if (sr->fid_ofile == NULL) {
418 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
419 return (SDRC_ERROR);
420 }
421
422 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
423
424 if (SMB_WRMODE_IS_STABLE(param->rw_mode) &&
425 STYPE_ISIPC(sr->tid_tree->t_res_type)) {
426 smbsr_error(sr, 0, ERRSRV, ERRaccess);
427 return (SDRC_ERROR);
428 }
429
430 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
431 ¶m->rw_vdb);
432
433 if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
434 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
435 ERRDOS, ERROR_INVALID_PARAMETER);
436 return (SDRC_ERROR);
437 }
438
439 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
440
441 if (param->rw_count != 0) {
442 if ((rc = smb_common_write(sr, param)) != 0) {
443 if (sr->smb_error.status !=
444 NT_STATUS_FILE_LOCK_CONFLICT)
445 smbsr_errno(sr, rc);
446 return (SDRC_ERROR);
447 }
448 }
449
450 count_low = param->rw_count & 0xFFFF;
451 count_high = (param->rw_count >> 16) & 0xFF;
452
453 rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww",
454 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0);
455
456 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
457 }
458
459 /*
460 * Common function for writing files or IPC/MSRPC named pipes.
461 *
462 * Returns errno values.
463 */
464 int
465 smb_common_write(smb_request_t *sr, smb_rw_param_t *param)
466 {
467 smb_ofile_t *ofile = sr->fid_ofile;
468 smb_node_t *node;
469 int stability = 0;
470 uint32_t lcount;
471 int rc = 0;
472
473 switch (sr->tid_tree->t_res_type & STYPE_MASK) {
474 case STYPE_DISKTREE:
475 case STYPE_PRINTQ:
476 node = ofile->f_node;
477
478 if (!smb_node_is_dir(node)) {
479 rc = smb_lock_range_access(sr, node, param->rw_offset,
480 param->rw_count, B_TRUE);
481 if (rc != NT_STATUS_SUCCESS) {
482 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
483 ERRDOS, ERROR_LOCK_VIOLATION);
484 return (EACCES);
485 }
486 }
487
488 if (SMB_WRMODE_IS_STABLE(param->rw_mode) ||
489 (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
490 stability = FSYNC;
491 }
492
493 rc = smb_fsop_write(sr, sr->user_cr, node, ofile,
494 ¶m->rw_vdb.vdb_uio, &lcount, stability);
495
496 if (rc)
497 return (rc);
498
499 /*
500 * Used to have code here to set mtime.
501 * We have just done a write, so we know
502 * the file system will update mtime.
503 * No need to do it again here.
504 *
505 * However, keep track of the fact that
506 * we have written data via this handle.
507 */
508 ofile->f_written = B_TRUE;
509
510 if (!smb_node_is_dir(node))
511 smb_oplock_break_levelII(node);
512
513 param->rw_count = lcount;
514 break;
515
516 case STYPE_IPC:
517 param->rw_count = param->rw_vdb.vdb_uio.uio_resid;
518
519 if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0)
520 param->rw_count = 0;
521 break;
522
523 default:
524 rc = EACCES;
525 break;
526 }
527
528 if (rc != 0)
529 return (rc);
530
531 mutex_enter(&ofile->f_mutex);
532 ofile->f_seek_pos = param->rw_offset + param->rw_count;
533 mutex_exit(&ofile->f_mutex);
534 return (rc);
535 }
536
537 /*
538 * Truncate a disk file to the specified offset.
539 * Typically, w_count will be zero here.
540 *
541 * Note that smb_write_andx cannot be used to reduce the file size so,
542 * if this is required, smb_write is called with a count of zero and
543 * the appropriate file length in offset. The file should be resized
544 * to the length specified by the offset.
545 *
546 * Returns errno values.
547 */
548 static int
549 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param)
550 {
551 smb_ofile_t *ofile = sr->fid_ofile;
552 smb_node_t *node = ofile->f_node;
553 smb_attr_t attr;
554 uint32_t status;
555 int rc;
556
557 if (STYPE_ISIPC(sr->tid_tree->t_res_type))
558 return (0);
559
560 mutex_enter(&node->n_mutex);
561 if (!smb_node_is_dir(node)) {
562 status = smb_lock_range_access(sr, node, param->rw_offset,
563 param->rw_count, B_TRUE);
564 if (status != NT_STATUS_SUCCESS) {
565 mutex_exit(&node->n_mutex);
566 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
567 ERRDOS, ERROR_LOCK_VIOLATION);
568 return (EACCES);
569 }
570 }
571 mutex_exit(&node->n_mutex);
572
573 bzero(&attr, sizeof (smb_attr_t));
574 attr.sa_mask = SMB_AT_SIZE;
575 attr.sa_vattr.va_size = param->rw_offset;
576 rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr);
577 if (rc != 0)
578 return (rc);
579
580 mutex_enter(&ofile->f_mutex);
581 ofile->f_seek_pos = param->rw_offset + param->rw_count;
582 mutex_exit(&ofile->f_mutex);
583 return (0);
584 }