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