xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_delete.c (revision 10966:37e5dcdf36d3)
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 /*
228670SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
26*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
275331Samw #include <smbsrv/smb_fsops.h>
285331Samw #include <smbsrv/smbinfo.h>
295772Sas200622 #include <sys/nbmlock.h>
305331Samw 
317961SNatalie.Li@Sun.COM static int smb_delete_check_path(smb_request_t *, boolean_t *);
327961SNatalie.Li@Sun.COM static int smb_delete_single_file(smb_request_t *, smb_error_t *);
337961SNatalie.Li@Sun.COM static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
3410504SKeyur.Desai@Sun.COM static int smb_delete_find_fname(smb_request_t *, smb_odir_t *, char *, int);
3510001SJoyce.McIntosh@Sun.COM static int smb_delete_check_dosattr(smb_request_t *, smb_error_t *);
367961SNatalie.Li@Sun.COM static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
377961SNatalie.Li@Sun.COM 
387961SNatalie.Li@Sun.COM static void smb_delete_error(smb_error_t *, uint32_t, uint16_t, uint16_t);
395331Samw 
405331Samw /*
415331Samw  * smb_com_delete
425331Samw  *
435331Samw  * The delete file message is sent to delete a data file. The appropriate
445331Samw  * Tid and additional pathname are passed. Read only files may not be
455331Samw  * deleted, the read-only attribute must be reset prior to file deletion.
465331Samw  *
475331Samw  * NT supports a hidden permission known as File Delete Child (FDC). If
485331Samw  * the user has FullControl access to a directory, the user is permitted
495331Samw  * to delete any object in the directory regardless of the permissions
505331Samw  * on the object.
515331Samw  *
525331Samw  * Client Request                     Description
535331Samw  * ================================== =================================
545331Samw  * UCHAR WordCount;                   Count of parameter words = 1
555331Samw  * USHORT SearchAttributes;
565331Samw  * USHORT ByteCount;                  Count of data bytes; min = 2
575331Samw  * UCHAR BufferFormat;                0x04
585331Samw  * STRING FileName[];                 File name
595331Samw  *
605331Samw  * Multiple files may be deleted in response to a single request as
615331Samw  * SMB_COM_DELETE supports wildcards
625331Samw  *
635331Samw  * SearchAttributes indicates the attributes that the target file(s) must
645331Samw  * have. If the attribute is zero then only normal files are deleted. If
655331Samw  * the system file or hidden attributes are specified then the delete is
665331Samw  * inclusive -both the specified type(s) of files and normal files are
675331Samw  * deleted. Attributes are described in the "Attribute Encoding" section
685331Samw  * of this document.
695331Samw  *
705331Samw  * If bit0 of the Flags2 field of the SMB header is set, a pattern is
715331Samw  * passed in, and the file has a long name, then the passed pattern  much
725331Samw  * match the long file name for the delete to succeed. If bit0 is clear, a
735331Samw  * pattern is passed in, and the file has a long name, then the passed
745331Samw  * pattern must match the file's short name for the deletion to succeed.
755331Samw  *
765331Samw  * Server Response                    Description
775331Samw  * ================================== =================================
785331Samw  * UCHAR WordCount;                   Count of parameter words = 0
795331Samw  * USHORT ByteCount;                  Count of data bytes = 0
805331Samw  *
815331Samw  * 4.2.10.1  Errors
825331Samw  *
835331Samw  * ERRDOS/ERRbadpath
845331Samw  * ERRDOS/ERRbadfile
855331Samw  * ERRDOS/ERRnoaccess
865331Samw  * ERRDOS/ERRbadshare	# returned by NT for files that are already open
875331Samw  * ERRHRD/ERRnowrite
885331Samw  * ERRSRV/ERRaccess
895331Samw  * ERRSRV/ERRinvdevice
905331Samw  * ERRSRV/ERRinvid
915331Samw  * ERRSRV/ERRbaduid
925331Samw  */
936030Sjb150015 smb_sdrc_t
946139Sjb150015 smb_pre_delete(smb_request_t *sr)
955331Samw {
966139Sjb150015 	int rc;
977961SNatalie.Li@Sun.COM 	smb_fqi_t *fqi;
987961SNatalie.Li@Sun.COM 
997961SNatalie.Li@Sun.COM 	fqi = &sr->arg.dirop.fqi;
1006139Sjb150015 
1019343SAfshin.Ardakani@Sun.COM 	if ((rc = smbsr_decode_vwv(sr, "w", &fqi->fq_sattr)) == 0)
1029343SAfshin.Ardakani@Sun.COM 		rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
1036139Sjb150015 
1047961SNatalie.Li@Sun.COM 	DTRACE_SMB_2(op__Delete__start, smb_request_t *, sr, smb_fqi_t *, fqi);
1056139Sjb150015 
1066139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1076139Sjb150015 }
1086139Sjb150015 
1096139Sjb150015 void
1106139Sjb150015 smb_post_delete(smb_request_t *sr)
1116139Sjb150015 {
1126139Sjb150015 	DTRACE_SMB_1(op__Delete__done, smb_request_t *, sr);
1136139Sjb150015 }
1146139Sjb150015 
1157348SJose.Borrego@Sun.COM /*
1167348SJose.Borrego@Sun.COM  * smb_com_delete
1177348SJose.Borrego@Sun.COM  *
1187961SNatalie.Li@Sun.COM  * 1. pre-process pathname -  smb_delete_check_path()
1197961SNatalie.Li@Sun.COM  *    checks dot, bad path syntax, wildcards in path
1207348SJose.Borrego@Sun.COM  *
1217961SNatalie.Li@Sun.COM  * 2. process the path to get directory node & last_comp,
1227961SNatalie.Li@Sun.COM  *    store these in fqi
1237961SNatalie.Li@Sun.COM  *    - If smb_pathname_reduce cannot find the specified path,
1247961SNatalie.Li@Sun.COM  *      the error (ENOTDIR) is translated to NT_STATUS_OBJECT_PATH_NOT_FOUND
1257961SNatalie.Li@Sun.COM  *      if the target is a single file (no wildcards).  If there are
1267961SNatalie.Li@Sun.COM  *      wildcards in the last_comp, NT_STATUS_OBJECT_NAME_NOT_FOUND is
1277961SNatalie.Li@Sun.COM  *      used instead.
1287961SNatalie.Li@Sun.COM  *    - If the directory node is the mount point and the last component
1297961SNatalie.Li@Sun.COM  *      is ".." NT_STATUS_OBJECT_PATH_SYNTAX_BAD is returned.
1307348SJose.Borrego@Sun.COM  *
1317961SNatalie.Li@Sun.COM  * 3. check access permissions
1327348SJose.Borrego@Sun.COM  *
1337961SNatalie.Li@Sun.COM  * 4. invoke the appropriate deletion routine to find and remove
1347961SNatalie.Li@Sun.COM  *    the specified file(s).
1357961SNatalie.Li@Sun.COM  *    - if target is a single file (no wildcards) - smb_delete_single_file
1367961SNatalie.Li@Sun.COM  *    - if the target contains wildcards - smb_delete_multiple_files
1377961SNatalie.Li@Sun.COM  *
1387961SNatalie.Li@Sun.COM  * Returns: SDRC_SUCCESS or SDRC_ERROR
1397348SJose.Borrego@Sun.COM  */
1406139Sjb150015 smb_sdrc_t
1416139Sjb150015 smb_com_delete(smb_request_t *sr)
1426139Sjb150015 {
1437348SJose.Borrego@Sun.COM 	int rc;
1447961SNatalie.Li@Sun.COM 	smb_error_t err;
1457961SNatalie.Li@Sun.COM 	uint32_t status;
1467348SJose.Borrego@Sun.COM 	boolean_t wildcards;
1477961SNatalie.Li@Sun.COM 	smb_fqi_t *fqi;
1485331Samw 
1497961SNatalie.Li@Sun.COM 	fqi = &sr->arg.dirop.fqi;
1507961SNatalie.Li@Sun.COM 
1517961SNatalie.Li@Sun.COM 	if (smb_delete_check_path(sr, &wildcards) != 0)
1526139Sjb150015 		return (SDRC_ERROR);
1535772Sas200622 
1549343SAfshin.Ardakani@Sun.COM 	rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
1557961SNatalie.Li@Sun.COM 	    sr->tid_tree->t_snode, sr->tid_tree->t_snode,
1569343SAfshin.Ardakani@Sun.COM 	    &fqi->fq_dnode, fqi->fq_last_comp);
1577961SNatalie.Li@Sun.COM 	if (rc == 0) {
1589343SAfshin.Ardakani@Sun.COM 		if (fqi->fq_dnode->vp->v_type != VDIR) {
1599343SAfshin.Ardakani@Sun.COM 			smb_node_release(fqi->fq_dnode);
1607961SNatalie.Li@Sun.COM 			rc = ENOTDIR;
1617961SNatalie.Li@Sun.COM 		}
1627961SNatalie.Li@Sun.COM 	}
1637961SNatalie.Li@Sun.COM 	if (rc != 0) {
1647961SNatalie.Li@Sun.COM 		if (rc == ENOTDIR) {
1657961SNatalie.Li@Sun.COM 			if (wildcards)
1667961SNatalie.Li@Sun.COM 				status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1677961SNatalie.Li@Sun.COM 			else
1687961SNatalie.Li@Sun.COM 				status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1697961SNatalie.Li@Sun.COM 			smbsr_error(sr, status, ERRDOS, ERROR_FILE_NOT_FOUND);
1707961SNatalie.Li@Sun.COM 		} else {
1717961SNatalie.Li@Sun.COM 			smbsr_errno(sr, rc);
1727348SJose.Borrego@Sun.COM 		}
1737348SJose.Borrego@Sun.COM 
1747348SJose.Borrego@Sun.COM 		return (SDRC_ERROR);
1757348SJose.Borrego@Sun.COM 	}
1767348SJose.Borrego@Sun.COM 
1779343SAfshin.Ardakani@Sun.COM 	if ((fqi->fq_dnode == sr->tid_tree->t_snode) &&
1789343SAfshin.Ardakani@Sun.COM 	    (strcmp(fqi->fq_last_comp, "..") == 0)) {
1799343SAfshin.Ardakani@Sun.COM 		smb_node_release(fqi->fq_dnode);
1807961SNatalie.Li@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
1817961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_BAD_PATHNAME);
1827961SNatalie.Li@Sun.COM 		return (SDRC_ERROR);
1837961SNatalie.Li@Sun.COM 	}
1847961SNatalie.Li@Sun.COM 
1859343SAfshin.Ardakani@Sun.COM 	rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode,
1867961SNatalie.Li@Sun.COM 	    FILE_LIST_DIRECTORY);
1877961SNatalie.Li@Sun.COM 	if (rc != 0) {
1889343SAfshin.Ardakani@Sun.COM 		smb_node_release(fqi->fq_dnode);
1897961SNatalie.Li@Sun.COM 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
1907961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_ACCESS_DENIED);
1917961SNatalie.Li@Sun.COM 		return (SDRC_ERROR);
1927961SNatalie.Li@Sun.COM 	}
1937961SNatalie.Li@Sun.COM 
1947961SNatalie.Li@Sun.COM 	if (wildcards)
1957961SNatalie.Li@Sun.COM 		rc = smb_delete_multiple_files(sr, &err);
1967961SNatalie.Li@Sun.COM 	else
1977961SNatalie.Li@Sun.COM 		rc = smb_delete_single_file(sr, &err);
1987961SNatalie.Li@Sun.COM 
1999343SAfshin.Ardakani@Sun.COM 	smb_node_release(fqi->fq_dnode);
2008026SJoyce.McIntosh@Sun.COM 
2017961SNatalie.Li@Sun.COM 	if (rc != 0)
2027961SNatalie.Li@Sun.COM 		smbsr_set_error(sr, &err);
2037961SNatalie.Li@Sun.COM 	else
2047961SNatalie.Li@Sun.COM 		rc = smbsr_encode_empty_result(sr);
2055331Samw 
2067961SNatalie.Li@Sun.COM 	return (rc == 0 ? SDRC_SUCCESS : SDRC_ERROR);
2077961SNatalie.Li@Sun.COM }
2087961SNatalie.Li@Sun.COM 
2097961SNatalie.Li@Sun.COM /*
2107961SNatalie.Li@Sun.COM  * smb_delete_single_file
2117961SNatalie.Li@Sun.COM  *
2127961SNatalie.Li@Sun.COM  * Find the specified file and, if its attributes match the search
2137961SNatalie.Li@Sun.COM  * criteria, delete it.
2147961SNatalie.Li@Sun.COM  *
2157961SNatalie.Li@Sun.COM  * Returns 0 - success (file deleted)
2167961SNatalie.Li@Sun.COM  *        -1 - error, err is populated with error details
2177961SNatalie.Li@Sun.COM  */
2187961SNatalie.Li@Sun.COM static int
2197961SNatalie.Li@Sun.COM smb_delete_single_file(smb_request_t *sr, smb_error_t *err)
2207961SNatalie.Li@Sun.COM {
2217961SNatalie.Li@Sun.COM 	smb_fqi_t *fqi;
2228334SJose.Borrego@Sun.COM 	uint32_t status;
2237961SNatalie.Li@Sun.COM 
2247961SNatalie.Li@Sun.COM 	fqi = &sr->arg.dirop.fqi;
2257961SNatalie.Li@Sun.COM 
2269343SAfshin.Ardakani@Sun.COM 	smb_pathname_setup(sr, &fqi->fq_path);
2279343SAfshin.Ardakani@Sun.COM 	status = smb_validate_object_name(&fqi->fq_path);
2288334SJose.Borrego@Sun.COM 	if (status != NT_STATUS_SUCCESS) {
2298334SJose.Borrego@Sun.COM 		smb_delete_error(err, status, ERRDOS, ERROR_INVALID_NAME);
2308334SJose.Borrego@Sun.COM 		return (-1);
2318334SJose.Borrego@Sun.COM 	}
2328334SJose.Borrego@Sun.COM 
2337961SNatalie.Li@Sun.COM 	if (smb_fsop_lookup_name(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
23410001SJoyce.McIntosh@Sun.COM 	    fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode) != 0) {
2357961SNatalie.Li@Sun.COM 		smb_delete_error(err, NT_STATUS_OBJECT_NAME_NOT_FOUND,
2367961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_FILE_NOT_FOUND);
2377961SNatalie.Li@Sun.COM 		return (-1);
2387961SNatalie.Li@Sun.COM 	}
2395331Samw 
24010001SJoyce.McIntosh@Sun.COM 	if (smb_delete_check_dosattr(sr, err) != 0) {
2419343SAfshin.Ardakani@Sun.COM 		smb_node_release(fqi->fq_fnode);
2427961SNatalie.Li@Sun.COM 		return (-1);
2437961SNatalie.Li@Sun.COM 	}
2447961SNatalie.Li@Sun.COM 
2457961SNatalie.Li@Sun.COM 	if (smb_delete_remove_file(sr, err) != 0) {
2469343SAfshin.Ardakani@Sun.COM 		smb_node_release(fqi->fq_fnode);
2477961SNatalie.Li@Sun.COM 		return (-1);
2487961SNatalie.Li@Sun.COM 	}
2497961SNatalie.Li@Sun.COM 
2509343SAfshin.Ardakani@Sun.COM 	smb_node_release(fqi->fq_fnode);
2517961SNatalie.Li@Sun.COM 	return (0);
2527961SNatalie.Li@Sun.COM }
2537961SNatalie.Li@Sun.COM 
2547961SNatalie.Li@Sun.COM /*
2557961SNatalie.Li@Sun.COM  * smb_delete_multiple_files
2567961SNatalie.Li@Sun.COM  *
2578670SJose.Borrego@Sun.COM  * For each matching file found by smb_delete_find_fname:
2587961SNatalie.Li@Sun.COM  * 1. lookup file
2597961SNatalie.Li@Sun.COM  * 2. check the file's attributes
2607961SNatalie.Li@Sun.COM  *    - The search ends with an error if a readonly file
2617961SNatalie.Li@Sun.COM  *      (NT_STATUS_CANNOT_DELETE) is matched.
2627961SNatalie.Li@Sun.COM  *    - The search ends (but not an error) if a directory is
2637961SNatalie.Li@Sun.COM  *      matched and the request's search did not include
2647961SNatalie.Li@Sun.COM  *      directories.
26510001SJoyce.McIntosh@Sun.COM  *    - Otherwise, if smb_delete_check_dosattr fails the file
2667961SNatalie.Li@Sun.COM  *      is skipped and the search continues (at step 1)
2677961SNatalie.Li@Sun.COM  * 3. delete the file
2687961SNatalie.Li@Sun.COM  *
2697961SNatalie.Li@Sun.COM  * Returns 0 - success
2707961SNatalie.Li@Sun.COM  *        -1 - error, err is populated with error details
2717961SNatalie.Li@Sun.COM  */
2727961SNatalie.Li@Sun.COM static int
2737961SNatalie.Li@Sun.COM smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
2747961SNatalie.Li@Sun.COM {
2757961SNatalie.Li@Sun.COM 	int rc, deleted = 0;
2767961SNatalie.Li@Sun.COM 	smb_fqi_t *fqi;
2778670SJose.Borrego@Sun.COM 	uint16_t odid;
2788670SJose.Borrego@Sun.COM 	smb_odir_t *od;
27910504SKeyur.Desai@Sun.COM 	char namebuf[MAXNAMELEN];
2807961SNatalie.Li@Sun.COM 
2817961SNatalie.Li@Sun.COM 	fqi = &sr->arg.dirop.fqi;
2827961SNatalie.Li@Sun.COM 
2838670SJose.Borrego@Sun.COM 	/*
2848670SJose.Borrego@Sun.COM 	 * Specify all search attributes (SMB_SEARCH_ATTRIBUTES) so that
28510001SJoyce.McIntosh@Sun.COM 	 * delete-specific checking can be done (smb_delete_check_dosattr).
2868670SJose.Borrego@Sun.COM 	 */
2879343SAfshin.Ardakani@Sun.COM 	odid = smb_odir_open(sr, fqi->fq_path.pn_path,
2889343SAfshin.Ardakani@Sun.COM 	    SMB_SEARCH_ATTRIBUTES, 0);
2899343SAfshin.Ardakani@Sun.COM 	if (odid == 0)
2908670SJose.Borrego@Sun.COM 		return (-1);
2919343SAfshin.Ardakani@Sun.COM 
2928670SJose.Borrego@Sun.COM 	if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL)
2938670SJose.Borrego@Sun.COM 		return (-1);
2948670SJose.Borrego@Sun.COM 
2957961SNatalie.Li@Sun.COM 	for (;;) {
29610504SKeyur.Desai@Sun.COM 		rc = smb_delete_find_fname(sr, od, namebuf, MAXNAMELEN);
2977961SNatalie.Li@Sun.COM 		if (rc != 0)
2987961SNatalie.Li@Sun.COM 			break;
2997961SNatalie.Li@Sun.COM 
3007961SNatalie.Li@Sun.COM 		rc = smb_fsop_lookup_name(sr, sr->user_cr, 0,
3019343SAfshin.Ardakani@Sun.COM 		    sr->tid_tree->t_snode, fqi->fq_dnode,
30210504SKeyur.Desai@Sun.COM 		    namebuf, &fqi->fq_fnode);
3037961SNatalie.Li@Sun.COM 		if (rc != 0)
3047961SNatalie.Li@Sun.COM 			break;
3057961SNatalie.Li@Sun.COM 
30610001SJoyce.McIntosh@Sun.COM 		if (smb_delete_check_dosattr(sr, err) != 0) {
3079343SAfshin.Ardakani@Sun.COM 			smb_node_release(fqi->fq_fnode);
3087961SNatalie.Li@Sun.COM 			if (err->status == NT_STATUS_CANNOT_DELETE) {
3099635SJoyce.McIntosh@Sun.COM 				smb_odir_close(od);
3108670SJose.Borrego@Sun.COM 				smb_odir_release(od);
3117961SNatalie.Li@Sun.COM 				return (-1);
3127348SJose.Borrego@Sun.COM 			}
3137961SNatalie.Li@Sun.COM 			if ((err->status == NT_STATUS_FILE_IS_A_DIRECTORY) &&
3149343SAfshin.Ardakani@Sun.COM 			    (SMB_SEARCH_DIRECTORY(fqi->fq_sattr) != 0))
3157961SNatalie.Li@Sun.COM 				break;
3167961SNatalie.Li@Sun.COM 			continue;
3175772Sas200622 		}
3185772Sas200622 
3197961SNatalie.Li@Sun.COM 		if (smb_delete_remove_file(sr, err) == 0) {
3207961SNatalie.Li@Sun.COM 			++deleted;
3219343SAfshin.Ardakani@Sun.COM 			smb_node_release(fqi->fq_fnode);
3227961SNatalie.Li@Sun.COM 			continue;
3237961SNatalie.Li@Sun.COM 		}
3247961SNatalie.Li@Sun.COM 		if (err->status == NT_STATUS_OBJECT_NAME_NOT_FOUND) {
3259343SAfshin.Ardakani@Sun.COM 			smb_node_release(fqi->fq_fnode);
3267961SNatalie.Li@Sun.COM 			continue;
3275331Samw 		}
3285331Samw 
3299635SJoyce.McIntosh@Sun.COM 		smb_odir_close(od);
3308670SJose.Borrego@Sun.COM 		smb_odir_release(od);
3319343SAfshin.Ardakani@Sun.COM 		smb_node_release(fqi->fq_fnode);
3327961SNatalie.Li@Sun.COM 		return (-1);
3335331Samw 	}
3345331Samw 
3359635SJoyce.McIntosh@Sun.COM 	smb_odir_close(od);
3368670SJose.Borrego@Sun.COM 	smb_odir_release(od);
3377961SNatalie.Li@Sun.COM 
3385331Samw 	if ((rc != 0) && (rc != ENOENT)) {
3397961SNatalie.Li@Sun.COM 		smbsr_map_errno(rc, err);
3407961SNatalie.Li@Sun.COM 		return (-1);
3415331Samw 	}
3425331Samw 
3435331Samw 	if (deleted == 0) {
3447961SNatalie.Li@Sun.COM 		smb_delete_error(err, NT_STATUS_NO_SUCH_FILE,
3457961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_FILE_NOT_FOUND);
3467961SNatalie.Li@Sun.COM 		return (-1);
3477961SNatalie.Li@Sun.COM 	}
3487961SNatalie.Li@Sun.COM 
3497961SNatalie.Li@Sun.COM 	return (0);
3507961SNatalie.Li@Sun.COM }
3517961SNatalie.Li@Sun.COM 
3527961SNatalie.Li@Sun.COM /*
3537961SNatalie.Li@Sun.COM  * smb_delete_find_fname
3547961SNatalie.Li@Sun.COM  *
35510504SKeyur.Desai@Sun.COM  * Find next filename that matches search pattern and return it
35610504SKeyur.Desai@Sun.COM  * in namebuf.
3577961SNatalie.Li@Sun.COM  *
3588670SJose.Borrego@Sun.COM  * Case insensitivity note:
3598670SJose.Borrego@Sun.COM  * If the tree is case insensitive and there's a case conflict
3608670SJose.Borrego@Sun.COM  * with the name returned from smb_odir_read, smb_delete_find_fname
3618670SJose.Borrego@Sun.COM  * performs case conflict name mangling to produce a unique filename.
3628670SJose.Borrego@Sun.COM  * This ensures that any subsequent smb_fsop_lookup, (which will
3638670SJose.Borrego@Sun.COM  * find the first case insensitive match) will find the correct file.
3648670SJose.Borrego@Sun.COM  *
3657961SNatalie.Li@Sun.COM  * Returns: 0 - success
3667961SNatalie.Li@Sun.COM  *          errno
3677961SNatalie.Li@Sun.COM  */
3687961SNatalie.Li@Sun.COM static int
36910504SKeyur.Desai@Sun.COM smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od, char *namebuf, int len)
3707961SNatalie.Li@Sun.COM {
3718670SJose.Borrego@Sun.COM 	int		rc;
3728670SJose.Borrego@Sun.COM 	smb_odirent_t	*odirent;
3738670SJose.Borrego@Sun.COM 	boolean_t	eos;
3748670SJose.Borrego@Sun.COM 	char		*name;
3758670SJose.Borrego@Sun.COM 	char		shortname[SMB_SHORTNAMELEN];
3768670SJose.Borrego@Sun.COM 	char		name83[SMB_SHORTNAMELEN];
3777961SNatalie.Li@Sun.COM 
3788670SJose.Borrego@Sun.COM 	odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
3797961SNatalie.Li@Sun.COM 
3808670SJose.Borrego@Sun.COM 	rc = smb_odir_read(sr, od, odirent, &eos);
3818670SJose.Borrego@Sun.COM 	if (rc != 0) {
3828670SJose.Borrego@Sun.COM 		kmem_free(odirent, sizeof (smb_odirent_t));
3838670SJose.Borrego@Sun.COM 		return (rc);
3848670SJose.Borrego@Sun.COM 	}
3858670SJose.Borrego@Sun.COM 	if (eos) {
3868670SJose.Borrego@Sun.COM 		kmem_free(odirent, sizeof (smb_odirent_t));
3878670SJose.Borrego@Sun.COM 		return (ENOENT);
3888670SJose.Borrego@Sun.COM 	}
3897961SNatalie.Li@Sun.COM 
3908670SJose.Borrego@Sun.COM 	/* if case conflict, force mangle and use shortname */
3919231SAfshin.Ardakani@Sun.COM 	if ((od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) &&
3929231SAfshin.Ardakani@Sun.COM 	    (odirent->od_eflags & ED_CASE_CONFLICT)) {
3938670SJose.Borrego@Sun.COM 		(void) smb_mangle_name(odirent->od_ino, odirent->od_name,
3948670SJose.Borrego@Sun.COM 		    shortname, name83, 1);
3958670SJose.Borrego@Sun.COM 		name = shortname;
3968670SJose.Borrego@Sun.COM 	} else {
3978670SJose.Borrego@Sun.COM 		name = odirent->od_name;
3988670SJose.Borrego@Sun.COM 	}
39910504SKeyur.Desai@Sun.COM 	(void) strlcpy(namebuf, name, len);
4007961SNatalie.Li@Sun.COM 
4018670SJose.Borrego@Sun.COM 	kmem_free(odirent, sizeof (smb_odirent_t));
4028670SJose.Borrego@Sun.COM 	return (0);
4037961SNatalie.Li@Sun.COM }
4047961SNatalie.Li@Sun.COM 
4057961SNatalie.Li@Sun.COM /*
40610001SJoyce.McIntosh@Sun.COM  * smb_delete_check_dosattr
4077961SNatalie.Li@Sun.COM  *
4087961SNatalie.Li@Sun.COM  * Check file's dos atributes to ensure that
4097961SNatalie.Li@Sun.COM  * 1. the file is not a directory - NT_STATUS_FILE_IS_A_DIRECTORY
4107961SNatalie.Li@Sun.COM  * 2. the file is not readonly - NT_STATUS_CANNOT_DELETE
4117961SNatalie.Li@Sun.COM  * 3. the file's dos attributes comply with the specified search attributes
4127961SNatalie.Li@Sun.COM  *     If the file is either hidden or system and those attributes
4137961SNatalie.Li@Sun.COM  *     are not specified in the search attributes - NT_STATUS_NO_SUCH_FILE
4147961SNatalie.Li@Sun.COM  *
4157961SNatalie.Li@Sun.COM  * Returns: 0 - file's attributes pass all checks
4167961SNatalie.Li@Sun.COM  *         -1 - err populated with error details
4177961SNatalie.Li@Sun.COM  */
4187961SNatalie.Li@Sun.COM static int
41910001SJoyce.McIntosh@Sun.COM smb_delete_check_dosattr(smb_request_t *sr, smb_error_t *err)
4207961SNatalie.Li@Sun.COM {
4217961SNatalie.Li@Sun.COM 	smb_fqi_t *fqi;
4227961SNatalie.Li@Sun.COM 	smb_node_t *node;
42310001SJoyce.McIntosh@Sun.COM 	smb_attr_t attr;
42410001SJoyce.McIntosh@Sun.COM 	uint16_t sattr;
4257961SNatalie.Li@Sun.COM 
4267961SNatalie.Li@Sun.COM 	fqi = &sr->arg.dirop.fqi;
4279343SAfshin.Ardakani@Sun.COM 	sattr = fqi->fq_sattr;
4289343SAfshin.Ardakani@Sun.COM 	node = fqi->fq_fnode;
4297961SNatalie.Li@Sun.COM 
43010001SJoyce.McIntosh@Sun.COM 	if (smb_node_getattr(sr, node, &attr) != 0) {
43110001SJoyce.McIntosh@Sun.COM 		smb_delete_error(err, NT_STATUS_INTERNAL_ERROR,
43210001SJoyce.McIntosh@Sun.COM 		    ERRDOS, ERROR_INTERNAL_ERROR);
43310001SJoyce.McIntosh@Sun.COM 		return (-1);
43410001SJoyce.McIntosh@Sun.COM 	}
43510001SJoyce.McIntosh@Sun.COM 
43610001SJoyce.McIntosh@Sun.COM 	if (attr.sa_dosattr & FILE_ATTRIBUTE_DIRECTORY) {
4377961SNatalie.Li@Sun.COM 		smb_delete_error(err, NT_STATUS_FILE_IS_A_DIRECTORY,
4387961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_ACCESS_DENIED);
4397961SNatalie.Li@Sun.COM 		return (-1);
4405331Samw 	}
4415331Samw 
4427961SNatalie.Li@Sun.COM 	if (SMB_PATHFILE_IS_READONLY(sr, node)) {
4437961SNatalie.Li@Sun.COM 		smb_delete_error(err, NT_STATUS_CANNOT_DELETE,
4447961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_ACCESS_DENIED);
4457961SNatalie.Li@Sun.COM 		return (-1);
4467961SNatalie.Li@Sun.COM 	}
4476030Sjb150015 
44810001SJoyce.McIntosh@Sun.COM 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
44910001SJoyce.McIntosh@Sun.COM 	    !(SMB_SEARCH_HIDDEN(sattr))) {
4507961SNatalie.Li@Sun.COM 		smb_delete_error(err, NT_STATUS_NO_SUCH_FILE,
4517961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_FILE_NOT_FOUND);
4527961SNatalie.Li@Sun.COM 		return (-1);
4537961SNatalie.Li@Sun.COM 	}
4547961SNatalie.Li@Sun.COM 
45510001SJoyce.McIntosh@Sun.COM 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
45610001SJoyce.McIntosh@Sun.COM 	    !(SMB_SEARCH_SYSTEM(sattr))) {
4577961SNatalie.Li@Sun.COM 		smb_delete_error(err, NT_STATUS_NO_SUCH_FILE,
4587961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_FILE_NOT_FOUND);
4597961SNatalie.Li@Sun.COM 		return (-1);
4607961SNatalie.Li@Sun.COM 	}
4617961SNatalie.Li@Sun.COM 
4627961SNatalie.Li@Sun.COM 	return (0);
4637961SNatalie.Li@Sun.COM }
4645331Samw 
4657961SNatalie.Li@Sun.COM /*
4667961SNatalie.Li@Sun.COM  * smb_delete_remove_file
4677961SNatalie.Li@Sun.COM  *
4687961SNatalie.Li@Sun.COM  * For consistency with Windows 2000, the range check should be done
4697961SNatalie.Li@Sun.COM  * after checking for sharing violations.  Attempting to delete a
4707961SNatalie.Li@Sun.COM  * locked file will result in sharing violation, which is the same
4717961SNatalie.Li@Sun.COM  * thing that will happen if you try to delete a non-locked open file.
4727961SNatalie.Li@Sun.COM  *
4737961SNatalie.Li@Sun.COM  * Note that windows 2000 rejects lock requests on open files that
4747961SNatalie.Li@Sun.COM  * have been opened with metadata open modes.  The error is
4757961SNatalie.Li@Sun.COM  * STATUS_ACCESS_DENIED.
4767961SNatalie.Li@Sun.COM  *
4777961SNatalie.Li@Sun.COM  * NT does not always close a file immediately, which can cause the
4787961SNatalie.Li@Sun.COM  * share and access checking to fail (the node refcnt is greater
4797961SNatalie.Li@Sun.COM  * than one), and the file doesn't get deleted. Breaking the oplock
4807961SNatalie.Li@Sun.COM  * before share and access checking gives the client a chance to
4817961SNatalie.Li@Sun.COM  * close the file.
4827961SNatalie.Li@Sun.COM  *
4837961SNatalie.Li@Sun.COM  * Returns: 0 - success
4847961SNatalie.Li@Sun.COM  *         -1 - error, err populated with error details
4857961SNatalie.Li@Sun.COM  */
4867961SNatalie.Li@Sun.COM static int
4877961SNatalie.Li@Sun.COM smb_delete_remove_file(smb_request_t *sr, smb_error_t *err)
4887961SNatalie.Li@Sun.COM {
4897961SNatalie.Li@Sun.COM 	int rc;
4907961SNatalie.Li@Sun.COM 	uint32_t status;
4917961SNatalie.Li@Sun.COM 	smb_fqi_t *fqi;
4927961SNatalie.Li@Sun.COM 	smb_node_t *node;
4939231SAfshin.Ardakani@Sun.COM 	uint32_t flags = 0;
4947961SNatalie.Li@Sun.COM 
4957961SNatalie.Li@Sun.COM 	fqi = &sr->arg.dirop.fqi;
4969343SAfshin.Ardakani@Sun.COM 	node = fqi->fq_fnode;
4977961SNatalie.Li@Sun.COM 
4989021Samw@Sun.COM 	(void) smb_oplock_break(node, sr->session, B_FALSE);
4997961SNatalie.Li@Sun.COM 
5007961SNatalie.Li@Sun.COM 	smb_node_start_crit(node, RW_READER);
5017961SNatalie.Li@Sun.COM 
5027961SNatalie.Li@Sun.COM 	status = smb_node_delete_check(node);
5037961SNatalie.Li@Sun.COM 	if (status != NT_STATUS_SUCCESS) {
5047961SNatalie.Li@Sun.COM 		smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
5057961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_SHARING_VIOLATION);
5067961SNatalie.Li@Sun.COM 		smb_node_end_crit(node);
5077961SNatalie.Li@Sun.COM 		return (-1);
5087961SNatalie.Li@Sun.COM 	}
5097961SNatalie.Li@Sun.COM 
5107961SNatalie.Li@Sun.COM 	status = smb_range_check(sr, node, 0, UINT64_MAX, B_TRUE);
5117961SNatalie.Li@Sun.COM 	if (status != NT_STATUS_SUCCESS) {
5127961SNatalie.Li@Sun.COM 		smb_delete_error(err, NT_STATUS_ACCESS_DENIED,
5137961SNatalie.Li@Sun.COM 		    ERRDOS, ERROR_ACCESS_DENIED);
5147961SNatalie.Li@Sun.COM 		smb_node_end_crit(node);
5157961SNatalie.Li@Sun.COM 		return (-1);
5167961SNatalie.Li@Sun.COM 	}
5177961SNatalie.Li@Sun.COM 
5189231SAfshin.Ardakani@Sun.COM 	if (SMB_TREE_SUPPORTS_CATIA(sr))
5199231SAfshin.Ardakani@Sun.COM 		flags |= SMB_CATIA;
5209231SAfshin.Ardakani@Sun.COM 
52110122SJordan.Brown@Sun.COM 	rc = smb_fsop_remove(sr, sr->user_cr, node->n_dnode,
5229231SAfshin.Ardakani@Sun.COM 	    node->od_name, flags);
5237961SNatalie.Li@Sun.COM 	if (rc != 0) {
5247961SNatalie.Li@Sun.COM 		if (rc == ENOENT)
5257961SNatalie.Li@Sun.COM 			smb_delete_error(err, NT_STATUS_OBJECT_NAME_NOT_FOUND,
5267961SNatalie.Li@Sun.COM 			    ERRDOS, ERROR_FILE_NOT_FOUND);
5277961SNatalie.Li@Sun.COM 		else
5287961SNatalie.Li@Sun.COM 			smbsr_map_errno(rc, err);
5297961SNatalie.Li@Sun.COM 
5307961SNatalie.Li@Sun.COM 		smb_node_end_crit(node);
5317961SNatalie.Li@Sun.COM 		return (-1);
5327961SNatalie.Li@Sun.COM 	}
5337961SNatalie.Li@Sun.COM 
5347961SNatalie.Li@Sun.COM 	smb_node_end_crit(node);
5357961SNatalie.Li@Sun.COM 	return (0);
5365331Samw }
5375331Samw 
5387961SNatalie.Li@Sun.COM 
5396139Sjb150015 /*
5407348SJose.Borrego@Sun.COM  * smb_delete_check_path
5417348SJose.Borrego@Sun.COM  *
5427961SNatalie.Li@Sun.COM  * Perform initial validation on the pathname and last_comp.
5437348SJose.Borrego@Sun.COM  *
5447961SNatalie.Li@Sun.COM  * wildcards in path:
5457961SNatalie.Li@Sun.COM  * Wildcards in the path (excluding the last_comp) should result
5467961SNatalie.Li@Sun.COM  * in NT_STATUS_OBJECT_NAME_INVALID.
5477348SJose.Borrego@Sun.COM  *
5487348SJose.Borrego@Sun.COM  * bad path syntax:
5497348SJose.Borrego@Sun.COM  * On unix .. at the root of a file system links to the root. Thus
5507348SJose.Borrego@Sun.COM  * an attempt to lookup "/../../.." will be the same as looking up "/"
5517348SJose.Borrego@Sun.COM  * CIFs clients expect the above to result in
5527348SJose.Borrego@Sun.COM  * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible
5537348SJose.Borrego@Sun.COM  * (and questionable if it's desirable) to deal with all cases
5547348SJose.Borrego@Sun.COM  * but paths beginning with \\.. are handled. See bad_paths[].
5557961SNatalie.Li@Sun.COM  * Cases like "\\dir\\..\\.." will be caught and handled after the
5567961SNatalie.Li@Sun.COM  * pnreduce.  Cases like "\\dir\\..\\..\\filename" will still result
5577961SNatalie.Li@Sun.COM  * in "\\filename" which is contrary to windows behavior.
5587348SJose.Borrego@Sun.COM  *
5597961SNatalie.Li@Sun.COM  * dot:
5607961SNatalie.Li@Sun.COM  * A filename of '.' should result in NT_STATUS_OBJECT_NAME_INVALID
5617961SNatalie.Li@Sun.COM  * Any wildcard filename that resolves to '.' should result in
5627961SNatalie.Li@Sun.COM  * NT_STATUS_OBJECT_NAME_INVALID if the search attributes include
5637961SNatalie.Li@Sun.COM  * FILE_ATTRIBUTE_DIRECTORY
5647348SJose.Borrego@Sun.COM  *
5657348SJose.Borrego@Sun.COM  * Returns:
5667961SNatalie.Li@Sun.COM  *   0:  path is valid. Sets *wildcard to TRUE if wildcard delete
5677348SJose.Borrego@Sun.COM  *	         i.e. if wildcards in last component
5687961SNatalie.Li@Sun.COM  *  -1: path is invalid. Sets error information in sr.
5697348SJose.Borrego@Sun.COM  */
5707961SNatalie.Li@Sun.COM static int
5717348SJose.Borrego@Sun.COM smb_delete_check_path(smb_request_t *sr, boolean_t *wildcard)
5727348SJose.Borrego@Sun.COM {
5737961SNatalie.Li@Sun.COM 	smb_fqi_t *fqi = &sr->arg.dirop.fqi;
5747961SNatalie.Li@Sun.COM 	char *p, *last_comp;
5757348SJose.Borrego@Sun.COM 	int i, wildcards;
5769343SAfshin.Ardakani@Sun.COM 	smb_pathname_t *pn = &fqi->fq_path;
5777348SJose.Borrego@Sun.COM 
5787348SJose.Borrego@Sun.COM 	struct {
5797348SJose.Borrego@Sun.COM 		char *name;
5807348SJose.Borrego@Sun.COM 		int len;
5817348SJose.Borrego@Sun.COM 	} *bad, bad_paths[] = {
5827348SJose.Borrego@Sun.COM 		{"\\..\0", 4},
5837348SJose.Borrego@Sun.COM 		{"\\..\\", 4},
5847348SJose.Borrego@Sun.COM 		{"..\0", 3},
5857348SJose.Borrego@Sun.COM 		{"..\\", 3}
5867348SJose.Borrego@Sun.COM 	};
5877348SJose.Borrego@Sun.COM 
5887348SJose.Borrego@Sun.COM 	/* find last component, strip trailing '\\' */
5899343SAfshin.Ardakani@Sun.COM 	p = pn->pn_path + strlen(pn->pn_path) - 1;
5907348SJose.Borrego@Sun.COM 	while (*p == '\\') {
5917348SJose.Borrego@Sun.COM 		*p = '\0';
5927348SJose.Borrego@Sun.COM 		--p;
5937348SJose.Borrego@Sun.COM 	}
5948938Samw@Sun.COM 
5959343SAfshin.Ardakani@Sun.COM 	if ((p = strrchr(pn->pn_path, '\\')) == NULL)
5969343SAfshin.Ardakani@Sun.COM 		last_comp = pn->pn_path;
5978938Samw@Sun.COM 	else
5987961SNatalie.Li@Sun.COM 		last_comp = ++p;
5997348SJose.Borrego@Sun.COM 
6008938Samw@Sun.COM 	wildcards = smb_convert_wildcards(last_comp);
6018938Samw@Sun.COM 
6029343SAfshin.Ardakani@Sun.COM 	if (last_comp != pn->pn_path) {
6038938Samw@Sun.COM 		/*
6048938Samw@Sun.COM 		 * Wildcards are only allowed in the last component.
6058938Samw@Sun.COM 		 * Check for additional wildcards in the path.
6068938Samw@Sun.COM 		 */
6079343SAfshin.Ardakani@Sun.COM 		if (smb_convert_wildcards(pn->pn_path) != wildcards) {
6087348SJose.Borrego@Sun.COM 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
6097348SJose.Borrego@Sun.COM 			    ERRDOS, ERROR_INVALID_NAME);
6107961SNatalie.Li@Sun.COM 			return (-1);
6117348SJose.Borrego@Sun.COM 		}
6127348SJose.Borrego@Sun.COM 	}
6137348SJose.Borrego@Sun.COM 
6147961SNatalie.Li@Sun.COM 	/* path above the mount point */
6157348SJose.Borrego@Sun.COM 	for (i = 0; i < sizeof (bad_paths) / sizeof (bad_paths[0]); ++i) {
6167348SJose.Borrego@Sun.COM 		bad = &bad_paths[i];
6179343SAfshin.Ardakani@Sun.COM 		if (strncmp(pn->pn_path, bad->name, bad->len) == 0) {
6187348SJose.Borrego@Sun.COM 			smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
6197348SJose.Borrego@Sun.COM 			    ERRDOS, ERROR_BAD_PATHNAME);
6207961SNatalie.Li@Sun.COM 			return (-1);
6217348SJose.Borrego@Sun.COM 		}
6227348SJose.Borrego@Sun.COM 	}
6237348SJose.Borrego@Sun.COM 
6247961SNatalie.Li@Sun.COM 	/* last component is, or resolves to, '.' (dot) */
6257961SNatalie.Li@Sun.COM 	if ((strcmp(last_comp, ".") == 0) ||
6269343SAfshin.Ardakani@Sun.COM 	    (SMB_SEARCH_DIRECTORY(fqi->fq_sattr) &&
6277961SNatalie.Li@Sun.COM 	    (smb_match(last_comp, ".")))) {
6287348SJose.Borrego@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
6297348SJose.Borrego@Sun.COM 		    ERRDOS, ERROR_INVALID_NAME);
6307961SNatalie.Li@Sun.COM 		return (-1);
6317348SJose.Borrego@Sun.COM 	}
6327348SJose.Borrego@Sun.COM 
6337348SJose.Borrego@Sun.COM 	*wildcard = (wildcards != 0);
6347961SNatalie.Li@Sun.COM 	return (0);
6357348SJose.Borrego@Sun.COM }
6367348SJose.Borrego@Sun.COM 
6377348SJose.Borrego@Sun.COM /*
6387961SNatalie.Li@Sun.COM  * smb_delete_error
6396139Sjb150015  */
6407961SNatalie.Li@Sun.COM static void
6417961SNatalie.Li@Sun.COM smb_delete_error(smb_error_t *err,
6427961SNatalie.Li@Sun.COM     uint32_t status, uint16_t errcls, uint16_t errcode)
6435331Samw {
6447961SNatalie.Li@Sun.COM 	err->severity = ERROR_SEVERITY_ERROR;
6457961SNatalie.Li@Sun.COM 	err->status = status;
6467961SNatalie.Li@Sun.COM 	err->errcls = errcls;
6477961SNatalie.Li@Sun.COM 	err->errcode = errcode;
6485331Samw }
649