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