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 2013 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <sys/sunddi.h>
28 #include <sys/nbmlock.h>
29
30 #include <smbsrv/smb_kproto.h>
31 #include <smbsrv/smb_fsops.h>
32 #include <smbsrv/smbinfo.h>
33
34 static int smb_delete_check_path(smb_request_t *);
35 static int smb_delete_single_file(smb_request_t *, smb_error_t *);
36 static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
37 static int smb_delete_find_fname(smb_request_t *, smb_odir_t *, char *, int);
38 static int smb_delete_check_dosattr(smb_request_t *, smb_error_t *);
39 static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
40
41 static void smb_delete_error(smb_error_t *, uint32_t, uint16_t, uint16_t);
42
43 /*
44 * smb_com_delete
87 * ERRDOS/ERRbadfile
88 * ERRDOS/ERRnoaccess
89 * ERRDOS/ERRbadshare # returned by NT for files that are already open
90 * ERRHRD/ERRnowrite
91 * ERRSRV/ERRaccess
92 * ERRSRV/ERRinvdevice
93 * ERRSRV/ERRinvid
94 * ERRSRV/ERRbaduid
95 */
96 smb_sdrc_t
97 smb_pre_delete(smb_request_t *sr)
98 {
99 int rc;
100 smb_fqi_t *fqi;
101
102 fqi = &sr->arg.dirop.fqi;
103
104 if ((rc = smbsr_decode_vwv(sr, "w", &fqi->fq_sattr)) == 0)
105 rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
106
107 DTRACE_SMB_2(op__Delete__start, smb_request_t *, sr, smb_fqi_t *, fqi);
108
109 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
110 }
111
112 void
113 smb_post_delete(smb_request_t *sr)
114 {
115 DTRACE_SMB_1(op__Delete__done, smb_request_t *, sr);
116 }
117
118 /*
119 * smb_com_delete
120 *
121 * 1. intialize, pre-process and validate pathname
122 *
123 * 2. process the path to get directory node & last_comp,
124 * store these in fqi
125 * - If smb_pathname_reduce cannot find the specified path,
126 * the error (ENOTDIR) is translated to NT_STATUS_OBJECT_PATH_NOT_FOUND
127 * if the target is a single file (no wildcards). If there are
128 * wildcards in the last_comp, NT_STATUS_OBJECT_NAME_NOT_FOUND is
129 * used instead.
130 * - If the directory node is the mount point and the last component
131 * is ".." NT_STATUS_OBJECT_PATH_SYNTAX_BAD is returned.
132 *
133 * 3. check access permissions
134 *
135 * 4. invoke the appropriate deletion routine to find and remove
453 * after checking for sharing violations. Attempting to delete a
454 * locked file will result in sharing violation, which is the same
455 * thing that will happen if you try to delete a non-locked open file.
456 *
457 * Note that windows 2000 rejects lock requests on open files that
458 * have been opened with metadata open modes. The error is
459 * STATUS_ACCESS_DENIED.
460 *
461 * NT does not always close a file immediately, which can cause the
462 * share and access checking to fail (the node refcnt is greater
463 * than one), and the file doesn't get deleted. Breaking the oplock
464 * before share and lock checking gives the client a chance to
465 * close the file.
466 *
467 * Returns: 0 - success
468 * -1 - error, err populated with error details
469 */
470 static int
471 smb_delete_remove_file(smb_request_t *sr, smb_error_t *err)
472 {
473 int rc, count;
474 uint32_t status;
475 smb_fqi_t *fqi;
476 smb_node_t *node;
477 uint32_t flags = 0;
478
479 fqi = &sr->arg.dirop.fqi;
480 node = fqi->fq_fnode;
481
482 /*
483 * Break BATCH oplock before ofile checks. If a client
484 * has a file open, this will force a flush or close,
485 * which may affect the outcome of any share checking.
486 */
487 (void) smb_oplock_break(sr, node,
488 SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH);
489
490 /*
491 * Wait (a little) for the oplock break to be
492 * responded to by clients closing handles.
493 * Hold node->n_lock as reader to keep new
494 * ofiles from showing up after we check.
495 */
496 smb_node_rdlock(node);
497 for (count = 0; count <= 12; count++) {
498 status = smb_node_delete_check(node);
499 if (status != NT_STATUS_SHARING_VIOLATION)
500 break;
501 smb_node_unlock(node);
502 delay(MSEC_TO_TICK(100));
503 smb_node_rdlock(node);
504 }
505 if (status != NT_STATUS_SUCCESS) {
506 smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
507 ERRDOS, ERROR_SHARING_VIOLATION);
508 smb_node_unlock(node);
509 return (-1);
510 }
511
512 /*
513 * Note, the combination of these two:
514 * smb_node_rdlock(node);
515 * nbl_start_crit(node->vp, RW_READER);
516 * is equivalent to this call:
517 * smb_node_start_crit(node, RW_READER)
518 *
519 * Cleanup after this point should use:
520 * smb_node_end_crit(node)
521 */
522 nbl_start_crit(node->vp, RW_READER);
523
524 /*
525 * This checks nbl_share_conflict, nbl_lock_conflict
526 */
527 status = smb_nbl_conflict(node, 0, UINT64_MAX, NBL_REMOVE);
528 if (status == NT_STATUS_SHARING_VIOLATION) {
529 smb_node_end_crit(node);
530 smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
531 ERRDOS, ERROR_SHARING_VIOLATION);
532 return (-1);
533 }
534 if (status != NT_STATUS_SUCCESS) {
535 smb_node_end_crit(node);
536 smb_delete_error(err, NT_STATUS_ACCESS_DENIED,
537 ERRDOS, ERROR_ACCESS_DENIED);
538 return (-1);
539 }
540
541 if (SMB_TREE_SUPPORTS_CATIA(sr))
542 flags |= SMB_CATIA;
543
544 rc = smb_fsop_remove(sr, sr->user_cr, node->n_dnode,
545 node->od_name, flags);
546 if (rc != 0) {
547 if (rc == ENOENT)
548 smb_delete_error(err, NT_STATUS_OBJECT_NAME_NOT_FOUND,
549 ERRDOS, ERROR_FILE_NOT_FOUND);
550 else
551 smbsr_map_errno(rc, err);
552
553 smb_node_end_crit(node);
554 return (-1);
555 }
556
557 smb_node_end_crit(node);
558 return (0);
559 }
560
561
562 /*
563 * smb_delete_check_path
564 *
565 * smb_pathname_validate() should already have been used to
566 * perform initial validation on the pathname. Additional
567 * request specific validation of the filename is performed
568 * here.
569 *
570 * - pn->pn_fname is NULL should result in NT_STATUS_FILE_IS_A_DIRECTORY
571 *
572 * - Any wildcard filename that resolves to '.' should result in
573 * NT_STATUS_OBJECT_NAME_INVALID if the search attributes include
574 * FILE_ATTRIBUTE_DIRECTORY
575 *
576 * Returns:
577 * 0: path is valid.
578 * -1: path is invalid. Sets error information in sr.
|
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 #include <sys/sunddi.h>
28 #include <sys/nbmlock.h>
29
30 #include <smbsrv/smb_kproto.h>
31 #include <smbsrv/smb_fsops.h>
32 #include <smbsrv/smbinfo.h>
33
34 static int smb_delete_check_path(smb_request_t *);
35 static int smb_delete_single_file(smb_request_t *, smb_error_t *);
36 static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
37 static int smb_delete_find_fname(smb_request_t *, smb_odir_t *, char *, int);
38 static int smb_delete_check_dosattr(smb_request_t *, smb_error_t *);
39 static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
40
41 static void smb_delete_error(smb_error_t *, uint32_t, uint16_t, uint16_t);
42
43 /*
44 * smb_com_delete
87 * ERRDOS/ERRbadfile
88 * ERRDOS/ERRnoaccess
89 * ERRDOS/ERRbadshare # returned by NT for files that are already open
90 * ERRHRD/ERRnowrite
91 * ERRSRV/ERRaccess
92 * ERRSRV/ERRinvdevice
93 * ERRSRV/ERRinvid
94 * ERRSRV/ERRbaduid
95 */
96 smb_sdrc_t
97 smb_pre_delete(smb_request_t *sr)
98 {
99 int rc;
100 smb_fqi_t *fqi;
101
102 fqi = &sr->arg.dirop.fqi;
103
104 if ((rc = smbsr_decode_vwv(sr, "w", &fqi->fq_sattr)) == 0)
105 rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
106
107 DTRACE_SMB_START(op__Delete, smb_request_t *, sr); /* arg.dirop */
108
109 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
110 }
111
112 void
113 smb_post_delete(smb_request_t *sr)
114 {
115 DTRACE_SMB_DONE(op__Delete, smb_request_t *, sr);
116 }
117
118 /*
119 * smb_com_delete
120 *
121 * 1. intialize, pre-process and validate pathname
122 *
123 * 2. process the path to get directory node & last_comp,
124 * store these in fqi
125 * - If smb_pathname_reduce cannot find the specified path,
126 * the error (ENOTDIR) is translated to NT_STATUS_OBJECT_PATH_NOT_FOUND
127 * if the target is a single file (no wildcards). If there are
128 * wildcards in the last_comp, NT_STATUS_OBJECT_NAME_NOT_FOUND is
129 * used instead.
130 * - If the directory node is the mount point and the last component
131 * is ".." NT_STATUS_OBJECT_PATH_SYNTAX_BAD is returned.
132 *
133 * 3. check access permissions
134 *
135 * 4. invoke the appropriate deletion routine to find and remove
453 * after checking for sharing violations. Attempting to delete a
454 * locked file will result in sharing violation, which is the same
455 * thing that will happen if you try to delete a non-locked open file.
456 *
457 * Note that windows 2000 rejects lock requests on open files that
458 * have been opened with metadata open modes. The error is
459 * STATUS_ACCESS_DENIED.
460 *
461 * NT does not always close a file immediately, which can cause the
462 * share and access checking to fail (the node refcnt is greater
463 * than one), and the file doesn't get deleted. Breaking the oplock
464 * before share and lock checking gives the client a chance to
465 * close the file.
466 *
467 * Returns: 0 - success
468 * -1 - error, err populated with error details
469 */
470 static int
471 smb_delete_remove_file(smb_request_t *sr, smb_error_t *err)
472 {
473 int rc;
474 uint32_t status;
475 smb_fqi_t *fqi;
476 smb_node_t *node;
477 uint32_t flags = 0;
478
479 fqi = &sr->arg.dirop.fqi;
480 node = fqi->fq_fnode;
481
482 /*
483 * Break BATCH oplock before ofile checks. If a client
484 * has a file open, this will force a flush or close,
485 * which may affect the outcome of any share checking.
486 */
487 status = smb_oplock_break_DELETE(node, NULL);
488 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
489 (void) smb_oplock_wait_break(node, 0);
490 status = 0;
491 }
492 if (status != 0) {
493 err->status = status;
494 return (-1);
495 }
496
497 smb_node_rdlock(node);
498 status = smb_node_delete_check(node);
499 if (status != NT_STATUS_SUCCESS) {
500 smb_node_unlock(node);
501 smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
502 ERRDOS, ERROR_SHARING_VIOLATION);
503 return (-1);
504 }
505
506 /*
507 * Note, the combination of these two:
508 * smb_node_rdlock(node);
509 * nbl_start_crit(node->vp, RW_READER);
510 * is equivalent to this call:
511 * smb_node_start_crit(node, RW_READER)
512 *
513 * Cleanup after this point should use:
514 * smb_node_end_crit(node)
515 */
516 nbl_start_crit(node->vp, RW_READER);
517
518 /*
519 * This checks nbl_share_conflict, nbl_lock_conflict
520 */
521 status = smb_nbl_conflict(node, 0, UINT64_MAX, NBL_REMOVE);
522 if (status == NT_STATUS_SHARING_VIOLATION) {
523 smb_node_end_crit(node);
524 smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
525 ERRDOS, ERROR_SHARING_VIOLATION);
526 return (-1);
527 }
528 if (status != NT_STATUS_SUCCESS) {
529 smb_node_end_crit(node);
530 smb_delete_error(err, NT_STATUS_ACCESS_DENIED,
531 ERRDOS, ERROR_ACCESS_DENIED);
532 return (-1);
533 }
534
535 if (SMB_TREE_SUPPORTS_CATIA(sr))
536 flags |= SMB_CATIA;
537
538 rc = smb_fsop_remove(sr, sr->user_cr, node->n_dnode,
539 node->od_name, flags);
540 if (rc != 0) {
541 smbsr_map_errno(rc, err);
542 rc = -1;
543 }
544
545 smb_node_end_crit(node);
546 return (rc);
547 }
548
549
550 /*
551 * smb_delete_check_path
552 *
553 * smb_pathname_validate() should already have been used to
554 * perform initial validation on the pathname. Additional
555 * request specific validation of the filename is performed
556 * here.
557 *
558 * - pn->pn_fname is NULL should result in NT_STATUS_FILE_IS_A_DIRECTORY
559 *
560 * - Any wildcard filename that resolves to '.' should result in
561 * NT_STATUS_OBJECT_NAME_INVALID if the search attributes include
562 * FILE_ATTRIBUTE_DIRECTORY
563 *
564 * Returns:
565 * 0: path is valid.
566 * -1: path is invalid. Sets error information in sr.
|