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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <smbsrv/smb_kproto.h> 27 #include <smbsrv/smbinfo.h> 28 #include <smbsrv/smb_fsops.h> 29 30 /* 31 * The create directory message is sent to create a new directory. The 32 * appropriate Tid and additional pathname are passed. The directory must 33 * not exist for it to be created. 34 * 35 * Client Request Description 36 * ================================== ================================= 37 * UCHAR WordCount; Count of parameter words = 0 38 * USHORT ByteCount; Count of data bytes; min = 2 39 * UCHAR BufferFormat; 0x04 40 * STRING DirectoryName[]; Directory name 41 * 42 * Servers require clients to have at least create permission for the 43 * subtree containing the directory in order to create a new directory. 44 * The creator's access rights to the new directory are be determined by 45 * local policy on the server. 46 * 47 * Server Response Description 48 * ================================== ================================= 49 * UCHAR WordCount; Count of parameter words = 0 50 * USHORT ByteCount; Count of data bytes = 0 51 */ 52 smb_sdrc_t 53 smb_pre_create_directory(smb_request_t *sr) 54 { 55 int rc; 56 57 rc = smbsr_decode_data(sr, "%S", sr, 58 &sr->arg.dirop.fqi.fq_path.pn_path); 59 60 DTRACE_SMB_2(op__CreateDirectory__start, smb_request_t *, sr, 61 struct dirop *, &sr->arg.dirop); 62 63 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 64 } 65 66 void 67 smb_post_create_directory(smb_request_t *sr) 68 { 69 DTRACE_SMB_1(op__CreateDirectory__done, smb_request_t *, sr); 70 } 71 72 smb_sdrc_t 73 smb_com_create_directory(smb_request_t *sr) 74 { 75 int rc = 0; 76 smb_pathname_t *pn = &sr->arg.dirop.fqi.fq_path; 77 78 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 79 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 80 ERRDOS, ERROR_ACCESS_DENIED); 81 return (SDRC_ERROR); 82 } 83 84 smb_pathname_init(sr, pn, pn->pn_path); 85 if (!smb_pathname_validate(sr, pn) || 86 !smb_validate_dirname(sr, pn)) { 87 return (SDRC_ERROR); 88 } 89 90 if ((rc = smb_common_create_directory(sr)) != 0) { 91 smbsr_errno(sr, rc); 92 return (SDRC_ERROR); 93 } 94 95 rc = smbsr_encode_empty_result(sr); 96 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 97 } 98 99 /* 100 * smb_common_create_directory 101 * 102 * Currently called from: 103 * smb_com_create_directory 104 * smb_com_trans2_create_directory 105 * 106 * Returns errno values. 107 */ 108 int 109 smb_common_create_directory(smb_request_t *sr) 110 { 111 int rc; 112 smb_attr_t new_attr; 113 smb_fqi_t *fqi; 114 smb_node_t *tnode; 115 116 fqi = &sr->arg.dirop.fqi; 117 tnode = sr->tid_tree->t_snode; 118 119 rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path, 120 tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp); 121 if (rc != 0) 122 return (rc); 123 124 if (smb_is_invalid_filename(fqi->fq_last_comp)) { 125 smb_node_release(fqi->fq_dnode); 126 return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */ 127 } 128 129 /* lookup node - to ensure that it does NOT exist */ 130 rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, 131 tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode); 132 if (rc == 0) { 133 smb_node_release(fqi->fq_dnode); 134 smb_node_release(fqi->fq_fnode); 135 return (EEXIST); 136 } 137 if (rc != ENOENT) { 138 smb_node_release(fqi->fq_dnode); 139 return (rc); 140 } 141 142 rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode, 143 FILE_ADD_SUBDIRECTORY); 144 if (rc != NT_STATUS_SUCCESS) { 145 smb_node_release(fqi->fq_dnode); 146 return (EACCES); 147 } 148 149 /* 150 * Explicitly set sa_dosattr, otherwise the file system may 151 * automatically apply FILE_ATTRIBUTE_ARCHIVE which, for 152 * compatibility with windows servers, should not be set. 153 */ 154 bzero(&new_attr, sizeof (new_attr)); 155 new_attr.sa_dosattr = FILE_ATTRIBUTE_DIRECTORY; 156 new_attr.sa_vattr.va_type = VDIR; 157 new_attr.sa_vattr.va_mode = 0777; 158 new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR; 159 160 rc = smb_fsop_mkdir(sr, sr->user_cr, fqi->fq_dnode, fqi->fq_last_comp, 161 &new_attr, &fqi->fq_fnode); 162 if (rc != 0) { 163 smb_node_release(fqi->fq_dnode); 164 return (rc); 165 } 166 167 sr->arg.open.create_options = FILE_DIRECTORY_FILE; 168 169 smb_node_release(fqi->fq_dnode); 170 smb_node_release(fqi->fq_fnode); 171 return (0); 172 } 173 174 /* 175 * The delete directory message is sent to delete an empty directory. The 176 * appropriate Tid and additional pathname are passed. The directory must 177 * be empty for it to be deleted. 178 * 179 * NT supports a hidden permission known as File Delete Child (FDC). If 180 * the user has FullControl access to a directory, the user is permitted 181 * to delete any object in the directory regardless of the permissions 182 * on the object. 183 * 184 * Client Request Description 185 * ================================== ================================= 186 * UCHAR WordCount; Count of parameter words = 0 187 * USHORT ByteCount; Count of data bytes; min = 2 188 * UCHAR BufferFormat; 0x04 189 * STRING DirectoryName[]; Directory name 190 * 191 * The directory to be deleted cannot be the root of the share specified 192 * by Tid. 193 * 194 * Server Response Description 195 * ================================== ================================= 196 * UCHAR WordCount; Count of parameter words = 0 197 * USHORT ByteCount; Count of data bytes = 0 198 */ 199 smb_sdrc_t 200 smb_pre_delete_directory(smb_request_t *sr) 201 { 202 int rc; 203 204 rc = smbsr_decode_data(sr, "%S", sr, 205 &sr->arg.dirop.fqi.fq_path.pn_path); 206 207 DTRACE_SMB_2(op__DeleteDirectory__start, smb_request_t *, sr, 208 struct dirop *, &sr->arg.dirop); 209 210 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 211 } 212 213 void 214 smb_post_delete_directory(smb_request_t *sr) 215 { 216 DTRACE_SMB_1(op__DeleteDirectory__done, smb_request_t *, sr); 217 } 218 219 smb_sdrc_t 220 smb_com_delete_directory(smb_request_t *sr) 221 { 222 int rc; 223 uint32_t flags = 0; 224 smb_fqi_t *fqi; 225 smb_node_t *tnode; 226 227 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 228 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 229 ERRDOS, ERROR_ACCESS_DENIED); 230 return (SDRC_ERROR); 231 } 232 233 fqi = &sr->arg.dirop.fqi; 234 tnode = sr->tid_tree->t_snode; 235 236 smb_pathname_init(sr, &fqi->fq_path, fqi->fq_path.pn_path); 237 if (!smb_pathname_validate(sr, &fqi->fq_path) || 238 !smb_validate_dirname(sr, &fqi->fq_path)) { 239 return (SDRC_ERROR); 240 } 241 242 rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path, 243 tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp); 244 if (rc != 0) { 245 smbsr_errno(sr, rc); 246 return (SDRC_ERROR); 247 } 248 249 rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, 250 tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode); 251 if (rc != 0) { 252 if (rc == ENOENT) 253 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 254 ERRDOS, ERROR_FILE_NOT_FOUND); 255 else 256 smbsr_errno(sr, rc); 257 smb_node_release(fqi->fq_dnode); 258 return (SDRC_ERROR); 259 } 260 261 /* Do not allow delete of root of share */ 262 if (fqi->fq_fnode == tnode) { 263 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 264 ERRDOS, ERROR_ACCESS_DENIED); 265 smb_node_release(fqi->fq_dnode); 266 smb_node_release(fqi->fq_fnode); 267 return (SDRC_ERROR); 268 } 269 270 rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr); 271 if (rc != 0) { 272 smbsr_errno(sr, rc); 273 smb_node_release(fqi->fq_dnode); 274 smb_node_release(fqi->fq_fnode); 275 return (SDRC_ERROR); 276 } 277 278 if (fqi->fq_fattr.sa_vattr.va_type != VDIR) { 279 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY, 280 ERRDOS, ERROR_PATH_NOT_FOUND); 281 smb_node_release(fqi->fq_dnode); 282 smb_node_release(fqi->fq_fnode); 283 return (SDRC_ERROR); 284 } 285 286 if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) || 287 (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE) 288 != NT_STATUS_SUCCESS)) { 289 smbsr_error(sr, NT_STATUS_CANNOT_DELETE, 290 ERRDOS, ERROR_ACCESS_DENIED); 291 smb_node_release(fqi->fq_dnode); 292 smb_node_release(fqi->fq_fnode); 293 return (SDRC_ERROR); 294 } 295 296 if (SMB_TREE_SUPPORTS_CATIA(sr)) 297 flags |= SMB_CATIA; 298 299 rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode, 300 fqi->fq_fnode->od_name, flags); 301 302 smb_node_release(fqi->fq_fnode); 303 smb_node_release(fqi->fq_dnode); 304 305 if (rc != 0) { 306 if (rc == EEXIST) 307 smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY, 308 ERRDOS, ERROR_DIR_NOT_EMPTY); 309 else 310 smbsr_errno(sr, rc); 311 return (SDRC_ERROR); 312 } 313 314 rc = smbsr_encode_empty_result(sr); 315 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 316 } 317 318 /* 319 * This SMB is used to verify that a path exists and is a directory. No 320 * error is returned if the given path exists and the client has read 321 * access to it. Client machines which maintain a concept of a "working 322 * directory" will find this useful to verify the validity of a "change 323 * working directory" command. Note that the servers do NOT have a concept 324 * of working directory for a particular client. The client must always 325 * supply full pathnames relative to the Tid in the SMB header. 326 * 327 * Client Request Description 328 * ================================== ================================= 329 * 330 * UCHAR WordCount; Count of parameter words = 0 331 * USHORT ByteCount; Count of data bytes; min = 2 332 * UCHAR BufferFormat; 0x04 333 * STRING DirectoryPath[]; Directory path 334 * 335 * Server Response Description 336 * ================================== ================================= 337 * 338 * UCHAR WordCount; Count of parameter words = 0 339 * USHORT ByteCount; Count of data bytes = 0 340 * 341 * DOS clients, in particular, depend on ERRbadpath if the directory is 342 * not found. 343 */ 344 smb_sdrc_t 345 smb_pre_check_directory(smb_request_t *sr) 346 { 347 int rc; 348 349 rc = smbsr_decode_data(sr, "%S", sr, 350 &sr->arg.dirop.fqi.fq_path.pn_path); 351 352 DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr, 353 struct dirop *, &sr->arg.dirop); 354 355 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 356 } 357 358 void 359 smb_post_check_directory(smb_request_t *sr) 360 { 361 DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr); 362 } 363 364 smb_sdrc_t 365 smb_com_check_directory(smb_request_t *sr) 366 { 367 int rc; 368 smb_fqi_t *fqi; 369 smb_node_t *tnode; 370 char *path; 371 smb_pathname_t *pn; 372 373 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 374 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, 375 ERROR_ACCESS_DENIED); 376 return (SDRC_ERROR); 377 } 378 379 fqi = &sr->arg.dirop.fqi; 380 pn = &fqi->fq_path; 381 382 if (pn->pn_path[0] == '\0') { 383 rc = smbsr_encode_empty_result(sr); 384 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 385 } 386 387 smb_pathname_init(sr, pn, pn->pn_path); 388 if (!smb_pathname_validate(sr, pn) || 389 !smb_validate_dirname(sr, pn)) { 390 return (SDRC_ERROR); 391 } 392 393 path = pn->pn_path; 394 tnode = sr->tid_tree->t_snode; 395 396 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 397 &fqi->fq_dnode, fqi->fq_last_comp); 398 if (rc != 0) { 399 smbsr_errno(sr, rc); 400 return (SDRC_ERROR); 401 } 402 403 rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, 404 tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode); 405 smb_node_release(fqi->fq_dnode); 406 if (rc != 0) { 407 if (rc == ENOENT) 408 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 409 ERRDOS, ERROR_PATH_NOT_FOUND); 410 else 411 smbsr_errno(sr, rc); 412 return (SDRC_ERROR); 413 } 414 415 rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr); 416 if (rc != 0) { 417 smbsr_errno(sr, rc); 418 smb_node_release(fqi->fq_fnode); 419 return (SDRC_ERROR); 420 } 421 422 if (fqi->fq_fattr.sa_vattr.va_type != VDIR) { 423 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY, 424 ERRDOS, ERROR_PATH_NOT_FOUND); 425 smb_node_release(fqi->fq_fnode); 426 return (SDRC_ERROR); 427 } 428 429 rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, FILE_TRAVERSE); 430 431 smb_node_release(fqi->fq_fnode); 432 433 if (rc != 0) { 434 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 435 ERRDOS, ERROR_ACCESS_DENIED); 436 return (SDRC_ERROR); 437 } 438 439 rc = smbsr_encode_empty_result(sr); 440 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 441 } 442