xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_delete.c (revision 7052:efa04b030974)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
225772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw #pragma ident	"%Z%%M%	%I%	%E% SMI"
275331Samw 
285331Samw #include <smbsrv/smb_incl.h>
295331Samw #include <smbsrv/smb_fsops.h>
305331Samw #include <smbsrv/smbinfo.h>
315772Sas200622 #include <sys/nbmlock.h>
325331Samw 
336139Sjb150015 static uint32_t smb_delete_check(smb_request_t *, smb_node_t *);
345331Samw 
355331Samw /*
365331Samw  * smb_com_delete
375331Samw  *
385331Samw  * The delete file message is sent to delete a data file. The appropriate
395331Samw  * Tid and additional pathname are passed. Read only files may not be
405331Samw  * deleted, the read-only attribute must be reset prior to file deletion.
415331Samw  *
425331Samw  * NT supports a hidden permission known as File Delete Child (FDC). If
435331Samw  * the user has FullControl access to a directory, the user is permitted
445331Samw  * to delete any object in the directory regardless of the permissions
455331Samw  * on the object.
465331Samw  *
475331Samw  * Client Request                     Description
485331Samw  * ================================== =================================
495331Samw  * UCHAR WordCount;                   Count of parameter words = 1
505331Samw  * USHORT SearchAttributes;
515331Samw  * USHORT ByteCount;                  Count of data bytes; min = 2
525331Samw  * UCHAR BufferFormat;                0x04
535331Samw  * STRING FileName[];                 File name
545331Samw  *
555331Samw  * Multiple files may be deleted in response to a single request as
565331Samw  * SMB_COM_DELETE supports wildcards
575331Samw  *
585331Samw  * SearchAttributes indicates the attributes that the target file(s) must
595331Samw  * have. If the attribute is zero then only normal files are deleted. If
605331Samw  * the system file or hidden attributes are specified then the delete is
615331Samw  * inclusive -both the specified type(s) of files and normal files are
625331Samw  * deleted. Attributes are described in the "Attribute Encoding" section
635331Samw  * of this document.
645331Samw  *
655331Samw  * If bit0 of the Flags2 field of the SMB header is set, a pattern is
665331Samw  * passed in, and the file has a long name, then the passed pattern  much
675331Samw  * match the long file name for the delete to succeed. If bit0 is clear, a
685331Samw  * pattern is passed in, and the file has a long name, then the passed
695331Samw  * pattern must match the file's short name for the deletion to succeed.
705331Samw  *
715331Samw  * Server Response                    Description
725331Samw  * ================================== =================================
735331Samw  * UCHAR WordCount;                   Count of parameter words = 0
745331Samw  * USHORT ByteCount;                  Count of data bytes = 0
755331Samw  *
765331Samw  * 4.2.10.1  Errors
775331Samw  *
785331Samw  * ERRDOS/ERRbadpath
795331Samw  * ERRDOS/ERRbadfile
805331Samw  * ERRDOS/ERRnoaccess
815331Samw  * ERRDOS/ERRbadshare	# returned by NT for files that are already open
825331Samw  * ERRHRD/ERRnowrite
835331Samw  * ERRSRV/ERRaccess
845331Samw  * ERRSRV/ERRinvdevice
855331Samw  * ERRSRV/ERRinvid
865331Samw  * ERRSRV/ERRbaduid
875331Samw  */
886030Sjb150015 smb_sdrc_t
896139Sjb150015 smb_pre_delete(smb_request_t *sr)
905331Samw {
916139Sjb150015 	struct smb_fqi *fqi = &sr->arg.dirop.fqi;
926139Sjb150015 	int rc;
936139Sjb150015 
946139Sjb150015 	if ((rc = smbsr_decode_vwv(sr, "w", &fqi->srch_attr)) == 0)
956139Sjb150015 		rc = smbsr_decode_data(sr, "%S", sr, &fqi->path);
966139Sjb150015 
976139Sjb150015 	DTRACE_SMB_2(op__Delete__start, smb_request_t *, sr,
986139Sjb150015 	    struct smb_fqi *, fqi);
996139Sjb150015 
1006139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1016139Sjb150015 }
1026139Sjb150015 
1036139Sjb150015 void
1046139Sjb150015 smb_post_delete(smb_request_t *sr)
1056139Sjb150015 {
1066139Sjb150015 	DTRACE_SMB_1(op__Delete__done, smb_request_t *, sr);
1076139Sjb150015 }
1086139Sjb150015 
1096139Sjb150015 smb_sdrc_t
1106139Sjb150015 smb_com_delete(smb_request_t *sr)
1116139Sjb150015 {
1126139Sjb150015 	struct smb_fqi *fqi = &sr->arg.dirop.fqi;
1135331Samw 	int	rc;
1145331Samw 	int	deleted = 0;
115*7052Samw 	struct smb_node *node = NULL;
1165331Samw 	smb_odir_context_t *pc;
1175331Samw 
1186139Sjb150015 	if (smb_rdir_open(sr, fqi->path, fqi->srch_attr) != 0)
1196139Sjb150015 		return (SDRC_ERROR);
1205772Sas200622 
1215331Samw 	pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
1225331Samw 
1235331Samw 	/*
1245331Samw 	 * This while loop is meant to deal with wildcards.
1255331Samw 	 * It is not expected that wildcards will exist for
1265331Samw 	 * streams.  For the streams case, it is expected
1275331Samw 	 * that the below loop will be executed only once.
1285331Samw 	 */
1295331Samw 
1305331Samw 	while ((rc = smb_rdir_next(sr, &node, pc)) == 0) {
1315331Samw 
132*7052Samw 		if (pc->dc_dattr & FILE_ATTRIBUTE_DIRECTORY) {
1336139Sjb150015 			smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
1346139Sjb150015 			    ERRDOS, ERROR_ACCESS_DENIED);
1355772Sas200622 			smb_node_release(node);
1365772Sas200622 			goto delete_error;
1375772Sas200622 		}
1385772Sas200622 
139*7052Samw 		if ((pc->dc_dattr & FILE_ATTRIBUTE_READONLY) ||
1405772Sas200622 		    (node->flags & NODE_CREATED_READONLY)) {
1416139Sjb150015 			smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
1426139Sjb150015 			    ERRDOS, ERROR_ACCESS_DENIED);
1435331Samw 			smb_node_release(node);
1445331Samw 			goto delete_error;
1455331Samw 		}
1465331Samw 
1475772Sas200622 		/*
1485772Sas200622 		 * NT does not always close a file immediately, which
1495772Sas200622 		 * can cause the share and access checking to fail
1505772Sas200622 		 * (the node refcnt is greater than one), and the file
1515772Sas200622 		 * doesn't get deleted. Breaking the oplock before
1525772Sas200622 		 * share and access checking gives the client a chance
1535772Sas200622 		 * to close the file.
1545772Sas200622 		 */
1555772Sas200622 
1566600Sas200622 		smb_oplock_break(node);
1575772Sas200622 
1585772Sas200622 		smb_node_start_crit(node, RW_READER);
1595772Sas200622 
1606139Sjb150015 		if (smb_delete_check(sr, node) != NT_STATUS_SUCCESS) {
1615772Sas200622 			smb_node_end_crit(node);
1625772Sas200622 			smb_node_release(node);
1635772Sas200622 			goto delete_error;
1645772Sas200622 		}
1655331Samw 
166*7052Samw 		/*
167*7052Samw 		 * Use node->od_name so as to skip mangle checks and
168*7052Samw 		 * stream processing (which have already been done in
169*7052Samw 		 * smb_rdir_next()).
170*7052Samw 		 * Use node->dir_snode to obtain the correct parent node
171*7052Samw 		 * (especially for streams).
172*7052Samw 		 */
173*7052Samw 		rc = smb_fsop_remove(sr, sr->user_cr, node->dir_snode,
174*7052Samw 		    node->od_name, 1);
1755331Samw 
1765772Sas200622 		smb_node_end_crit(node);
1775772Sas200622 		smb_node_release(node);
1785772Sas200622 		node = NULL;
1795772Sas200622 
1805331Samw 		if (rc != 0) {
1816139Sjb150015 			if (rc != ENOENT) {
1826139Sjb150015 				smbsr_errno(sr, rc);
1836139Sjb150015 				goto delete_error;
1846139Sjb150015 			}
1855331Samw 		} else {
1865331Samw 			deleted++;
1875331Samw 		}
1885331Samw 	}
1895331Samw 
1905331Samw 	if ((rc != 0) && (rc != ENOENT)) {
1916139Sjb150015 		smbsr_errno(sr, rc);
1926139Sjb150015 		goto delete_error;
1935331Samw 	}
1945331Samw 
1955331Samw 	if (deleted == 0) {
1966139Sjb150015 		if (sr->sid_odir->d_wildcards == 0)
1976139Sjb150015 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1986139Sjb150015 			    ERRDOS, ERROR_FILE_NOT_FOUND);
1996139Sjb150015 		else
2006139Sjb150015 			smbsr_error(sr, NT_STATUS_NO_SUCH_FILE,
2016139Sjb150015 			    ERRDOS, ERROR_FILE_NOT_FOUND);
2025331Samw 		goto delete_error;
2035331Samw 	}
2045331Samw 
2055331Samw 	smb_rdir_close(sr);
2065331Samw 	kmem_free(pc, sizeof (*pc));
2076030Sjb150015 
2086030Sjb150015 	rc = smbsr_encode_empty_result(sr);
2096139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
2105331Samw 
2115331Samw delete_error:
2125331Samw 	smb_rdir_close(sr);
2135331Samw 	kmem_free(pc, sizeof (*pc));
2146139Sjb150015 	return (SDRC_ERROR);
2155331Samw }
2165331Samw 
2176139Sjb150015 /*
2186139Sjb150015  * For consistency with Windows 2000, the range check should be done
2196139Sjb150015  * after checking for sharing violations.  Attempting to delete a
2206139Sjb150015  * locked file will result in sharing violation, which is the same
2216139Sjb150015  * thing that will happen if you try to delete a non-locked open file.
2226139Sjb150015  *
2236139Sjb150015  * Note that windows 2000 rejects lock requests on open files that
2246139Sjb150015  * have been opened with metadata open modes.  The error is
2256139Sjb150015  * STATUS_ACCESS_DENIED.
2266139Sjb150015  */
2276139Sjb150015 static uint32_t
2286139Sjb150015 smb_delete_check(smb_request_t *sr, smb_node_t *node)
2295331Samw {
2306139Sjb150015 	uint32_t status;
2315331Samw 
2326139Sjb150015 	status = smb_node_delete_check(node);
2336139Sjb150015 
2346139Sjb150015 	if (status == NT_STATUS_SHARING_VIOLATION) {
2356139Sjb150015 		smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
2366139Sjb150015 		    ERRDOS, ERROR_SHARING_VIOLATION);
2376139Sjb150015 		return (status);
2385331Samw 	}
2395331Samw 
2406139Sjb150015 	status = smb_range_check(sr, sr->user_cr, node, 0, UINT64_MAX, B_TRUE);
2415772Sas200622 
2426139Sjb150015 	if (status != NT_STATUS_SUCCESS) {
2436139Sjb150015 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
2446139Sjb150015 		    ERRDOS, ERROR_ACCESS_DENIED);
2455331Samw 	}
2465331Samw 
2476139Sjb150015 	return (status);
2485331Samw }
249