xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_delete.c (revision 5772:237ac22142fe)
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 /*
22*5772Sas200622  * 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>
31*5772Sas200622 #include <sys/nbmlock.h>
325331Samw 
33*5772Sas200622 static uint32_t smb_delete_check(smb_request_t *sr, smb_node_t *node,
34*5772Sas200622     smb_error_t *smberr);
355331Samw 
365331Samw /*
375331Samw  * smb_com_delete
385331Samw  *
395331Samw  * The delete file message is sent to delete a data file. The appropriate
405331Samw  * Tid and additional pathname are passed. Read only files may not be
415331Samw  * deleted, the read-only attribute must be reset prior to file deletion.
425331Samw  *
435331Samw  * NT supports a hidden permission known as File Delete Child (FDC). If
445331Samw  * the user has FullControl access to a directory, the user is permitted
455331Samw  * to delete any object in the directory regardless of the permissions
465331Samw  * on the object.
475331Samw  *
485331Samw  * Client Request                     Description
495331Samw  * ================================== =================================
505331Samw  * UCHAR WordCount;                   Count of parameter words = 1
515331Samw  * USHORT SearchAttributes;
525331Samw  * USHORT ByteCount;                  Count of data bytes; min = 2
535331Samw  * UCHAR BufferFormat;                0x04
545331Samw  * STRING FileName[];                 File name
555331Samw  *
565331Samw  * Multiple files may be deleted in response to a single request as
575331Samw  * SMB_COM_DELETE supports wildcards
585331Samw  *
595331Samw  * SearchAttributes indicates the attributes that the target file(s) must
605331Samw  * have. If the attribute is zero then only normal files are deleted. If
615331Samw  * the system file or hidden attributes are specified then the delete is
625331Samw  * inclusive -both the specified type(s) of files and normal files are
635331Samw  * deleted. Attributes are described in the "Attribute Encoding" section
645331Samw  * of this document.
655331Samw  *
665331Samw  * If bit0 of the Flags2 field of the SMB header is set, a pattern is
675331Samw  * passed in, and the file has a long name, then the passed pattern  much
685331Samw  * match the long file name for the delete to succeed. If bit0 is clear, a
695331Samw  * pattern is passed in, and the file has a long name, then the passed
705331Samw  * pattern must match the file's short name for the deletion to succeed.
715331Samw  *
725331Samw  * Server Response                    Description
735331Samw  * ================================== =================================
745331Samw  * UCHAR WordCount;                   Count of parameter words = 0
755331Samw  * USHORT ByteCount;                  Count of data bytes = 0
765331Samw  *
775331Samw  * 4.2.10.1  Errors
785331Samw  *
795331Samw  * ERRDOS/ERRbadpath
805331Samw  * ERRDOS/ERRbadfile
815331Samw  * ERRDOS/ERRnoaccess
825331Samw  * ERRDOS/ERRbadshare	# returned by NT for files that are already open
835331Samw  * ERRHRD/ERRnowrite
845331Samw  * ERRSRV/ERRaccess
855331Samw  * ERRSRV/ERRinvdevice
865331Samw  * ERRSRV/ERRinvid
875331Samw  * ERRSRV/ERRbaduid
885331Samw  */
895331Samw int
905331Samw smb_com_delete(struct smb_request *sr)
915331Samw {
925331Samw 	int	rc;
935331Samw 	int	od = 0;
945331Samw 	int	deleted = 0;
955331Samw 	unsigned short sattr;
965331Samw 	char *path;
975331Samw 	struct smb_node *dir_snode;
985331Samw 	struct smb_node *node = 0;
995331Samw 	char *name;
1005331Samw 	char *fname;
1015331Samw 	char *sname;
1025331Samw 	char *fullname;
1035331Samw 	smb_error_t smberr;
1045331Samw 	int is_stream;
1055331Samw 	smb_odir_context_t *pc;
1065331Samw 
107*5772Sas200622 	if (smbsr_decode_vwv(sr, "w", &sattr) != 0) {
108*5772Sas200622 		smbsr_decode_error(sr);
109*5772Sas200622 		/* NOTREACHED */
110*5772Sas200622 	}
111*5772Sas200622 
112*5772Sas200622 	if (smbsr_decode_data(sr, "%S", sr, &path) != 0) {
113*5772Sas200622 		smbsr_decode_error(sr);
114*5772Sas200622 		/* NOTREACHED */
115*5772Sas200622 	}
116*5772Sas200622 
1175331Samw 	pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
1185331Samw 	fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1195331Samw 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1205331Samw 	name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1215331Samw 	fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1225331Samw 
1235331Samw 	is_stream = smb_stream_parse_name(path, fname, sname);
1245331Samw 
1255331Samw 	(void) smb_rdir_open(sr, path, sattr);
1265331Samw 	dir_snode = sr->sid_odir->d_dir_snode;
1275331Samw 
1285331Samw 	/*
1295331Samw 	 * This while loop is meant to deal with wildcards.
1305331Samw 	 * It is not expected that wildcards will exist for
1315331Samw 	 * streams.  For the streams case, it is expected
1325331Samw 	 * that the below loop will be executed only once.
1335331Samw 	 */
1345331Samw 
1355331Samw 	while ((rc = smb_rdir_next(sr, &node, pc)) == 0) {
1365331Samw 		(void) strlcpy(name, pc->dc_name, MAXNAMELEN);
1375331Samw 
138*5772Sas200622 		if (pc->dc_dattr & SMB_FA_DIRECTORY) {
139*5772Sas200622 			smberr.errcls = ERRDOS;
140*5772Sas200622 			smberr.errcode = ERROR_ACCESS_DENIED;
141*5772Sas200622 			smberr.status = NT_STATUS_FILE_IS_A_DIRECTORY;
142*5772Sas200622 			smb_node_release(node);
143*5772Sas200622 			goto delete_error;
144*5772Sas200622 		}
145*5772Sas200622 
146*5772Sas200622 		if ((pc->dc_dattr & SMB_FA_READONLY) ||
147*5772Sas200622 		    (node->flags & NODE_CREATED_READONLY)) {
148*5772Sas200622 			smberr.errcls = ERRDOS;
149*5772Sas200622 			smberr.errcode = ERROR_ACCESS_DENIED;
150*5772Sas200622 			smberr.status = NT_STATUS_CANNOT_DELETE;
1515331Samw 			smb_node_release(node);
1525331Samw 			goto delete_error;
1535331Samw 		}
1545331Samw 
155*5772Sas200622 		/*
156*5772Sas200622 		 * NT does not always close a file immediately, which
157*5772Sas200622 		 * can cause the share and access checking to fail
158*5772Sas200622 		 * (the node refcnt is greater than one), and the file
159*5772Sas200622 		 * doesn't get deleted. Breaking the oplock before
160*5772Sas200622 		 * share and access checking gives the client a chance
161*5772Sas200622 		 * to close the file.
162*5772Sas200622 		 */
163*5772Sas200622 
164*5772Sas200622 		if (OPLOCKS_IN_FORCE(node)) {
165*5772Sas200622 			smberr.status = smb_break_oplock(sr, node);
166*5772Sas200622 
167*5772Sas200622 			if (smberr.status != NT_STATUS_SUCCESS) {
168*5772Sas200622 				smberr.errcls = ERRDOS;
169*5772Sas200622 				smberr.errcode = ERROR_VC_DISCONNECTED;
170*5772Sas200622 				smb_node_release(node);
171*5772Sas200622 				goto delete_error;
172*5772Sas200622 			}
173*5772Sas200622 		}
174*5772Sas200622 
175*5772Sas200622 		smb_node_start_crit(node, RW_READER);
176*5772Sas200622 
177*5772Sas200622 		if (smb_delete_check(sr, node, &smberr)) {
178*5772Sas200622 			smb_node_end_crit(node);
179*5772Sas200622 			smb_node_release(node);
180*5772Sas200622 			goto delete_error;
181*5772Sas200622 		}
1825331Samw 
1835331Samw 		if (is_stream) {
1845331Samw 			/*
1855331Samw 			 * It is assumed that fname does not contain
1865331Samw 			 * any wildcards .
1875331Samw 			 * smb_fsop_remove() requires filename+streamname
1885331Samw 			 */
1895331Samw 			(void) snprintf(fullname, MAXPATHLEN, "%s%s",
1905331Samw 			    fname, sname);
1915331Samw 			rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
1925331Samw 			    fullname, 0);
1935331Samw 		} else {
1945331Samw 			/*
1955331Samw 			 * name (i.e. pc->dc_name) is the on-disk name
1965331Samw 			 * unless there is a case collision, in which
1975331Samw 			 * case readdir will have returned a mangled name.
1985331Samw 			 */
1995331Samw 			if (smb_maybe_mangled_name(name) == 0)
2005331Samw 				od = 1;
2015331Samw 
2025331Samw 			rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
2035331Samw 			    name, od);
2045331Samw 		}
2055331Samw 
206*5772Sas200622 		smb_node_end_crit(node);
207*5772Sas200622 		smb_node_release(node);
208*5772Sas200622 		node = NULL;
209*5772Sas200622 
2105331Samw 		if (rc != 0) {
2115331Samw 			if (rc != ENOENT) {
2125331Samw 				smb_rdir_close(sr);
2135331Samw 				kmem_free(pc, sizeof (*pc));
2145331Samw 				kmem_free(name, MAXNAMELEN);
2155331Samw 				kmem_free(fname, MAXNAMELEN);
2165331Samw 				kmem_free(sname, MAXNAMELEN);
2175331Samw 				kmem_free(fullname, MAXPATHLEN);
218*5772Sas200622 				smbsr_errno(sr, rc);
2195331Samw 				/* NOTREACHED */
2205331Samw 			}
2215331Samw 		} else {
2225331Samw 			deleted++;
2235331Samw 		}
2245331Samw 	}
2255331Samw 
2265331Samw 	if ((rc != 0) && (rc != ENOENT)) {
2275331Samw 		/* rc returned by smb_rdir_next() */
2285331Samw 		smb_rdir_close(sr);
2295331Samw 		kmem_free(pc, sizeof (*pc));
2305331Samw 		kmem_free(name, MAXNAMELEN);
2315331Samw 		kmem_free(fname, MAXNAMELEN);
2325331Samw 		kmem_free(sname, MAXNAMELEN);
2335331Samw 		kmem_free(fullname, MAXPATHLEN);
234*5772Sas200622 		smbsr_errno(sr, rc);
2355331Samw 		/* NOTREACHED */
2365331Samw 	}
2375331Samw 
2385331Samw 	if (deleted == 0) {
2395331Samw 		smberr.errcls = ERRDOS;
2405331Samw 		smberr.errcode = ERROR_FILE_NOT_FOUND;
2415331Samw 		smberr.status = (sr->sid_odir->d_wildcards == 0)
2425331Samw 		    ? NT_STATUS_OBJECT_NAME_NOT_FOUND : NT_STATUS_NO_SUCH_FILE;
2435331Samw 		goto delete_error;
2445331Samw 	}
2455331Samw 
2465331Samw 	smb_rdir_close(sr);
2475331Samw 
2485331Samw 	smbsr_encode_empty_result(sr);
2495331Samw 
2505331Samw 	kmem_free(pc, sizeof (*pc));
2515331Samw 	kmem_free(name, MAXNAMELEN);
2525331Samw 	kmem_free(fname, MAXNAMELEN);
2535331Samw 	kmem_free(sname, MAXNAMELEN);
2545331Samw 	kmem_free(fullname, MAXPATHLEN);
2555331Samw 	return (SDRC_NORMAL_REPLY);
2565331Samw 
2575331Samw delete_error:
2585331Samw 	smb_rdir_close(sr);
2595331Samw 	kmem_free(pc, sizeof (*pc));
2605331Samw 	kmem_free(name, MAXNAMELEN);
2615331Samw 	kmem_free(fname, MAXNAMELEN);
2625331Samw 	kmem_free(sname, MAXNAMELEN);
2635331Samw 	kmem_free(fullname, MAXPATHLEN);
264*5772Sas200622 	smbsr_error(sr, smberr.status, smberr.errcls, smberr.errcode);
2655331Samw 	/* NOTREACHED */
2665331Samw 	return (SDRC_NORMAL_REPLY); /* compiler complains otherwise */
2675331Samw }
2685331Samw 
269*5772Sas200622 uint32_t
270*5772Sas200622 smb_delete_check(smb_request_t *sr, smb_node_t *node, smb_error_t *smberr)
2715331Samw {
272*5772Sas200622 	smberr->status = smb_node_delete_check(node);
2735331Samw 
2745331Samw 	if (smberr->status == NT_STATUS_SHARING_VIOLATION) {
2755331Samw 		smberr->errcls = ERRDOS;
2765331Samw 		smberr->errcode = ERROR_SHARING_VIOLATION;
277*5772Sas200622 		return (smberr->status);
2785331Samw 	}
2795331Samw 
2805331Samw 	/*
2815331Samw 	 * This should be done after Share checking due to tests with
2825331Samw 	 * W2K. I got sharing violation error trying to delete a
2835331Samw 	 * locked file which is basically the same error if you
2845331Samw 	 * try to delete a non-locked open file.
2855331Samw 	 *
2865331Samw 	 * One thing that I discovered during these tests is that
2875331Samw 	 * W2K rejects lock requests on open files which are opened
2885331Samw 	 * with Metadata open modes. The error is STATUS_ACCESS_DENIED.
2895331Samw 	 */
290*5772Sas200622 
291*5772Sas200622 	smberr->status = smb_range_check(sr, sr->user_cr, node, 0,
292*5772Sas200622 	    UINT64_MAX, B_TRUE);
293*5772Sas200622 
294*5772Sas200622 	if (smberr->status != NT_STATUS_SUCCESS) {
2955331Samw 		smberr->errcls = ERRDOS;
2965331Samw 		smberr->errcode = ERROR_ACCESS_DENIED;
2975331Samw 		smberr->status = NT_STATUS_ACCESS_DENIED;
2985331Samw 	}
2995331Samw 
300*5772Sas200622 	return (smberr->status);
3015331Samw }
302