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