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