1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <smbsrv/smb_incl.h> 29 #include <smbsrv/smb_fsops.h> 30 #include <smbsrv/smbinfo.h> 31 32 static DWORD smb_delete_check(struct smb_request *sr, struct smb_node *node, 33 uint16_t dattr, smb_error_t *smberr); 34 static DWORD smb_delete_share_check(struct smb_node *node); 35 36 /* 37 * smb_com_delete 38 * 39 * The delete file message is sent to delete a data file. The appropriate 40 * Tid and additional pathname are passed. Read only files may not be 41 * deleted, the read-only attribute must be reset prior to file deletion. 42 * 43 * NT supports a hidden permission known as File Delete Child (FDC). If 44 * the user has FullControl access to a directory, the user is permitted 45 * to delete any object in the directory regardless of the permissions 46 * on the object. 47 * 48 * Client Request Description 49 * ================================== ================================= 50 * UCHAR WordCount; Count of parameter words = 1 51 * USHORT SearchAttributes; 52 * USHORT ByteCount; Count of data bytes; min = 2 53 * UCHAR BufferFormat; 0x04 54 * STRING FileName[]; File name 55 * 56 * Multiple files may be deleted in response to a single request as 57 * SMB_COM_DELETE supports wildcards 58 * 59 * SearchAttributes indicates the attributes that the target file(s) must 60 * have. If the attribute is zero then only normal files are deleted. If 61 * the system file or hidden attributes are specified then the delete is 62 * inclusive -both the specified type(s) of files and normal files are 63 * deleted. Attributes are described in the "Attribute Encoding" section 64 * of this document. 65 * 66 * If bit0 of the Flags2 field of the SMB header is set, a pattern is 67 * passed in, and the file has a long name, then the passed pattern much 68 * match the long file name for the delete to succeed. If bit0 is clear, a 69 * pattern is passed in, and the file has a long name, then the passed 70 * pattern must match the file's short name for the deletion to succeed. 71 * 72 * Server Response Description 73 * ================================== ================================= 74 * UCHAR WordCount; Count of parameter words = 0 75 * USHORT ByteCount; Count of data bytes = 0 76 * 77 * 4.2.10.1 Errors 78 * 79 * ERRDOS/ERRbadpath 80 * ERRDOS/ERRbadfile 81 * ERRDOS/ERRnoaccess 82 * ERRDOS/ERRbadshare # returned by NT for files that are already open 83 * ERRHRD/ERRnowrite 84 * ERRSRV/ERRaccess 85 * ERRSRV/ERRinvdevice 86 * ERRSRV/ERRinvid 87 * ERRSRV/ERRbaduid 88 */ 89 int 90 smb_com_delete(struct smb_request *sr) 91 { 92 int rc; 93 int od = 0; 94 int deleted = 0; 95 unsigned short sattr; 96 char *path; 97 struct smb_node *dir_snode; 98 struct smb_node *node = 0; 99 char *name; 100 char *fname; 101 char *sname; 102 char *fullname; 103 smb_error_t smberr; 104 int is_stream; 105 smb_odir_context_t *pc; 106 107 pc = kmem_zalloc(sizeof (*pc), KM_SLEEP); 108 fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 109 sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 110 name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 111 fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 112 113 if (smbsr_decode_vwv(sr, "w", &sattr) != 0) { 114 kmem_free(pc, sizeof (*pc)); 115 kmem_free(name, MAXNAMELEN); 116 kmem_free(fname, MAXNAMELEN); 117 kmem_free(sname, MAXNAMELEN); 118 kmem_free(fullname, MAXPATHLEN); 119 smbsr_decode_error(sr); 120 /* NOTREACHED */ 121 } 122 123 if (smbsr_decode_data(sr, "%S", sr, &path) != 0) { 124 kmem_free(pc, sizeof (*pc)); 125 kmem_free(name, MAXNAMELEN); 126 kmem_free(fname, MAXNAMELEN); 127 kmem_free(sname, MAXNAMELEN); 128 kmem_free(fullname, MAXPATHLEN); 129 smbsr_decode_error(sr); 130 /* NOTREACHED */ 131 } 132 133 is_stream = smb_stream_parse_name(path, fname, sname); 134 135 (void) smb_rdir_open(sr, path, sattr); 136 dir_snode = sr->sid_odir->d_dir_snode; 137 138 /* 139 * This while loop is meant to deal with wildcards. 140 * It is not expected that wildcards will exist for 141 * streams. For the streams case, it is expected 142 * that the below loop will be executed only once. 143 */ 144 145 while ((rc = smb_rdir_next(sr, &node, pc)) == 0) { 146 (void) strlcpy(name, pc->dc_name, MAXNAMELEN); 147 148 if (smb_delete_check(sr, node, pc->dc_dattr, &smberr) 149 != NT_STATUS_SUCCESS) { 150 smb_node_release(node); 151 goto delete_error; 152 } 153 154 smb_node_release(node); 155 node = NULL; 156 157 if (is_stream) { 158 /* 159 * It is assumed that fname does not contain 160 * any wildcards . 161 * smb_fsop_remove() requires filename+streamname 162 */ 163 (void) snprintf(fullname, MAXPATHLEN, "%s%s", 164 fname, sname); 165 rc = smb_fsop_remove(sr, sr->user_cr, dir_snode, 166 fullname, 0); 167 } else { 168 /* 169 * name (i.e. pc->dc_name) is the on-disk name 170 * unless there is a case collision, in which 171 * case readdir will have returned a mangled name. 172 */ 173 if (smb_maybe_mangled_name(name) == 0) 174 od = 1; 175 176 rc = smb_fsop_remove(sr, sr->user_cr, dir_snode, 177 name, od); 178 } 179 180 if (rc != 0) { 181 if (rc != ENOENT) { 182 smb_rdir_close(sr); 183 kmem_free(pc, sizeof (*pc)); 184 kmem_free(name, MAXNAMELEN); 185 kmem_free(fname, MAXNAMELEN); 186 kmem_free(sname, MAXNAMELEN); 187 kmem_free(fullname, MAXPATHLEN); 188 smbsr_raise_errno(sr, rc); 189 /* NOTREACHED */ 190 } 191 } else { 192 deleted++; 193 } 194 } 195 196 if ((rc != 0) && (rc != ENOENT)) { 197 /* rc returned by smb_rdir_next() */ 198 smb_rdir_close(sr); 199 kmem_free(pc, sizeof (*pc)); 200 kmem_free(name, MAXNAMELEN); 201 kmem_free(fname, MAXNAMELEN); 202 kmem_free(sname, MAXNAMELEN); 203 kmem_free(fullname, MAXPATHLEN); 204 smbsr_raise_errno(sr, rc); 205 /* NOTREACHED */ 206 } 207 208 if (deleted == 0) { 209 smberr.errcls = ERRDOS; 210 smberr.errcode = ERROR_FILE_NOT_FOUND; 211 smberr.status = (sr->sid_odir->d_wildcards == 0) 212 ? NT_STATUS_OBJECT_NAME_NOT_FOUND : NT_STATUS_NO_SUCH_FILE; 213 goto delete_error; 214 } 215 216 smb_rdir_close(sr); 217 218 smbsr_encode_empty_result(sr); 219 220 kmem_free(pc, sizeof (*pc)); 221 kmem_free(name, MAXNAMELEN); 222 kmem_free(fname, MAXNAMELEN); 223 kmem_free(sname, MAXNAMELEN); 224 kmem_free(fullname, MAXPATHLEN); 225 return (SDRC_NORMAL_REPLY); 226 227 delete_error: 228 smb_rdir_close(sr); 229 kmem_free(pc, sizeof (*pc)); 230 kmem_free(name, MAXNAMELEN); 231 kmem_free(fname, MAXNAMELEN); 232 kmem_free(sname, MAXNAMELEN); 233 kmem_free(fullname, MAXPATHLEN); 234 smbsr_raise_cifs_error(sr, 235 smberr.status, smberr.errcls, smberr.errcode); 236 /* NOTREACHED */ 237 return (SDRC_NORMAL_REPLY); /* compiler complains otherwise */ 238 } 239 240 static DWORD 241 smb_delete_check( 242 struct smb_request *sr, 243 struct smb_node *node, 244 uint16_t dattr, 245 smb_error_t *smberr) 246 { 247 if (dattr & SMB_FA_DIRECTORY) { 248 smberr->errcls = ERRDOS; 249 smberr->errcode = ERROR_ACCESS_DENIED; 250 smberr->status = NT_STATUS_FILE_IS_A_DIRECTORY; 251 return (NT_STATUS_UNSUCCESSFUL); 252 } 253 254 if ((dattr & SMB_FA_READONLY) || 255 (node->flags & NODE_CREATED_READONLY)) { 256 smberr->errcls = ERRDOS; 257 smberr->errcode = ERROR_ACCESS_DENIED; 258 smberr->status = NT_STATUS_CANNOT_DELETE; 259 return (NT_STATUS_UNSUCCESSFUL); 260 } 261 262 /* 263 * NT does not always close a file immediately, which 264 * can cause the share and access checking to fail 265 * (the node refcnt is greater than one), and the file 266 * doesn't get deleted. Breaking the oplock before 267 * share and access checking gives the client a chance 268 * to close the file. 269 */ 270 if (OPLOCKS_IN_FORCE(node)) { 271 smberr->status = smb_break_oplock(sr, node); 272 273 if (smberr->status != NT_STATUS_SUCCESS) { 274 smberr->errcls = ERRDOS; 275 smberr->errcode = ERROR_VC_DISCONNECTED; 276 return (NT_STATUS_UNSUCCESSFUL); 277 } 278 } 279 280 smberr->status = smb_delete_share_check(node); 281 if (smberr->status == NT_STATUS_SHARING_VIOLATION) { 282 smberr->errcls = ERRDOS; 283 smberr->errcode = ERROR_SHARING_VIOLATION; 284 return (NT_STATUS_UNSUCCESSFUL); 285 } 286 287 /* 288 * This should be done after Share checking due to tests with 289 * W2K. I got sharing violation error trying to delete a 290 * locked file which is basically the same error if you 291 * try to delete a non-locked open file. 292 * 293 * One thing that I discovered during these tests is that 294 * W2K rejects lock requests on open files which are opened 295 * with Metadata open modes. The error is STATUS_ACCESS_DENIED. 296 */ 297 if (smb_lock_range_access(sr, node, 0, 0, FILE_WRITE_DATA) != 298 NT_STATUS_SUCCESS) { 299 smberr->errcls = ERRDOS; 300 smberr->errcode = ERROR_ACCESS_DENIED; 301 smberr->status = NT_STATUS_ACCESS_DENIED; 302 return (NT_STATUS_UNSUCCESSFUL); 303 } 304 305 306 return (NT_STATUS_SUCCESS); 307 } 308 309 /* 310 * smb_delete_share_check 311 * 312 * An open file can be deleted only if opened for 313 * accessing meta data. Share modes aren't important 314 * in this case. 315 * 316 * NOTE: there is another mechanism for deleting an 317 * open file that NT clients usually use this method. 318 * That's setting "Delete on close" flag for an open 319 * file, in this way the file will be deleted after 320 * last close. This flag can be set by SmbTrans2SetFileInfo 321 * with FILE_DISPOSITION_INFO information level. 322 * For setting this flag file should be opened by 323 * DELETE access in the FID that is passed in the Trans2 324 * request. 325 */ 326 static DWORD 327 smb_delete_share_check(struct smb_node *node) 328 { 329 smb_ofile_t *file; 330 331 if (node == 0 || node->n_refcnt <= 1) 332 return (NT_STATUS_SUCCESS); 333 334 if (node->attr.sa_vattr.va_type == VDIR) 335 return (NT_STATUS_SUCCESS); 336 337 smb_llist_enter(&node->n_ofile_list, RW_READER); 338 file = smb_llist_head(&node->n_ofile_list); 339 while (file) { 340 ASSERT(file->f_magic == SMB_OFILE_MAGIC); 341 if (file->f_granted_access & 342 (FILE_READ_DATA | 343 FILE_WRITE_DATA | 344 FILE_APPEND_DATA | 345 FILE_EXECUTE | 346 DELETE)) { 347 smb_llist_exit(&node->n_ofile_list); 348 return (NT_STATUS_SHARING_VIOLATION); 349 } 350 file = smb_llist_next(&node->n_ofile_list, file); 351 } 352 smb_llist_exit(&node->n_ofile_list); 353 return (NT_STATUS_SUCCESS); 354 } 355