1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22dc20a302Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27da6c28aaSamw 28da6c28aaSamw #include <smbsrv/smb_incl.h> 29da6c28aaSamw #include <smbsrv/smb_fsops.h> 30da6c28aaSamw #include <smbsrv/smbinfo.h> 31dc20a302Sas200622 #include <sys/nbmlock.h> 32da6c28aaSamw 33*faa1795aSjb150015 static uint32_t smb_delete_check(smb_request_t *, smb_node_t *); 34da6c28aaSamw 35da6c28aaSamw /* 36da6c28aaSamw * smb_com_delete 37da6c28aaSamw * 38da6c28aaSamw * The delete file message is sent to delete a data file. The appropriate 39da6c28aaSamw * Tid and additional pathname are passed. Read only files may not be 40da6c28aaSamw * deleted, the read-only attribute must be reset prior to file deletion. 41da6c28aaSamw * 42da6c28aaSamw * NT supports a hidden permission known as File Delete Child (FDC). If 43da6c28aaSamw * the user has FullControl access to a directory, the user is permitted 44da6c28aaSamw * to delete any object in the directory regardless of the permissions 45da6c28aaSamw * on the object. 46da6c28aaSamw * 47da6c28aaSamw * Client Request Description 48da6c28aaSamw * ================================== ================================= 49da6c28aaSamw * UCHAR WordCount; Count of parameter words = 1 50da6c28aaSamw * USHORT SearchAttributes; 51da6c28aaSamw * USHORT ByteCount; Count of data bytes; min = 2 52da6c28aaSamw * UCHAR BufferFormat; 0x04 53da6c28aaSamw * STRING FileName[]; File name 54da6c28aaSamw * 55da6c28aaSamw * Multiple files may be deleted in response to a single request as 56da6c28aaSamw * SMB_COM_DELETE supports wildcards 57da6c28aaSamw * 58da6c28aaSamw * SearchAttributes indicates the attributes that the target file(s) must 59da6c28aaSamw * have. If the attribute is zero then only normal files are deleted. If 60da6c28aaSamw * the system file or hidden attributes are specified then the delete is 61da6c28aaSamw * inclusive -both the specified type(s) of files and normal files are 62da6c28aaSamw * deleted. Attributes are described in the "Attribute Encoding" section 63da6c28aaSamw * of this document. 64da6c28aaSamw * 65da6c28aaSamw * If bit0 of the Flags2 field of the SMB header is set, a pattern is 66da6c28aaSamw * passed in, and the file has a long name, then the passed pattern much 67da6c28aaSamw * match the long file name for the delete to succeed. If bit0 is clear, a 68da6c28aaSamw * pattern is passed in, and the file has a long name, then the passed 69da6c28aaSamw * pattern must match the file's short name for the deletion to succeed. 70da6c28aaSamw * 71da6c28aaSamw * Server Response Description 72da6c28aaSamw * ================================== ================================= 73da6c28aaSamw * UCHAR WordCount; Count of parameter words = 0 74da6c28aaSamw * USHORT ByteCount; Count of data bytes = 0 75da6c28aaSamw * 76da6c28aaSamw * 4.2.10.1 Errors 77da6c28aaSamw * 78da6c28aaSamw * ERRDOS/ERRbadpath 79da6c28aaSamw * ERRDOS/ERRbadfile 80da6c28aaSamw * ERRDOS/ERRnoaccess 81da6c28aaSamw * ERRDOS/ERRbadshare # returned by NT for files that are already open 82da6c28aaSamw * ERRHRD/ERRnowrite 83da6c28aaSamw * ERRSRV/ERRaccess 84da6c28aaSamw * ERRSRV/ERRinvdevice 85da6c28aaSamw * ERRSRV/ERRinvid 86da6c28aaSamw * ERRSRV/ERRbaduid 87da6c28aaSamw */ 887b59d02dSjb150015 smb_sdrc_t 89*faa1795aSjb150015 smb_pre_delete(smb_request_t *sr) 90da6c28aaSamw { 91*faa1795aSjb150015 struct smb_fqi *fqi = &sr->arg.dirop.fqi; 92*faa1795aSjb150015 int rc; 93*faa1795aSjb150015 94*faa1795aSjb150015 if ((rc = smbsr_decode_vwv(sr, "w", &fqi->srch_attr)) == 0) 95*faa1795aSjb150015 rc = smbsr_decode_data(sr, "%S", sr, &fqi->path); 96*faa1795aSjb150015 97*faa1795aSjb150015 DTRACE_SMB_2(op__Delete__start, smb_request_t *, sr, 98*faa1795aSjb150015 struct smb_fqi *, fqi); 99*faa1795aSjb150015 100*faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 101*faa1795aSjb150015 } 102*faa1795aSjb150015 103*faa1795aSjb150015 void 104*faa1795aSjb150015 smb_post_delete(smb_request_t *sr) 105*faa1795aSjb150015 { 106*faa1795aSjb150015 DTRACE_SMB_1(op__Delete__done, smb_request_t *, sr); 107*faa1795aSjb150015 } 108*faa1795aSjb150015 109*faa1795aSjb150015 smb_sdrc_t 110*faa1795aSjb150015 smb_com_delete(smb_request_t *sr) 111*faa1795aSjb150015 { 112*faa1795aSjb150015 struct smb_fqi *fqi = &sr->arg.dirop.fqi; 113da6c28aaSamw int rc; 114da6c28aaSamw int od = 0; 115da6c28aaSamw int deleted = 0; 116da6c28aaSamw struct smb_node *dir_snode; 117da6c28aaSamw struct smb_node *node = 0; 118da6c28aaSamw char *name; 119da6c28aaSamw char *fname; 120da6c28aaSamw char *sname; 121da6c28aaSamw char *fullname; 122*faa1795aSjb150015 uint32_t status; 123da6c28aaSamw int is_stream; 124da6c28aaSamw smb_odir_context_t *pc; 125da6c28aaSamw 126*faa1795aSjb150015 if (smb_rdir_open(sr, fqi->path, fqi->srch_attr) != 0) 127*faa1795aSjb150015 return (SDRC_ERROR); 128da6c28aaSamw 129dc20a302Sas200622 pc = kmem_zalloc(sizeof (*pc), KM_SLEEP); 130dc20a302Sas200622 fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 131dc20a302Sas200622 sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 132dc20a302Sas200622 name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 133dc20a302Sas200622 fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 134dc20a302Sas200622 135*faa1795aSjb150015 is_stream = smb_stream_parse_name(fqi->path, fname, sname); 136da6c28aaSamw dir_snode = sr->sid_odir->d_dir_snode; 137da6c28aaSamw 138da6c28aaSamw /* 139da6c28aaSamw * This while loop is meant to deal with wildcards. 140da6c28aaSamw * It is not expected that wildcards will exist for 141da6c28aaSamw * streams. For the streams case, it is expected 142da6c28aaSamw * that the below loop will be executed only once. 143da6c28aaSamw */ 144da6c28aaSamw 145da6c28aaSamw while ((rc = smb_rdir_next(sr, &node, pc)) == 0) { 146da6c28aaSamw (void) strlcpy(name, pc->dc_name, MAXNAMELEN); 147da6c28aaSamw 148dc20a302Sas200622 if (pc->dc_dattr & SMB_FA_DIRECTORY) { 149*faa1795aSjb150015 smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY, 150*faa1795aSjb150015 ERRDOS, ERROR_ACCESS_DENIED); 151da6c28aaSamw smb_node_release(node); 152da6c28aaSamw goto delete_error; 153da6c28aaSamw } 154da6c28aaSamw 155dc20a302Sas200622 if ((pc->dc_dattr & SMB_FA_READONLY) || 156dc20a302Sas200622 (node->flags & NODE_CREATED_READONLY)) { 157*faa1795aSjb150015 smbsr_error(sr, NT_STATUS_CANNOT_DELETE, 158*faa1795aSjb150015 ERRDOS, ERROR_ACCESS_DENIED); 159da6c28aaSamw smb_node_release(node); 160dc20a302Sas200622 goto delete_error; 161dc20a302Sas200622 } 162dc20a302Sas200622 163dc20a302Sas200622 /* 164dc20a302Sas200622 * NT does not always close a file immediately, which 165dc20a302Sas200622 * can cause the share and access checking to fail 166dc20a302Sas200622 * (the node refcnt is greater than one), and the file 167dc20a302Sas200622 * doesn't get deleted. Breaking the oplock before 168dc20a302Sas200622 * share and access checking gives the client a chance 169dc20a302Sas200622 * to close the file. 170dc20a302Sas200622 */ 171dc20a302Sas200622 172dc20a302Sas200622 if (OPLOCKS_IN_FORCE(node)) { 173*faa1795aSjb150015 status = smb_break_oplock(sr, node); 174dc20a302Sas200622 175*faa1795aSjb150015 if (status != NT_STATUS_SUCCESS) { 176*faa1795aSjb150015 smbsr_error(sr, status, 177*faa1795aSjb150015 ERRDOS, ERROR_VC_DISCONNECTED); 178dc20a302Sas200622 smb_node_release(node); 179dc20a302Sas200622 goto delete_error; 180dc20a302Sas200622 } 181dc20a302Sas200622 } 182dc20a302Sas200622 183dc20a302Sas200622 smb_node_start_crit(node, RW_READER); 184dc20a302Sas200622 185*faa1795aSjb150015 if (smb_delete_check(sr, node) != NT_STATUS_SUCCESS) { 186dc20a302Sas200622 smb_node_end_crit(node); 187dc20a302Sas200622 smb_node_release(node); 188dc20a302Sas200622 goto delete_error; 189dc20a302Sas200622 } 190da6c28aaSamw 191da6c28aaSamw if (is_stream) { 192da6c28aaSamw /* 193da6c28aaSamw * It is assumed that fname does not contain 194da6c28aaSamw * any wildcards . 195da6c28aaSamw * smb_fsop_remove() requires filename+streamname 196da6c28aaSamw */ 197da6c28aaSamw (void) snprintf(fullname, MAXPATHLEN, "%s%s", 198da6c28aaSamw fname, sname); 199da6c28aaSamw rc = smb_fsop_remove(sr, sr->user_cr, dir_snode, 200da6c28aaSamw fullname, 0); 201da6c28aaSamw } else { 202da6c28aaSamw /* 203da6c28aaSamw * name (i.e. pc->dc_name) is the on-disk name 204da6c28aaSamw * unless there is a case collision, in which 205da6c28aaSamw * case readdir will have returned a mangled name. 206da6c28aaSamw */ 207da6c28aaSamw if (smb_maybe_mangled_name(name) == 0) 208da6c28aaSamw od = 1; 209da6c28aaSamw 210da6c28aaSamw rc = smb_fsop_remove(sr, sr->user_cr, dir_snode, 211da6c28aaSamw name, od); 212da6c28aaSamw } 213da6c28aaSamw 214dc20a302Sas200622 smb_node_end_crit(node); 215dc20a302Sas200622 smb_node_release(node); 216dc20a302Sas200622 node = NULL; 217dc20a302Sas200622 218da6c28aaSamw if (rc != 0) { 219*faa1795aSjb150015 if (rc != ENOENT) { 220*faa1795aSjb150015 smbsr_errno(sr, rc); 221*faa1795aSjb150015 goto delete_error; 222*faa1795aSjb150015 } 223da6c28aaSamw } else { 224da6c28aaSamw deleted++; 225da6c28aaSamw } 226da6c28aaSamw } 227da6c28aaSamw 228da6c28aaSamw if ((rc != 0) && (rc != ENOENT)) { 229*faa1795aSjb150015 smbsr_errno(sr, rc); 230*faa1795aSjb150015 goto delete_error; 231da6c28aaSamw } 232da6c28aaSamw 233da6c28aaSamw if (deleted == 0) { 234*faa1795aSjb150015 if (sr->sid_odir->d_wildcards == 0) 235*faa1795aSjb150015 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 236*faa1795aSjb150015 ERRDOS, ERROR_FILE_NOT_FOUND); 237*faa1795aSjb150015 else 238*faa1795aSjb150015 smbsr_error(sr, NT_STATUS_NO_SUCH_FILE, 239*faa1795aSjb150015 ERRDOS, ERROR_FILE_NOT_FOUND); 240da6c28aaSamw goto delete_error; 241da6c28aaSamw } 242da6c28aaSamw 243da6c28aaSamw smb_rdir_close(sr); 244da6c28aaSamw kmem_free(pc, sizeof (*pc)); 245da6c28aaSamw kmem_free(name, MAXNAMELEN); 246da6c28aaSamw kmem_free(fname, MAXNAMELEN); 247da6c28aaSamw kmem_free(sname, MAXNAMELEN); 248da6c28aaSamw kmem_free(fullname, MAXPATHLEN); 2497b59d02dSjb150015 2507b59d02dSjb150015 rc = smbsr_encode_empty_result(sr); 251*faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 252da6c28aaSamw 253da6c28aaSamw delete_error: 254da6c28aaSamw smb_rdir_close(sr); 255da6c28aaSamw kmem_free(pc, sizeof (*pc)); 256da6c28aaSamw kmem_free(name, MAXNAMELEN); 257da6c28aaSamw kmem_free(fname, MAXNAMELEN); 258da6c28aaSamw kmem_free(sname, MAXNAMELEN); 259da6c28aaSamw kmem_free(fullname, MAXPATHLEN); 260*faa1795aSjb150015 return (SDRC_ERROR); 261da6c28aaSamw } 262da6c28aaSamw 263da6c28aaSamw /* 264*faa1795aSjb150015 * For consistency with Windows 2000, the range check should be done 265*faa1795aSjb150015 * after checking for sharing violations. Attempting to delete a 266*faa1795aSjb150015 * locked file will result in sharing violation, which is the same 267*faa1795aSjb150015 * thing that will happen if you try to delete a non-locked open file. 268da6c28aaSamw * 269*faa1795aSjb150015 * Note that windows 2000 rejects lock requests on open files that 270*faa1795aSjb150015 * have been opened with metadata open modes. The error is 271*faa1795aSjb150015 * STATUS_ACCESS_DENIED. 272da6c28aaSamw */ 273*faa1795aSjb150015 static uint32_t 274*faa1795aSjb150015 smb_delete_check(smb_request_t *sr, smb_node_t *node) 275*faa1795aSjb150015 { 276*faa1795aSjb150015 uint32_t status; 277dc20a302Sas200622 278*faa1795aSjb150015 status = smb_node_delete_check(node); 279dc20a302Sas200622 280*faa1795aSjb150015 if (status == NT_STATUS_SHARING_VIOLATION) { 281*faa1795aSjb150015 smbsr_error(sr, NT_STATUS_SHARING_VIOLATION, 282*faa1795aSjb150015 ERRDOS, ERROR_SHARING_VIOLATION); 283*faa1795aSjb150015 return (status); 284da6c28aaSamw } 285da6c28aaSamw 286*faa1795aSjb150015 status = smb_range_check(sr, sr->user_cr, node, 0, UINT64_MAX, B_TRUE); 287*faa1795aSjb150015 288*faa1795aSjb150015 if (status != NT_STATUS_SUCCESS) { 289*faa1795aSjb150015 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 290*faa1795aSjb150015 ERRDOS, ERROR_ACCESS_DENIED); 291*faa1795aSjb150015 } 292*faa1795aSjb150015 293*faa1795aSjb150015 return (status); 294da6c28aaSamw } 295