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 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 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 rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr); 283 if (rc != 0) { 284 smbsr_errno(sr, rc); 285 smb_node_release(fqi->fq_dnode); 286 smb_node_release(fqi->fq_fnode); 287 return (SDRC_ERROR); 288 } 289 290 if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) || 291 (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE) 292 != NT_STATUS_SUCCESS)) { 293 smbsr_error(sr, NT_STATUS_CANNOT_DELETE, 294 ERRDOS, ERROR_ACCESS_DENIED); 295 smb_node_release(fqi->fq_dnode); 296 smb_node_release(fqi->fq_fnode); 297 return (SDRC_ERROR); 298 } 299 300 if (SMB_TREE_SUPPORTS_CATIA(sr)) 301 flags |= SMB_CATIA; 302 303 rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode, 304 fqi->fq_fnode->od_name, flags); 305 306 smb_node_release(fqi->fq_fnode); 307 smb_node_release(fqi->fq_dnode); 308 309 if (rc != 0) { 310 if (rc == EEXIST) 311 smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY, 312 ERRDOS, ERROR_DIR_NOT_EMPTY); 313 else 314 smbsr_errno(sr, rc); 315 return (SDRC_ERROR); 316 } 317 318 rc = smbsr_encode_empty_result(sr); 319 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 320 } 321 322 /* 323 * This SMB is used to verify that a path exists and is a directory. No 324 * error is returned if the given path exists and the client has read 325 * access to it. Client machines which maintain a concept of a "working 326 * directory" will find this useful to verify the validity of a "change 327 * working directory" command. Note that the servers do NOT have a concept 328 * of working directory for a particular client. The client must always 329 * supply full pathnames relative to the Tid in the SMB header. 330 * 331 * Client Request Description 332 * ================================== ================================= 333 * 334 * UCHAR WordCount; Count of parameter words = 0 335 * USHORT ByteCount; Count of data bytes; min = 2 336 * UCHAR BufferFormat; 0x04 337 * STRING DirectoryPath[]; Directory path 338 * 339 * Server Response Description 340 * ================================== ================================= 341 * 342 * UCHAR WordCount; Count of parameter words = 0 343 * USHORT ByteCount; Count of data bytes = 0 344 * 345 * DOS clients, in particular, depend on ERRbadpath if the directory is 346 * not found. 347 */ 348 smb_sdrc_t 349 smb_pre_check_directory(smb_request_t *sr) 350 { 351 int rc; 352 353 rc = smbsr_decode_data(sr, "%S", sr, 354 &sr->arg.dirop.fqi.fq_path.pn_path); 355 356 DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr, 357 struct dirop *, &sr->arg.dirop); 358 359 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 360 } 361 362 void 363 smb_post_check_directory(smb_request_t *sr) 364 { 365 DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr); 366 } 367 368 smb_sdrc_t 369 smb_com_check_directory(smb_request_t *sr) 370 { 371 int rc; 372 smb_fqi_t *fqi; 373 smb_node_t *tnode; 374 smb_node_t *node; 375 char *path; 376 smb_pathname_t *pn; 377 378 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 379 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, 380 ERROR_ACCESS_DENIED); 381 return (SDRC_ERROR); 382 } 383 384 fqi = &sr->arg.dirop.fqi; 385 pn = &fqi->fq_path; 386 387 if (pn->pn_path[0] == '\0') { 388 rc = smbsr_encode_empty_result(sr); 389 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 390 } 391 392 smb_pathname_init(sr, pn, pn->pn_path); 393 if (!smb_pathname_validate(sr, pn) || 394 !smb_validate_dirname(sr, pn)) { 395 return (SDRC_ERROR); 396 } 397 398 path = pn->pn_path; 399 tnode = sr->tid_tree->t_snode; 400 401 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 402 &fqi->fq_dnode, fqi->fq_last_comp); 403 if (rc != 0) { 404 smbsr_errno(sr, rc); 405 return (SDRC_ERROR); 406 } 407 408 rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, 409 tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode); 410 smb_node_release(fqi->fq_dnode); 411 if (rc != 0) { 412 if (rc == ENOENT) 413 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 414 ERRDOS, ERROR_PATH_NOT_FOUND); 415 else 416 smbsr_errno(sr, rc); 417 return (SDRC_ERROR); 418 } 419 420 node = fqi->fq_fnode; 421 if (!smb_node_is_dir(node)) { 422 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY, 423 ERRDOS, ERROR_PATH_NOT_FOUND); 424 smb_node_release(node); 425 return (SDRC_ERROR); 426 } 427 428 if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) { 429 smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); 430 smb_node_release(node); 431 return (SDRC_ERROR); 432 } 433 434 rc = smb_fsop_access(sr, sr->user_cr, node, FILE_TRAVERSE); 435 436 smb_node_release(node); 437 438 if (rc != 0) { 439 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 440 ERRDOS, ERROR_ACCESS_DENIED); 441 return (SDRC_ERROR); 442 } 443 444 rc = smbsr_encode_empty_result(sr); 445 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 446 } 447