xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_delete.c (revision 6600:4e63bcd27ae9)
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	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;
1225331Samw 	int is_stream;
1235331Samw 	smb_odir_context_t *pc;
1245331Samw 
1256139Sjb150015 	if (smb_rdir_open(sr, fqi->path, fqi->srch_attr) != 0)
1266139Sjb150015 		return (SDRC_ERROR);
1275772Sas200622 
1285331Samw 	pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
1295331Samw 	fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1305331Samw 	sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1315331Samw 	name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1325331Samw 	fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1335331Samw 
1346139Sjb150015 	is_stream = smb_stream_parse_name(fqi->path, fname, sname);
1355331Samw 	dir_snode = sr->sid_odir->d_dir_snode;
1365331Samw 
1375331Samw 	/*
1385331Samw 	 * This while loop is meant to deal with wildcards.
1395331Samw 	 * It is not expected that wildcards will exist for
1405331Samw 	 * streams.  For the streams case, it is expected
1415331Samw 	 * that the below loop will be executed only once.
1425331Samw 	 */
1435331Samw 
1445331Samw 	while ((rc = smb_rdir_next(sr, &node, pc)) == 0) {
1455331Samw 		(void) strlcpy(name, pc->dc_name, MAXNAMELEN);
1465331Samw 
1475772Sas200622 		if (pc->dc_dattr & SMB_FA_DIRECTORY) {
1486139Sjb150015 			smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
1496139Sjb150015 			    ERRDOS, ERROR_ACCESS_DENIED);
1505772Sas200622 			smb_node_release(node);
1515772Sas200622 			goto delete_error;
1525772Sas200622 		}
1535772Sas200622 
1545772Sas200622 		if ((pc->dc_dattr & SMB_FA_READONLY) ||
1555772Sas200622 		    (node->flags & NODE_CREATED_READONLY)) {
1566139Sjb150015 			smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
1576139Sjb150015 			    ERRDOS, ERROR_ACCESS_DENIED);
1585331Samw 			smb_node_release(node);
1595331Samw 			goto delete_error;
1605331Samw 		}
1615331Samw 
1625772Sas200622 		/*
1635772Sas200622 		 * NT does not always close a file immediately, which
1645772Sas200622 		 * can cause the share and access checking to fail
1655772Sas200622 		 * (the node refcnt is greater than one), and the file
1665772Sas200622 		 * doesn't get deleted. Breaking the oplock before
1675772Sas200622 		 * share and access checking gives the client a chance
1685772Sas200622 		 * to close the file.
1695772Sas200622 		 */
1705772Sas200622 
171*6600Sas200622 		smb_oplock_break(node);
1725772Sas200622 
1735772Sas200622 		smb_node_start_crit(node, RW_READER);
1745772Sas200622 
1756139Sjb150015 		if (smb_delete_check(sr, node) != NT_STATUS_SUCCESS) {
1765772Sas200622 			smb_node_end_crit(node);
1775772Sas200622 			smb_node_release(node);
1785772Sas200622 			goto delete_error;
1795772Sas200622 		}
1805331Samw 
1815331Samw 		if (is_stream) {
1825331Samw 			/*
1835331Samw 			 * It is assumed that fname does not contain
1845331Samw 			 * any wildcards .
1855331Samw 			 * smb_fsop_remove() requires filename+streamname
1865331Samw 			 */
1875331Samw 			(void) snprintf(fullname, MAXPATHLEN, "%s%s",
1885331Samw 			    fname, sname);
1895331Samw 			rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
1905331Samw 			    fullname, 0);
1915331Samw 		} else {
1925331Samw 			/*
1935331Samw 			 * name (i.e. pc->dc_name) is the on-disk name
1945331Samw 			 * unless there is a case collision, in which
1955331Samw 			 * case readdir will have returned a mangled name.
1965331Samw 			 */
1975331Samw 			if (smb_maybe_mangled_name(name) == 0)
1985331Samw 				od = 1;
1995331Samw 
2005331Samw 			rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
2015331Samw 			    name, od);
2025331Samw 		}
2035331Samw 
2045772Sas200622 		smb_node_end_crit(node);
2055772Sas200622 		smb_node_release(node);
2065772Sas200622 		node = NULL;
2075772Sas200622 
2085331Samw 		if (rc != 0) {
2096139Sjb150015 			if (rc != ENOENT) {
2106139Sjb150015 				smbsr_errno(sr, rc);
2116139Sjb150015 				goto delete_error;
2126139Sjb150015 			}
2135331Samw 		} else {
2145331Samw 			deleted++;
2155331Samw 		}
2165331Samw 	}
2175331Samw 
2185331Samw 	if ((rc != 0) && (rc != ENOENT)) {
2196139Sjb150015 		smbsr_errno(sr, rc);
2206139Sjb150015 		goto delete_error;
2215331Samw 	}
2225331Samw 
2235331Samw 	if (deleted == 0) {
2246139Sjb150015 		if (sr->sid_odir->d_wildcards == 0)
2256139Sjb150015 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
2266139Sjb150015 			    ERRDOS, ERROR_FILE_NOT_FOUND);
2276139Sjb150015 		else
2286139Sjb150015 			smbsr_error(sr, NT_STATUS_NO_SUCH_FILE,
2296139Sjb150015 			    ERRDOS, ERROR_FILE_NOT_FOUND);
2305331Samw 		goto delete_error;
2315331Samw 	}
2325331Samw 
2335331Samw 	smb_rdir_close(sr);
2345331Samw 	kmem_free(pc, sizeof (*pc));
2355331Samw 	kmem_free(name, MAXNAMELEN);
2365331Samw 	kmem_free(fname, MAXNAMELEN);
2375331Samw 	kmem_free(sname, MAXNAMELEN);
2385331Samw 	kmem_free(fullname, MAXPATHLEN);
2396030Sjb150015 
2406030Sjb150015 	rc = smbsr_encode_empty_result(sr);
2416139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
2425331Samw 
2435331Samw delete_error:
2445331Samw 	smb_rdir_close(sr);
2455331Samw 	kmem_free(pc, sizeof (*pc));
2465331Samw 	kmem_free(name, MAXNAMELEN);
2475331Samw 	kmem_free(fname, MAXNAMELEN);
2485331Samw 	kmem_free(sname, MAXNAMELEN);
2495331Samw 	kmem_free(fullname, MAXPATHLEN);
2506139Sjb150015 	return (SDRC_ERROR);
2515331Samw }
2525331Samw 
2536139Sjb150015 /*
2546139Sjb150015  * For consistency with Windows 2000, the range check should be done
2556139Sjb150015  * after checking for sharing violations.  Attempting to delete a
2566139Sjb150015  * locked file will result in sharing violation, which is the same
2576139Sjb150015  * thing that will happen if you try to delete a non-locked open file.
2586139Sjb150015  *
2596139Sjb150015  * Note that windows 2000 rejects lock requests on open files that
2606139Sjb150015  * have been opened with metadata open modes.  The error is
2616139Sjb150015  * STATUS_ACCESS_DENIED.
2626139Sjb150015  */
2636139Sjb150015 static uint32_t
2646139Sjb150015 smb_delete_check(smb_request_t *sr, smb_node_t *node)
2655331Samw {
2666139Sjb150015 	uint32_t status;
2675331Samw 
2686139Sjb150015 	status = smb_node_delete_check(node);
2696139Sjb150015 
2706139Sjb150015 	if (status == NT_STATUS_SHARING_VIOLATION) {
2716139Sjb150015 		smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
2726139Sjb150015 		    ERRDOS, ERROR_SHARING_VIOLATION);
2736139Sjb150015 		return (status);
2745331Samw 	}
2755331Samw 
2766139Sjb150015 	status = smb_range_check(sr, sr->user_cr, node, 0, UINT64_MAX, B_TRUE);
2775772Sas200622 
2786139Sjb150015 	if (status != NT_STATUS_SUCCESS) {
2796139Sjb150015 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
2806139Sjb150015 		    ERRDOS, ERROR_ACCESS_DENIED);
2815331Samw 	}
2825331Samw 
2836139Sjb150015 	return (status);
2845331Samw }
285