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