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