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 *sr, smb_node_t *node, 34 smb_error_t *smberr); 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 if (smbsr_decode_vwv(sr, "w", &sattr) != 0) { 108 smbsr_decode_error(sr); 109 /* NOTREACHED */ 110 } 111 112 if (smbsr_decode_data(sr, "%S", sr, &path) != 0) { 113 smbsr_decode_error(sr); 114 /* NOTREACHED */ 115 } 116 117 pc = kmem_zalloc(sizeof (*pc), KM_SLEEP); 118 fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 119 sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 120 name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 121 fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 122 123 is_stream = smb_stream_parse_name(path, fname, sname); 124 125 (void) smb_rdir_open(sr, path, sattr); 126 dir_snode = sr->sid_odir->d_dir_snode; 127 128 /* 129 * This while loop is meant to deal with wildcards. 130 * It is not expected that wildcards will exist for 131 * streams. For the streams case, it is expected 132 * that the below loop will be executed only once. 133 */ 134 135 while ((rc = smb_rdir_next(sr, &node, pc)) == 0) { 136 (void) strlcpy(name, pc->dc_name, MAXNAMELEN); 137 138 if (pc->dc_dattr & SMB_FA_DIRECTORY) { 139 smberr.errcls = ERRDOS; 140 smberr.errcode = ERROR_ACCESS_DENIED; 141 smberr.status = NT_STATUS_FILE_IS_A_DIRECTORY; 142 smb_node_release(node); 143 goto delete_error; 144 } 145 146 if ((pc->dc_dattr & SMB_FA_READONLY) || 147 (node->flags & NODE_CREATED_READONLY)) { 148 smberr.errcls = ERRDOS; 149 smberr.errcode = ERROR_ACCESS_DENIED; 150 smberr.status = NT_STATUS_CANNOT_DELETE; 151 smb_node_release(node); 152 goto delete_error; 153 } 154 155 /* 156 * NT does not always close a file immediately, which 157 * can cause the share and access checking to fail 158 * (the node refcnt is greater than one), and the file 159 * doesn't get deleted. Breaking the oplock before 160 * share and access checking gives the client a chance 161 * to close the file. 162 */ 163 164 if (OPLOCKS_IN_FORCE(node)) { 165 smberr.status = smb_break_oplock(sr, node); 166 167 if (smberr.status != NT_STATUS_SUCCESS) { 168 smberr.errcls = ERRDOS; 169 smberr.errcode = ERROR_VC_DISCONNECTED; 170 smb_node_release(node); 171 goto delete_error; 172 } 173 } 174 175 smb_node_start_crit(node, RW_READER); 176 177 if (smb_delete_check(sr, node, &smberr)) { 178 smb_node_end_crit(node); 179 smb_node_release(node); 180 goto delete_error; 181 } 182 183 if (is_stream) { 184 /* 185 * It is assumed that fname does not contain 186 * any wildcards . 187 * smb_fsop_remove() requires filename+streamname 188 */ 189 (void) snprintf(fullname, MAXPATHLEN, "%s%s", 190 fname, sname); 191 rc = smb_fsop_remove(sr, sr->user_cr, dir_snode, 192 fullname, 0); 193 } else { 194 /* 195 * name (i.e. pc->dc_name) is the on-disk name 196 * unless there is a case collision, in which 197 * case readdir will have returned a mangled name. 198 */ 199 if (smb_maybe_mangled_name(name) == 0) 200 od = 1; 201 202 rc = smb_fsop_remove(sr, sr->user_cr, dir_snode, 203 name, od); 204 } 205 206 smb_node_end_crit(node); 207 smb_node_release(node); 208 node = NULL; 209 210 if (rc != 0) { 211 if (rc != ENOENT) { 212 smb_rdir_close(sr); 213 kmem_free(pc, sizeof (*pc)); 214 kmem_free(name, MAXNAMELEN); 215 kmem_free(fname, MAXNAMELEN); 216 kmem_free(sname, MAXNAMELEN); 217 kmem_free(fullname, MAXPATHLEN); 218 smbsr_errno(sr, rc); 219 /* NOTREACHED */ 220 } 221 } else { 222 deleted++; 223 } 224 } 225 226 if ((rc != 0) && (rc != ENOENT)) { 227 /* rc returned by smb_rdir_next() */ 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_errno(sr, rc); 235 /* NOTREACHED */ 236 } 237 238 if (deleted == 0) { 239 smberr.errcls = ERRDOS; 240 smberr.errcode = ERROR_FILE_NOT_FOUND; 241 smberr.status = (sr->sid_odir->d_wildcards == 0) 242 ? NT_STATUS_OBJECT_NAME_NOT_FOUND : NT_STATUS_NO_SUCH_FILE; 243 goto delete_error; 244 } 245 246 smb_rdir_close(sr); 247 248 smbsr_encode_empty_result(sr); 249 250 kmem_free(pc, sizeof (*pc)); 251 kmem_free(name, MAXNAMELEN); 252 kmem_free(fname, MAXNAMELEN); 253 kmem_free(sname, MAXNAMELEN); 254 kmem_free(fullname, MAXPATHLEN); 255 return (SDRC_NORMAL_REPLY); 256 257 delete_error: 258 smb_rdir_close(sr); 259 kmem_free(pc, sizeof (*pc)); 260 kmem_free(name, MAXNAMELEN); 261 kmem_free(fname, MAXNAMELEN); 262 kmem_free(sname, MAXNAMELEN); 263 kmem_free(fullname, MAXPATHLEN); 264 smbsr_error(sr, smberr.status, smberr.errcls, smberr.errcode); 265 /* NOTREACHED */ 266 return (SDRC_NORMAL_REPLY); /* compiler complains otherwise */ 267 } 268 269 uint32_t 270 smb_delete_check(smb_request_t *sr, smb_node_t *node, smb_error_t *smberr) 271 { 272 smberr->status = smb_node_delete_check(node); 273 274 if (smberr->status == NT_STATUS_SHARING_VIOLATION) { 275 smberr->errcls = ERRDOS; 276 smberr->errcode = ERROR_SHARING_VIOLATION; 277 return (smberr->status); 278 } 279 280 /* 281 * This should be done after Share checking due to tests with 282 * W2K. I got sharing violation error trying to delete a 283 * locked file which is basically the same error if you 284 * try to delete a non-locked open file. 285 * 286 * One thing that I discovered during these tests is that 287 * W2K rejects lock requests on open files which are opened 288 * with Metadata open modes. The error is STATUS_ACCESS_DENIED. 289 */ 290 291 smberr->status = smb_range_check(sr, sr->user_cr, node, 0, 292 UINT64_MAX, B_TRUE); 293 294 if (smberr->status != NT_STATUS_SUCCESS) { 295 smberr->errcls = ERRDOS; 296 smberr->errcode = ERROR_ACCESS_DENIED; 297 smberr->status = NT_STATUS_ACCESS_DENIED; 298 } 299 300 return (smberr->status); 301 } 302