xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_delete.c (revision 6139:5c743b207bf9)
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 
33*6139Sjb150015 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
89*6139Sjb150015 smb_pre_delete(smb_request_t *sr)
905331Samw {
91*6139Sjb150015 	struct smb_fqi *fqi = &sr->arg.dirop.fqi;
92*6139Sjb150015 	int rc;
93*6139Sjb150015 
94*6139Sjb150015 	if ((rc = smbsr_decode_vwv(sr, "w", &fqi->srch_attr)) == 0)
95*6139Sjb150015 		rc = smbsr_decode_data(sr, "%S", sr, &fqi->path);
96*6139Sjb150015 
97*6139Sjb150015 	DTRACE_SMB_2(op__Delete__start, smb_request_t *, sr,
98*6139Sjb150015 	    struct smb_fqi *, fqi);
99*6139Sjb150015 
100*6139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
101*6139Sjb150015 }
102*6139Sjb150015 
103*6139Sjb150015 void
104*6139Sjb150015 smb_post_delete(smb_request_t *sr)
105*6139Sjb150015 {
106*6139Sjb150015 	DTRACE_SMB_1(op__Delete__done, smb_request_t *, sr);
107*6139Sjb150015 }
108*6139Sjb150015 
109*6139Sjb150015 smb_sdrc_t
110*6139Sjb150015 smb_com_delete(smb_request_t *sr)
111*6139Sjb150015 {
112*6139Sjb150015 	struct smb_fqi *fqi = &sr->arg.dirop.fqi;
1135331Samw 	int	rc;
1145331Samw 	int	od = 0;
1155331Samw 	int	deleted = 0;
1165331Samw 	struct smb_node *dir_snode;
1175331Samw 	struct smb_node *node = 0;
1185331Samw 	char *name;
1195331Samw 	char *fname;
1205331Samw 	char *sname;
1215331Samw 	char *fullname;
122*6139Sjb150015 	uint32_t status;
1235331Samw 	int is_stream;
1245331Samw 	smb_odir_context_t *pc;
1255331Samw 
126*6139Sjb150015 	if (smb_rdir_open(sr, fqi->path, fqi->srch_attr) != 0)
127*6139Sjb150015 		return (SDRC_ERROR);
1285772Sas200622 
1295331Samw 	pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
1305331Samw 	fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1315331Samw 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1325331Samw 	name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1335331Samw 	fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1345331Samw 
135*6139Sjb150015 	is_stream = smb_stream_parse_name(fqi->path, fname, sname);
1365331Samw 	dir_snode = sr->sid_odir->d_dir_snode;
1375331Samw 
1385331Samw 	/*
1395331Samw 	 * This while loop is meant to deal with wildcards.
1405331Samw 	 * It is not expected that wildcards will exist for
1415331Samw 	 * streams.  For the streams case, it is expected
1425331Samw 	 * that the below loop will be executed only once.
1435331Samw 	 */
1445331Samw 
1455331Samw 	while ((rc = smb_rdir_next(sr, &node, pc)) == 0) {
1465331Samw 		(void) strlcpy(name, pc->dc_name, MAXNAMELEN);
1475331Samw 
1485772Sas200622 		if (pc->dc_dattr & SMB_FA_DIRECTORY) {
149*6139Sjb150015 			smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
150*6139Sjb150015 			    ERRDOS, ERROR_ACCESS_DENIED);
1515772Sas200622 			smb_node_release(node);
1525772Sas200622 			goto delete_error;
1535772Sas200622 		}
1545772Sas200622 
1555772Sas200622 		if ((pc->dc_dattr & SMB_FA_READONLY) ||
1565772Sas200622 		    (node->flags & NODE_CREATED_READONLY)) {
157*6139Sjb150015 			smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
158*6139Sjb150015 			    ERRDOS, ERROR_ACCESS_DENIED);
1595331Samw 			smb_node_release(node);
1605331Samw 			goto delete_error;
1615331Samw 		}
1625331Samw 
1635772Sas200622 		/*
1645772Sas200622 		 * NT does not always close a file immediately, which
1655772Sas200622 		 * can cause the share and access checking to fail
1665772Sas200622 		 * (the node refcnt is greater than one), and the file
1675772Sas200622 		 * doesn't get deleted. Breaking the oplock before
1685772Sas200622 		 * share and access checking gives the client a chance
1695772Sas200622 		 * to close the file.
1705772Sas200622 		 */
1715772Sas200622 
1725772Sas200622 		if (OPLOCKS_IN_FORCE(node)) {
173*6139Sjb150015 			status = smb_break_oplock(sr, node);
1745772Sas200622 
175*6139Sjb150015 			if (status != NT_STATUS_SUCCESS) {
176*6139Sjb150015 				smbsr_error(sr, status,
177*6139Sjb150015 				    ERRDOS, ERROR_VC_DISCONNECTED);
1785772Sas200622 				smb_node_release(node);
1795772Sas200622 				goto delete_error;
1805772Sas200622 			}
1815772Sas200622 		}
1825772Sas200622 
1835772Sas200622 		smb_node_start_crit(node, RW_READER);
1845772Sas200622 
185*6139Sjb150015 		if (smb_delete_check(sr, node) != NT_STATUS_SUCCESS) {
1865772Sas200622 			smb_node_end_crit(node);
1875772Sas200622 			smb_node_release(node);
1885772Sas200622 			goto delete_error;
1895772Sas200622 		}
1905331Samw 
1915331Samw 		if (is_stream) {
1925331Samw 			/*
1935331Samw 			 * It is assumed that fname does not contain
1945331Samw 			 * any wildcards .
1955331Samw 			 * smb_fsop_remove() requires filename+streamname
1965331Samw 			 */
1975331Samw 			(void) snprintf(fullname, MAXPATHLEN, "%s%s",
1985331Samw 			    fname, sname);
1995331Samw 			rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
2005331Samw 			    fullname, 0);
2015331Samw 		} else {
2025331Samw 			/*
2035331Samw 			 * name (i.e. pc->dc_name) is the on-disk name
2045331Samw 			 * unless there is a case collision, in which
2055331Samw 			 * case readdir will have returned a mangled name.
2065331Samw 			 */
2075331Samw 			if (smb_maybe_mangled_name(name) == 0)
2085331Samw 				od = 1;
2095331Samw 
2105331Samw 			rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
2115331Samw 			    name, od);
2125331Samw 		}
2135331Samw 
2145772Sas200622 		smb_node_end_crit(node);
2155772Sas200622 		smb_node_release(node);
2165772Sas200622 		node = NULL;
2175772Sas200622 
2185331Samw 		if (rc != 0) {
219*6139Sjb150015 			if (rc != ENOENT) {
220*6139Sjb150015 				smbsr_errno(sr, rc);
221*6139Sjb150015 				goto delete_error;
222*6139Sjb150015 			}
2235331Samw 		} else {
2245331Samw 			deleted++;
2255331Samw 		}
2265331Samw 	}
2275331Samw 
2285331Samw 	if ((rc != 0) && (rc != ENOENT)) {
229*6139Sjb150015 		smbsr_errno(sr, rc);
230*6139Sjb150015 		goto delete_error;
2315331Samw 	}
2325331Samw 
2335331Samw 	if (deleted == 0) {
234*6139Sjb150015 		if (sr->sid_odir->d_wildcards == 0)
235*6139Sjb150015 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
236*6139Sjb150015 			    ERRDOS, ERROR_FILE_NOT_FOUND);
237*6139Sjb150015 		else
238*6139Sjb150015 			smbsr_error(sr, NT_STATUS_NO_SUCH_FILE,
239*6139Sjb150015 			    ERRDOS, ERROR_FILE_NOT_FOUND);
2405331Samw 		goto delete_error;
2415331Samw 	}
2425331Samw 
2435331Samw 	smb_rdir_close(sr);
2445331Samw 	kmem_free(pc, sizeof (*pc));
2455331Samw 	kmem_free(name, MAXNAMELEN);
2465331Samw 	kmem_free(fname, MAXNAMELEN);
2475331Samw 	kmem_free(sname, MAXNAMELEN);
2485331Samw 	kmem_free(fullname, MAXPATHLEN);
2496030Sjb150015 
2506030Sjb150015 	rc = smbsr_encode_empty_result(sr);
251*6139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
2525331Samw 
2535331Samw delete_error:
2545331Samw 	smb_rdir_close(sr);
2555331Samw 	kmem_free(pc, sizeof (*pc));
2565331Samw 	kmem_free(name, MAXNAMELEN);
2575331Samw 	kmem_free(fname, MAXNAMELEN);
2585331Samw 	kmem_free(sname, MAXNAMELEN);
2595331Samw 	kmem_free(fullname, MAXPATHLEN);
260*6139Sjb150015 	return (SDRC_ERROR);
2615331Samw }
2625331Samw 
263*6139Sjb150015 /*
264*6139Sjb150015  * For consistency with Windows 2000, the range check should be done
265*6139Sjb150015  * after checking for sharing violations.  Attempting to delete a
266*6139Sjb150015  * locked file will result in sharing violation, which is the same
267*6139Sjb150015  * thing that will happen if you try to delete a non-locked open file.
268*6139Sjb150015  *
269*6139Sjb150015  * Note that windows 2000 rejects lock requests on open files that
270*6139Sjb150015  * have been opened with metadata open modes.  The error is
271*6139Sjb150015  * STATUS_ACCESS_DENIED.
272*6139Sjb150015  */
273*6139Sjb150015 static uint32_t
274*6139Sjb150015 smb_delete_check(smb_request_t *sr, smb_node_t *node)
2755331Samw {
276*6139Sjb150015 	uint32_t status;
2775331Samw 
278*6139Sjb150015 	status = smb_node_delete_check(node);
279*6139Sjb150015 
280*6139Sjb150015 	if (status == NT_STATUS_SHARING_VIOLATION) {
281*6139Sjb150015 		smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
282*6139Sjb150015 		    ERRDOS, ERROR_SHARING_VIOLATION);
283*6139Sjb150015 		return (status);
2845331Samw 	}
2855331Samw 
286*6139Sjb150015 	status = smb_range_check(sr, sr->user_cr, node, 0, UINT64_MAX, B_TRUE);
2875772Sas200622 
288*6139Sjb150015 	if (status != NT_STATUS_SUCCESS) {
289*6139Sjb150015 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
290*6139Sjb150015 		    ERRDOS, ERROR_ACCESS_DENIED);
2915331Samw 	}
2925331Samw 
293*6139Sjb150015 	return (status);
2945331Samw }
295