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