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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * Trans2 Set File/Path Information Levels:
28 *
29 * SMB_INFO_STANDARD
30 * SMB_INFO_SET_EAS
31 * SMB_SET_FILE_BASIC_INFO
32 * SMB_SET_FILE_DISPOSITION_INFO
33 * SMB_SET_FILE_END_OF_FILE_INFO
34 * SMB_SET_FILE_ALLOCATION_INFO
35 *
36 * Handled Passthrough levels:
37 * SMB_FILE_BASIC_INFORMATION
38 * SMB_FILE_RENAME_INFORMATION
39 * SMB_FILE_LINK_INFORMATION
40 * SMB_FILE_DISPOSITION_INFORMATION
41 * SMB_FILE_END_OF_FILE_INFORMATION
42 * SMB_FILE_ALLOCATION_INFORMATION
43 *
44 * Internal levels representing non trans2 requests
45 * SMB_SET_INFORMATION
46 * SMB_SET_INFORMATION2
47 */
48
49 /*
50 * Setting timestamps:
51 * The behaviour when the time field is set to -1 is not documented
52 * but is generally treated like 0, meaning that that server file
53 * system assigned value need not be changed.
54 *
55 * Setting attributes - FILE_ATTRIBUTE_NORMAL:
56 * SMB_SET_INFORMATION -
57 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
58 * do NOT change the file's attributes.
59 * SMB_SET_BASIC_INFO -
60 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
61 * clear (0) the file's attributes.
62 * - if the specified attributes are 0 do NOT change the file's
63 * attributes.
64 */
65
66 #include <smbsrv/smb_kproto.h>
67 #include <smbsrv/smb_fsops.h>
68
69 typedef struct smb_setinfo {
70 uint16_t si_infolev;
71 smb_xa_t *si_xa;
72 smb_node_t *si_node;
73 } smb_setinfo_t;
74
75 /*
76 * These functions all return 0 (success) or -1 (error).
77 * They set error details in the sr when appropriate.
78 */
79 static int smb_set_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
80 static int smb_set_by_path(smb_request_t *, smb_xa_t *, uint16_t);
81 static int smb_set_fileinfo(smb_request_t *, smb_setinfo_t *);
82 static int smb_set_information(smb_request_t *, smb_setinfo_t *);
83 static int smb_set_information2(smb_request_t *, smb_setinfo_t *);
84 static int smb_set_standard_info(smb_request_t *, smb_setinfo_t *);
85 static int smb_set_basic_info(smb_request_t *, smb_setinfo_t *);
86 static int smb_set_disposition_info(smb_request_t *, smb_setinfo_t *);
87 static int smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *);
88 static int smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *);
89 static int smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *);
90
91 /*
92 * smb_com_trans2_set_file_information
93 */
94 smb_sdrc_t
smb_com_trans2_set_file_information(smb_request_t * sr,smb_xa_t * xa)95 smb_com_trans2_set_file_information(smb_request_t *sr, smb_xa_t *xa)
96 {
97 uint16_t infolev;
98
99 if (smb_mbc_decodef(&xa->req_param_mb, "ww",
100 &sr->smb_fid, &infolev) != 0)
101 return (SDRC_ERROR);
102
103 if (smb_set_by_fid(sr, xa, infolev) != 0)
104 return (SDRC_ERROR);
105
106 return (SDRC_SUCCESS);
107 }
108
109 /*
110 * smb_com_trans2_set_path_information
111 */
112 smb_sdrc_t
smb_com_trans2_set_path_information(smb_request_t * sr,smb_xa_t * xa)113 smb_com_trans2_set_path_information(smb_request_t *sr, smb_xa_t *xa)
114 {
115 uint16_t infolev;
116 smb_fqi_t *fqi = &sr->arg.dirop.fqi;
117
118 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
119 smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
120 ERRDOS, ERROR_INVALID_FUNCTION);
121 return (SDRC_ERROR);
122 }
123
124 if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
125 sr, &infolev, &fqi->fq_path.pn_path) != 0)
126 return (SDRC_ERROR);
127
128 if (smb_set_by_path(sr, xa, infolev) != 0)
129 return (SDRC_ERROR);
130
131 return (SDRC_SUCCESS);
132 }
133
134 /*
135 * smb_com_set_information (aka setattr)
136 */
137 smb_sdrc_t
smb_pre_set_information(smb_request_t * sr)138 smb_pre_set_information(smb_request_t *sr)
139 {
140 DTRACE_SMB_1(op__SetInformation__start, smb_request_t *, sr);
141 return (SDRC_SUCCESS);
142 }
143
144 void
smb_post_set_information(smb_request_t * sr)145 smb_post_set_information(smb_request_t *sr)
146 {
147 DTRACE_SMB_1(op__SetInformation__done, smb_request_t *, sr);
148 }
149
150 smb_sdrc_t
smb_com_set_information(smb_request_t * sr)151 smb_com_set_information(smb_request_t *sr)
152 {
153 uint16_t infolev = SMB_SET_INFORMATION;
154 smb_fqi_t *fqi = &sr->arg.dirop.fqi;
155
156 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
157 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
158 ERRDOS, ERROR_ACCESS_DENIED);
159 return (SDRC_ERROR);
160 }
161
162 if (smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path) != 0)
163 return (SDRC_ERROR);
164
165 if (smb_set_by_path(sr, NULL, infolev) != 0)
166 return (SDRC_ERROR);
167
168 if (smbsr_encode_empty_result(sr) != 0)
169 return (SDRC_ERROR);
170
171 return (SDRC_SUCCESS);
172 }
173
174 /*
175 * smb_com_set_information2 (aka setattre)
176 */
177 smb_sdrc_t
smb_pre_set_information2(smb_request_t * sr)178 smb_pre_set_information2(smb_request_t *sr)
179 {
180 DTRACE_SMB_1(op__SetInformation2__start, smb_request_t *, sr);
181 return (SDRC_SUCCESS);
182 }
183
184 void
smb_post_set_information2(smb_request_t * sr)185 smb_post_set_information2(smb_request_t *sr)
186 {
187 DTRACE_SMB_1(op__SetInformation2__done, smb_request_t *, sr);
188 }
189
190 smb_sdrc_t
smb_com_set_information2(smb_request_t * sr)191 smb_com_set_information2(smb_request_t *sr)
192 {
193 uint16_t infolev = SMB_SET_INFORMATION2;
194
195 if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0)
196 return (SDRC_ERROR);
197
198 if (smb_set_by_fid(sr, NULL, infolev) != 0)
199 return (SDRC_ERROR);
200
201 if (smbsr_encode_empty_result(sr) != 0)
202 return (SDRC_ERROR);
203
204 return (SDRC_SUCCESS);
205 }
206
207 /*
208 * smb_set_by_fid
209 *
210 * Common code for setting file information by open file id.
211 * Use the id to identify the node object and invoke smb_set_fileinfo
212 * for that node.
213 *
214 * Setting attributes on a named pipe by id is handled by simply
215 * returning success.
216 */
217 static int
smb_set_by_fid(smb_request_t * sr,smb_xa_t * xa,uint16_t infolev)218 smb_set_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
219 {
220 int rc;
221 smb_setinfo_t sinfo;
222
223 if (SMB_TREE_IS_READONLY(sr)) {
224 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
225 ERRDOS, ERROR_ACCESS_DENIED);
226 return (-1);
227 }
228
229 if (STYPE_ISIPC(sr->tid_tree->t_res_type))
230 return (0);
231
232 smbsr_lookup_file(sr);
233 if (sr->fid_ofile == NULL) {
234 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
235 return (-1);
236 }
237
238 if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
239 smbsr_release_file(sr);
240 return (0);
241 }
242
243 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
244
245 sinfo.si_xa = xa;
246 sinfo.si_infolev = infolev;
247 sinfo.si_node = sr->fid_ofile->f_node;
248 rc = smb_set_fileinfo(sr, &sinfo);
249
250 smbsr_release_file(sr);
251 return (rc);
252 }
253
254 /*
255 * smb_set_by_path
256 *
257 * Common code for setting file information by file name.
258 * Use the file name to identify the node object and invoke
259 * smb_set_fileinfo for that node.
260 *
261 * Path should be set in sr->arg.dirop.fqi.fq_path prior to
262 * calling smb_set_by_path.
263 *
264 * Setting attributes on a named pipe by name is an error and
265 * is handled in the calling functions so that they can return
266 * the appropriate error status code (which differs by caller).
267 */
268 static int
smb_set_by_path(smb_request_t * sr,smb_xa_t * xa,uint16_t infolev)269 smb_set_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
270 {
271 int rc;
272 smb_setinfo_t sinfo;
273 smb_node_t *node, *dnode;
274 char *name;
275 smb_pathname_t *pn;
276
277 if (SMB_TREE_IS_READONLY(sr)) {
278 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
279 ERRDOS, ERROR_ACCESS_DENIED);
280 return (-1);
281 }
282
283 pn = &sr->arg.dirop.fqi.fq_path;
284 smb_pathname_init(sr, pn, pn->pn_path);
285 if (!smb_pathname_validate(sr, pn))
286 return (-1);
287
288 name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
289 rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
290 sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, name);
291 if (rc == 0) {
292 rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
293 sr->tid_tree->t_snode, dnode, name, &node);
294 smb_node_release(dnode);
295 }
296 kmem_free(name, MAXNAMELEN);
297
298 if (rc != 0) {
299 if (rc == ENOENT) {
300 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
301 ERRDOS, ERROR_FILE_NOT_FOUND);
302 } else {
303 smbsr_errno(sr, rc);
304 }
305 return (-1);
306 }
307
308 sinfo.si_xa = xa;
309 sinfo.si_infolev = infolev;
310 sinfo.si_node = node;
311 rc = smb_set_fileinfo(sr, &sinfo);
312
313 smb_node_release(node);
314 return (rc);
315 }
316
317 /*
318 * smb_set_fileinfo
319 *
320 * For compatibility with windows servers, SMB_FILE_LINK_INFORMATION
321 * is handled by returning NT_STATUS_NOT_SUPPORTED.
322 */
323 static int
smb_set_fileinfo(smb_request_t * sr,smb_setinfo_t * sinfo)324 smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo)
325 {
326 switch (sinfo->si_infolev) {
327 case SMB_SET_INFORMATION:
328 return (smb_set_information(sr, sinfo));
329
330 case SMB_SET_INFORMATION2:
331 return (smb_set_information2(sr, sinfo));
332
333 case SMB_INFO_STANDARD:
334 return (smb_set_standard_info(sr, sinfo));
335
336 case SMB_INFO_SET_EAS:
337 /* EAs not supported */
338 return (0);
339
340 case SMB_SET_FILE_BASIC_INFO:
341 case SMB_FILE_BASIC_INFORMATION:
342 return (smb_set_basic_info(sr, sinfo));
343
344 case SMB_SET_FILE_DISPOSITION_INFO:
345 case SMB_FILE_DISPOSITION_INFORMATION:
346 return (smb_set_disposition_info(sr, sinfo));
347
348 case SMB_SET_FILE_END_OF_FILE_INFO:
349 case SMB_FILE_END_OF_FILE_INFORMATION:
350 return (smb_set_eof_info(sr, sinfo));
351
352 case SMB_SET_FILE_ALLOCATION_INFO:
353 case SMB_FILE_ALLOCATION_INFORMATION:
354 return (smb_set_alloc_info(sr, sinfo));
355
356 case SMB_FILE_RENAME_INFORMATION:
357 return (smb_set_rename_info(sr, sinfo));
358
359 case SMB_FILE_LINK_INFORMATION:
360 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
361 ERRDOS, ERROR_NOT_SUPPORTED);
362 return (-1);
363 default:
364 break;
365 }
366
367 smbsr_error(sr, NT_STATUS_INVALID_INFO_CLASS,
368 ERRDOS, ERROR_INVALID_PARAMETER);
369 return (-1);
370 }
371
372 /*
373 * smb_set_information
374 *
375 * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
376 * target is not a directory.
377 *
378 * For compatibility with Windows Servers, if the specified
379 * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change
380 * the file's attributes.
381 */
382 static int
smb_set_information(smb_request_t * sr,smb_setinfo_t * sinfo)383 smb_set_information(smb_request_t *sr, smb_setinfo_t *sinfo)
384 {
385 int rc;
386 uint16_t attributes;
387 smb_node_t *node = sinfo->si_node;
388 smb_attr_t attr;
389 uint32_t mtime;
390
391 if (smbsr_decode_vwv(sr, "wl10.", &attributes, &mtime) != 0)
392 return (-1);
393
394 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
395 (!smb_node_is_dir(node))) {
396 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
397 ERRDOS, ERROR_INVALID_PARAMETER);
398 return (-1);
399 }
400
401 bzero(&attr, sizeof (smb_attr_t));
402 if (attributes != FILE_ATTRIBUTE_NORMAL) {
403 attr.sa_dosattr = attributes;
404 attr.sa_mask |= SMB_AT_DOSATTR;
405 }
406
407 if (mtime != 0 && mtime != UINT_MAX) {
408 attr.sa_vattr.va_mtime.tv_sec =
409 smb_time_local_to_gmt(sr, mtime);
410 attr.sa_mask |= SMB_AT_MTIME;
411 }
412
413 rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
414 if (rc != 0) {
415 smbsr_errno(sr, rc);
416 return (-1);
417 }
418
419 return (0);
420 }
421
422 /*
423 * smb_set_information2
424 */
425 static int
smb_set_information2(smb_request_t * sr,smb_setinfo_t * sinfo)426 smb_set_information2(smb_request_t *sr, smb_setinfo_t *sinfo)
427 {
428 int rc;
429 uint32_t crtime, atime, mtime;
430 smb_attr_t attr;
431
432 if (smbsr_decode_vwv(sr, "yyy", &crtime, &atime, &mtime) != 0)
433 return (-1);
434
435 bzero(&attr, sizeof (smb_attr_t));
436 if (mtime != 0 && mtime != UINT_MAX) {
437 attr.sa_vattr.va_mtime.tv_sec =
438 smb_time_local_to_gmt(sr, mtime);
439 attr.sa_mask |= SMB_AT_MTIME;
440 }
441
442 if (crtime != 0 && crtime != UINT_MAX) {
443 attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
444 attr.sa_mask |= SMB_AT_CRTIME;
445 }
446
447 if (atime != 0 && atime != UINT_MAX) {
448 attr.sa_vattr.va_atime.tv_sec =
449 smb_time_local_to_gmt(sr, atime);
450 attr.sa_mask |= SMB_AT_ATIME;
451 }
452
453 rc = smb_node_setattr(sr, sinfo->si_node, sr->user_cr,
454 sr->fid_ofile, &attr);
455 if (rc != 0) {
456 smbsr_errno(sr, rc);
457 return (-1);
458 }
459
460 return (0);
461 }
462
463 /*
464 * smb_set_standard_info
465 *
466 * Sets standard file/path information.
467 */
468 static int
smb_set_standard_info(smb_request_t * sr,smb_setinfo_t * sinfo)469 smb_set_standard_info(smb_request_t *sr, smb_setinfo_t *sinfo)
470 {
471 smb_attr_t attr;
472 uint32_t crtime, atime, mtime;
473 smb_node_t *node = sinfo->si_node;
474 int rc;
475
476 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "yyy",
477 &crtime, &atime, &mtime) != 0) {
478 return (-1);
479 }
480
481 bzero(&attr, sizeof (smb_attr_t));
482 if (mtime != 0 && mtime != (uint32_t)-1) {
483 attr.sa_vattr.va_mtime.tv_sec =
484 smb_time_local_to_gmt(sr, mtime);
485 attr.sa_mask |= SMB_AT_MTIME;
486 }
487
488 if (crtime != 0 && crtime != (uint32_t)-1) {
489 attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
490 attr.sa_mask |= SMB_AT_CRTIME;
491 }
492
493 if (atime != 0 && atime != (uint32_t)-1) {
494 attr.sa_vattr.va_atime.tv_sec =
495 smb_time_local_to_gmt(sr, atime);
496 attr.sa_mask |= SMB_AT_ATIME;
497 }
498
499 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
500 if (rc != 0) {
501 smbsr_errno(sr, rc);
502 return (-1);
503 }
504
505 return (0);
506 }
507
508 /*
509 * smb_set_basic_info
510 *
511 * Sets basic file/path information.
512 *
513 * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
514 * target is not a directory.
515 *
516 * For compatibility with windows servers:
517 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
518 * clear (0) the file's attributes.
519 * - if the specified attributes are 0 do NOT change the file's attributes.
520 */
521 static int
smb_set_basic_info(smb_request_t * sr,smb_setinfo_t * sinfo)522 smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *sinfo)
523 {
524 int rc;
525 uint64_t crtime, atime, mtime, ctime;
526 uint16_t attributes;
527 smb_attr_t attr;
528 smb_node_t *node = sinfo->si_node;
529
530 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "qqqqw",
531 &crtime, &atime, &mtime, &ctime, &attributes) != 0) {
532 return (-1);
533 }
534
535 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
536 (!smb_node_is_dir(node))) {
537 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
538 ERRDOS, ERROR_INVALID_PARAMETER);
539 return (-1);
540 }
541
542 bzero(&attr, sizeof (smb_attr_t));
543 if (ctime != 0 && ctime != (uint64_t)-1) {
544 smb_time_nt_to_unix(ctime, &attr.sa_vattr.va_ctime);
545 attr.sa_mask |= SMB_AT_CTIME;
546 }
547
548 if (crtime != 0 && crtime != (uint64_t)-1) {
549 smb_time_nt_to_unix(crtime, &attr.sa_crtime);
550 attr.sa_mask |= SMB_AT_CRTIME;
551 }
552
553 if (mtime != 0 && mtime != (uint64_t)-1) {
554 smb_time_nt_to_unix(mtime, &attr.sa_vattr.va_mtime);
555 attr.sa_mask |= SMB_AT_MTIME;
556 }
557
558 if (atime != 0 && atime != (uint64_t)-1) {
559 smb_time_nt_to_unix(atime, &attr.sa_vattr.va_atime);
560 attr.sa_mask |= SMB_AT_ATIME;
561 }
562
563 if (attributes != 0) {
564 attr.sa_dosattr = attributes;
565 attr.sa_mask |= SMB_AT_DOSATTR;
566 }
567
568 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
569 if (rc != 0) {
570 smbsr_errno(sr, rc);
571 return (-1);
572 }
573
574 return (0);
575 }
576
577 /*
578 * smb_set_eof_info
579 */
580 static int
smb_set_eof_info(smb_request_t * sr,smb_setinfo_t * sinfo)581 smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *sinfo)
582 {
583 int rc;
584 smb_attr_t attr;
585 uint64_t eof;
586 smb_node_t *node = sinfo->si_node;
587
588 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &eof) != 0)
589 return (-1);
590
591 if (smb_node_is_dir(node)) {
592 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
593 ERRDOS, ERROR_INVALID_PARAMETER);
594 return (-1);
595 }
596
597 /* If opened by path, break exclusive oplock */
598 if (sr->fid_ofile == NULL)
599 (void) smb_oplock_break(sr, node,
600 SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE);
601
602 bzero(&attr, sizeof (smb_attr_t));
603 attr.sa_mask = SMB_AT_SIZE;
604 attr.sa_vattr.va_size = (u_offset_t)eof;
605 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
606 if (rc != 0) {
607 smbsr_errno(sr, rc);
608 return (-1);
609 }
610
611 smb_oplock_break_levelII(node);
612 return (0);
613 }
614
615 /*
616 * smb_set_alloc_info
617 */
618 static int
smb_set_alloc_info(smb_request_t * sr,smb_setinfo_t * sinfo)619 smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *sinfo)
620 {
621 int rc;
622 smb_attr_t attr;
623 uint64_t allocsz;
624 smb_node_t *node = sinfo->si_node;
625
626 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &allocsz) != 0)
627 return (-1);
628
629 if (smb_node_is_dir(node)) {
630 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
631 ERRDOS, ERROR_INVALID_PARAMETER);
632 return (-1);
633 }
634
635 /* If opened by path, break exclusive oplock */
636 if (sr->fid_ofile == NULL)
637 (void) smb_oplock_break(sr, node,
638 SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE);
639
640 bzero(&attr, sizeof (smb_attr_t));
641 attr.sa_mask = SMB_AT_ALLOCSZ;
642 attr.sa_allocsz = (u_offset_t)allocsz;
643 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
644 if (rc != 0) {
645 smbsr_errno(sr, rc);
646 return (-1);
647 }
648
649 smb_oplock_break_levelII(node);
650 return (0);
651 }
652
653 /*
654 * smb_set_disposition_info
655 *
656 * Set/Clear DELETE_ON_CLOSE flag for an open file.
657 * File should have been opened with DELETE access otherwise
658 * the operation is not permitted.
659 *
660 * NOTE: The node should be marked delete-on-close upon the receipt
661 * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
662 * It is different than both SmbNtCreateAndX and SmbNtTransact, which
663 * set delete-on-close on the ofile and defer setting the flag on the
664 * node until the file is closed.
665 *
666 * Observation of Windows 2000 indicates the following:
667 *
668 * 1) If a file is not opened with delete-on-close create options and
669 * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
670 * using that open file handle, any subsequent open requests will fail
671 * with DELETE_PENDING.
672 *
673 * 2) If a file is opened with delete-on-close create options and the
674 * client attempts to unset delete-on-close via Trans2SetFileInfo
675 * (SetDispositionInfo) prior to the file close, any subsequent open
676 * requests will still fail with DELETE_PENDING after the file is closed.
677 *
678 * 3) If a file is opened with delete-on-close create options and that
679 * file handle (not the last open handle and the only file handle
680 * with delete-on-close set) is closed. Any subsequent open requests
681 * will fail with DELETE_PENDING. Unsetting delete-on-close via
682 * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
683 * node delete-on-close flag, which will result in the file not being
684 * removed even after the last file handle is closed.
685 */
686 static int
smb_set_disposition_info(smb_request_t * sr,smb_setinfo_t * sinfo)687 smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *sinfo)
688 {
689 unsigned char mark_delete;
690 uint32_t flags = 0;
691 int doserr;
692 uint32_t status;
693
694 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "b", &mark_delete) != 0)
695 return (-1);
696
697 if ((sr->fid_ofile == NULL) ||
698 !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
699 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
700 ERRDOS, ERROR_ACCESS_DENIED);
701 return (-1);
702 }
703
704 if (mark_delete) {
705 if (SMB_TREE_SUPPORTS_CATIA(sr))
706 flags |= SMB_CATIA;
707
708 status = smb_node_set_delete_on_close(sinfo->si_node,
709 sr->user_cr, flags);
710 if (status != NT_STATUS_SUCCESS) {
711 switch (status) {
712 case NT_STATUS_CANNOT_DELETE:
713 doserr = ERROR_ACCESS_DENIED;
714 break;
715 case NT_STATUS_DIRECTORY_NOT_EMPTY:
716 doserr = ERROR_DIR_NOT_EMPTY;
717 break;
718 default:
719 doserr = ERROR_GEN_FAILURE;
720 break;
721 }
722 smbsr_error(sr, status, ERRDOS, doserr);
723 return (-1);
724 }
725 } else {
726 smb_node_reset_delete_on_close(sinfo->si_node);
727 }
728 return (0);
729 }
730
731 /*
732 * smb_set_rename_info
733 *
734 * Explicitly specified parameter validation rules:
735 * - If rootdir is not NULL respond with NT_STATUS_INVALID_PARAMETER.
736 * - If the filename contains a separator character respond with
737 * NT_STATUS_INVALID_PARAMETER.
738 *
739 * Oplock break:
740 * Some Windows servers break BATCH oplocks prior to the rename.
741 * W2K3 does not. We behave as W2K3; we do not send an oplock break.
742 */
743 static int
smb_set_rename_info(smb_request_t * sr,smb_setinfo_t * sinfo)744 smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *sinfo)
745 {
746 int rc;
747 uint32_t flags, rootdir, namelen;
748 char *fname;
749
750 rc = smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "lll",
751 &flags, &rootdir, &namelen);
752 if (rc == 0) {
753 rc = smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "%#U",
754 sr, namelen, &fname);
755 }
756 if (rc != 0)
757 return (-1);
758
759 if ((rootdir != 0) || (namelen == 0) || (namelen >= MAXNAMELEN)) {
760 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
761 ERRDOS, ERROR_INVALID_PARAMETER);
762 return (-1);
763 }
764
765 if (strchr(fname, '\\') != NULL) {
766 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
767 ERRDOS, ERROR_NOT_SUPPORTED);
768 return (-1);
769 }
770
771 rc = smb_trans2_rename(sr, sinfo->si_node, fname, flags);
772
773 return ((rc == 0) ? 0 : -1);
774 }
775