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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * General Structures Layout 28 * ------------------------- 29 * 30 * This is a simplified diagram showing the relationship between most of the 31 * main structures. 32 * 33 * +-------------------+ 34 * | SMB_INFO | 35 * +-------------------+ 36 * | 37 * | 38 * v 39 * +-------------------+ +-------------------+ +-------------------+ 40 * | SESSION |<----->| SESSION |......| SESSION | 41 * +-------------------+ +-------------------+ +-------------------+ 42 * | | 43 * | | 44 * | v 45 * | +-------------------+ +-------------------+ +-------------------+ 46 * | | USER |<--->| USER |...| USER | 47 * | +-------------------+ +-------------------+ +-------------------+ 48 * | 49 * | 50 * v 51 * +-------------------+ +-------------------+ +-------------------+ 52 * | TREE |<----->| TREE |......| TREE | 53 * +-------------------+ +-------------------+ +-------------------+ 54 * | | 55 * | | 56 * | v 57 * | +-------+ +-------+ +-------+ 58 * | | OFILE |<----->| OFILE |......| OFILE | 59 * | +-------+ +-------+ +-------+ 60 * | 61 * | 62 * v 63 * +-------+ +------+ +------+ 64 * | ODIR |<----->| ODIR |......| ODIR | 65 * +-------+ +------+ +------+ 66 * 67 * 68 * Odir State Machine 69 * ------------------ 70 * 71 * +-------------------------+ 72 * | SMB_ODIR_STATE_OPEN |<----------- open / creation 73 * +-------------------------+ 74 * | ^ 75 * | (first) | (last) 76 * | lookup | release 77 * v | 78 * +-------------------------+ 79 * | SMB_ODIR_STATE_IN_USE |---- 80 * +-------------------------+ | lookup / release / read 81 * | ^------- 82 * | close 83 * | 84 * v 85 * +-------------------------+ 86 * | SMB_ODIR_STATE_CLOSING |---- 87 * +-------------------------+ | close / release / read 88 * | ^------- 89 * | (last) release 90 * | 91 * v 92 * +-------------------------+ 93 * | SMB_ODIR_STATE_CLOSED |----------> deletion 94 * +-------------------------+ 95 * 96 * 97 * SMB_ODIR_STATE_OPEN 98 * - the odir exists in the list of odirs of its tree 99 * - lookup is valid in this state. It will place a hold on the odir 100 * by incrementing the reference count and the odir will transition 101 * to SMB_ODIR_STATE_IN_USE 102 * - read/close/release not valid in this state 103 * 104 * SMB_ODIR_STATE_IN_USE 105 * - the odir exists in the list of odirs of its tree. 106 * - lookup is valid in this state. It will place a hold on the odir 107 * by incrementing the reference count. 108 * - if the last hold is released the odir will transition 109 * back to SMB_ODIR_STATE_OPEN 110 * - if a close is received the odir will transition to 111 * SMB_ODIR_STATE_CLOSING. 112 * 113 * SMB_ODIR_STATE_CLOSING 114 * - the odir exists in the list of odirs of its tree. 115 * - lookup will fail in this state. 116 * - when the last hold is released the odir will transition 117 * to SMB_ODIR_STATE_CLOSED. 118 * 119 * SMB_ODIR_STATE_CLOSED 120 * - the odir exists in the list of odirs of its tree. 121 * - there are no users of the odir (refcnt == 0) 122 * - the odir is being removed from the tree's list and deleted. 123 * - lookup will fail in this state. 124 * - read/close/release not valid in this state 125 * 126 * Comments 127 * -------- 128 * The state machine of the odir structures is controlled by 3 elements: 129 * - The list of odirs of the tree it belongs to. 130 * - The mutex embedded in the structure itself. 131 * - The reference count. 132 * 133 * There's a mutex embedded in the odir structure used to protect its fields 134 * and there's a lock embedded in the list of odirs of a tree. To 135 * increment or to decrement the reference count the mutex must be entered. 136 * To insert the odir into the list of odirs of the tree and to remove 137 * the odir from it, the lock must be entered in RW_WRITER mode. 138 * 139 * In order to avoid deadlocks, when both (mutex and lock of the odir 140 * list) have to be entered, the lock must be entered first. 141 * 142 * 143 * Odir Interface 144 * --------------- 145 * smb_odir_open(char *pathname) 146 * Create an odir representing the directory specified in pathname and 147 * add it into the tree's list of odirs. 148 * Returns NT status. 149 * 150 * smb_odir_openfh(smb_ofile_t *of) 151 * Create an odir representing the directory specified by the 152 * existing open handle (from a prior open of the directory). 153 * Returns NT status. 154 * 155 * smb_odir_openat(smb_node_t *unode) 156 * Create an odir representing the extended attribute directory 157 * associated with the file (or directory) represented by unode 158 * and add it into the tree's list of odirs. 159 * Returns NT status. 160 * 161 * smb_odir_t *odir = smb_tree_lookup_odir(..., odid) 162 * Find the odir corresponding to the specified odid in the tree's 163 * list of odirs. Place a hold on the odir. 164 * 165 * smb_odir_read(..., smb_odirent_t *odirent) 166 * Find the next directory entry in the odir and return it in odirent. 167 * 168 * smb_odir_read_fileinfo(..., smb_fileinfo_t *) 169 * Find the next directory entry in the odir. Return the details of 170 * the directory entry in smb_fileinfo_t. (See odir internals below) 171 * 172 * smb_odir_read_streaminfo(..., smb_streaminfo_t *) 173 * Find the next named stream entry in the odir. Return the details of 174 * the named stream in smb_streaminfo_t. 175 * 176 * smb_odir_close(smb_odir_t *odir) 177 * Close the odir. 178 * The caller of close must have a hold on the odir being closed. 179 * The hold should be released after closing. 180 * 181 * smb_odir_release(smb_odir_t *odir) 182 * Release the hold on the odir, obtained by lookup. 183 * 184 * 185 * Odir Internals 186 * -------------- 187 * The odir object represent an open directory search. Each read operation 188 * provides the caller with a structure containing information pertaining 189 * to the next directory entry that matches the search criteria, namely 190 * the filename or match pattern and, in the case of smb_odir_read_fileinfo(), 191 * the search attributes. 192 * 193 * The odir maintains a buffer (d_buf) of directory entries read from 194 * the filesystem via a vop_readdir. The buffer is populated when a read 195 * request (smb_odir_next_odirent) finds that the buffer is empty or that 196 * the end of the buffer has been reached, and also when a new client request 197 * (find next) begins. 198 * 199 * The data in d_buf (that which is returned from the file system) can 200 * be in one of two formats. If the file system supports extended directory 201 * entries we request that the data be returned as edirent_t structures. If 202 * it does not the data will be returned as dirent64_t structures. For 203 * convenience, when the next directory entry is read from d_buf by 204 * smb_odir_next_odirent it is translated into an smb_odirent_t. 205 * 206 * smb_odir_read_fileinfo 207 * The processing required to obtain the information to populate the caller's 208 * smb_fileinfo_t differs depending upon whether the directory search is for a 209 * single specified filename or for multiple files matching a search pattern. 210 * Thus smb_odir_read_fileinfo uses two static functions: 211 * smb_odir_single_fileinfo - obtains the smb_fileinfo_t info for the single 212 * filename as specified in smb_odir_open request. 213 * smb_odir_wildcard_fileinfo - obtains the smb_fileinfo_t info for the filename 214 * returned from the smb_odir_next_odirent. This is called in a loop until 215 * an entry matching the search criteria is found or no more entries exist. 216 * 217 * If a directory entry is a VLNK, the name returned in the smb_fileinfo_t 218 * is the name of the directory entry but the attributes are the attribites 219 * of the file that is the target of the link. If the link target cannot 220 * be found the attributes returned are the attributes of the link itself. 221 * 222 * smb_odir_read_streaminfo 223 * In order for an odir to provide information about stream files it 224 * must be opened with smb_odir_openat(). smb_odir_read_streaminfo() can 225 * then be used to obtain the name and size of named stream files. 226 * 227 * Resuming a Search 228 * ----------------- 229 * A directory search often consists of multiple client requests: an initial 230 * find_first request followed by zero or more find_next requests and a 231 * find_close request. 232 * The find_first request will open and lookup the odir, read its desired 233 * number of entries from the odir, then release the odir and return. 234 * A find_next request will lookup the odir and read its desired number of 235 * entries from the odir, then release the odir and return. 236 * At the end of the search the find_close request will close the odir. 237 * 238 * In order to be able to resume a directory search (find_next) the odir 239 * provides the capability for the caller to save one or more resume points 240 * (cookies) at the end of a request, and to specify which resume point 241 * (cookie) to restart from at the beginning of the next search. 242 * smb_odir_save_cookie(..., cookie) 243 * smb_odir_resume_at(smb_odir_resume_t *resume) 244 * A search can be resumed at a specified resume point (cookie), the resume 245 * point (cookie) stored at a specified index in the d_cookies array, or 246 * a specified filename. The latter (specified filename) is not yet supported. 247 * 248 * See smb_search, smb_find, smb_find_unique, and smb_trans2_find for details 249 */ 250 251 #include <smbsrv/smb_kproto.h> 252 #include <smbsrv/smb_fsops.h> 253 #include <smbsrv/smb_share.h> 254 #include <sys/extdirent.h> 255 256 /* static functions */ 257 static smb_odir_t *smb_odir_create(smb_request_t *, smb_node_t *, 258 const char *, uint16_t, uint16_t, cred_t *); 259 static int smb_odir_single_fileinfo(smb_request_t *, smb_odir_t *, 260 smb_fileinfo_t *); 261 static int smb_odir_wildcard_fileinfo(smb_request_t *, smb_odir_t *, 262 smb_odirent_t *, smb_fileinfo_t *); 263 static int smb_odir_next_odirent(smb_odir_t *, smb_odirent_t *); 264 static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *, 265 char *, smb_node_t **); 266 static boolean_t smb_odir_match_name(smb_odir_t *, smb_odirent_t *); 267 268 269 /* 270 * smb_odir_openpath 271 * 272 * Create an odir representing the directory specified in pathname. 273 * 274 * Returns: 275 * NT Status 276 */ 277 uint32_t 278 smb_odir_openpath(smb_request_t *sr, char *path, uint16_t sattr, 279 uint32_t flags, smb_odir_t **odp) 280 { 281 int rc; 282 smb_tree_t *tree; 283 smb_node_t *dnode; 284 char pattern[MAXNAMELEN]; 285 uint16_t odid; 286 cred_t *cr; 287 288 ASSERT(sr); 289 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 290 ASSERT(sr->tid_tree); 291 ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC); 292 *odp = NULL; 293 294 tree = sr->tid_tree; 295 296 if (sr->session->dialect < NT_LM_0_12) 297 smb_convert_wildcards(path); 298 299 rc = smb_pathname_reduce(sr, sr->user_cr, path, 300 tree->t_snode, tree->t_snode, &dnode, pattern); 301 if (rc != 0) 302 return (smb_errno2status(rc)); 303 304 if (!smb_node_is_dir(dnode)) { 305 smb_node_release(dnode); 306 return (NT_STATUS_OBJECT_PATH_NOT_FOUND); 307 } 308 309 if (smb_fsop_access(sr, sr->user_cr, dnode, FILE_LIST_DIRECTORY) != 0) { 310 smb_node_release(dnode); 311 return (NT_STATUS_ACCESS_DENIED); 312 } 313 314 if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) { 315 smb_node_release(dnode); 316 return (NT_STATUS_TOO_MANY_OPENED_FILES); 317 } 318 319 if (flags & SMB_ODIR_OPENF_BACKUP_INTENT) 320 cr = smb_user_getprivcred(sr->uid_user); 321 else 322 cr = sr->uid_user->u_cred; 323 324 *odp = smb_odir_create(sr, dnode, pattern, sattr, odid, cr); 325 smb_node_release(dnode); 326 327 return (0); 328 } 329 330 /* 331 * smb_odir_openfh 332 * 333 * Create an odir representing the directory already opened on "of". 334 * 335 * Returns: 336 * NT status 337 */ 338 uint32_t 339 smb_odir_openfh(smb_request_t *sr, const char *pattern, uint16_t sattr, 340 smb_odir_t **odp) 341 { 342 smb_ofile_t *of = sr->fid_ofile; 343 344 *odp = NULL; 345 346 if (of->f_node == NULL || !smb_node_is_dir(of->f_node)) 347 return (NT_STATUS_INVALID_PARAMETER); 348 349 if ((of->f_granted_access & FILE_LIST_DIRECTORY) == 0) 350 return (NT_STATUS_ACCESS_DENIED); 351 352 *odp = smb_odir_create(sr, of->f_node, pattern, sattr, 0, of->f_cr); 353 354 return (0); 355 } 356 357 /* 358 * smb_odir_openat 359 * 360 * Create an odir representing the extended attribute directory 361 * associated with the file (or directory) represented by unode. 362 * 363 * Returns: 364 * NT status 365 */ 366 uint32_t 367 smb_odir_openat(smb_request_t *sr, smb_node_t *unode, smb_odir_t **odp) 368 { 369 char pattern[SMB_STREAM_PREFIX_LEN + 2]; 370 vnode_t *xattr_dvp; 371 cred_t *cr; 372 smb_node_t *xattr_dnode; 373 int rc; 374 375 ASSERT(sr); 376 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 377 ASSERT(unode); 378 ASSERT(unode->n_magic == SMB_NODE_MAGIC); 379 *odp = NULL; 380 381 if (SMB_TREE_CONTAINS_NODE(sr, unode) == 0 || 382 SMB_TREE_HAS_ACCESS(sr, ACE_LIST_DIRECTORY) == 0) 383 return (NT_STATUS_ACCESS_DENIED); 384 385 cr = zone_kcred(); 386 387 /* find the xattrdir vnode */ 388 rc = smb_vop_lookup_xattrdir(unode->vp, &xattr_dvp, LOOKUP_XATTR, cr); 389 if (rc != 0) 390 return (smb_errno2status(rc)); 391 392 /* lookup the xattrdir's smb_node */ 393 xattr_dnode = smb_node_lookup(sr, NULL, cr, xattr_dvp, XATTR_DIR, 394 unode, NULL); 395 VN_RELE(xattr_dvp); 396 if (xattr_dnode == NULL) 397 return (NT_STATUS_NO_MEMORY); 398 399 (void) snprintf(pattern, sizeof (pattern), "%s*", SMB_STREAM_PREFIX); 400 *odp = smb_odir_create(sr, xattr_dnode, pattern, 401 SMB_SEARCH_ATTRIBUTES, 0, cr); 402 403 smb_node_release(xattr_dnode); 404 return (0); 405 } 406 407 /* 408 * smb_odir_hold 409 * 410 * A hold will only be granted if the odir is open or in_use. 411 */ 412 boolean_t 413 smb_odir_hold(smb_odir_t *od) 414 { 415 ASSERT(od); 416 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 417 418 mutex_enter(&od->d_mutex); 419 420 switch (od->d_state) { 421 case SMB_ODIR_STATE_OPEN: 422 od->d_refcnt++; 423 od->d_state = SMB_ODIR_STATE_IN_USE; 424 break; 425 case SMB_ODIR_STATE_IN_USE: 426 od->d_refcnt++; 427 break; 428 case SMB_ODIR_STATE_CLOSING: 429 case SMB_ODIR_STATE_CLOSED: 430 default: 431 mutex_exit(&od->d_mutex); 432 return (B_FALSE); 433 } 434 435 mutex_exit(&od->d_mutex); 436 return (B_TRUE); 437 } 438 439 /* 440 * If the odir is in SMB_ODIR_STATE_CLOSING and this release results in 441 * a refcnt of 0, change the state to SMB_ODIR_STATE_CLOSED and post the 442 * object for deletion. Object deletion is deferred to avoid modifying 443 * a list while an iteration may be in progress. 444 */ 445 void 446 smb_odir_release(smb_odir_t *od) 447 { 448 SMB_ODIR_VALID(od); 449 450 mutex_enter(&od->d_mutex); 451 ASSERT(od->d_refcnt > 0); 452 453 switch (od->d_state) { 454 case SMB_ODIR_STATE_OPEN: 455 break; 456 case SMB_ODIR_STATE_IN_USE: 457 od->d_refcnt--; 458 if (od->d_refcnt == 0) 459 od->d_state = SMB_ODIR_STATE_OPEN; 460 break; 461 case SMB_ODIR_STATE_CLOSING: 462 od->d_refcnt--; 463 if (od->d_refcnt == 0) { 464 od->d_state = SMB_ODIR_STATE_CLOSED; 465 smb_tree_post_odir(od->d_tree, od); 466 } 467 break; 468 case SMB_ODIR_STATE_CLOSED: 469 default: 470 break; 471 } 472 473 mutex_exit(&od->d_mutex); 474 } 475 476 /* 477 * smb_odir_close 478 */ 479 void 480 smb_odir_close(smb_odir_t *od) 481 { 482 ASSERT(od); 483 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 484 485 mutex_enter(&od->d_mutex); 486 ASSERT(od->d_refcnt > 0); 487 switch (od->d_state) { 488 case SMB_ODIR_STATE_OPEN: 489 break; 490 case SMB_ODIR_STATE_IN_USE: 491 od->d_state = SMB_ODIR_STATE_CLOSING; 492 break; 493 case SMB_ODIR_STATE_CLOSING: 494 case SMB_ODIR_STATE_CLOSED: 495 default: 496 break; 497 } 498 mutex_exit(&od->d_mutex); 499 } 500 501 /* 502 * smb_odir_read 503 * 504 * Find the next directory entry matching the search pattern. 505 * No search attribute matching is performed. 506 * 507 * Returns: 508 * 0 - success. 509 * - If a matching entry was found eof will be B_FALSE and 510 * odirent will be populated. 511 * ENOENT 512 * - If we've scanned to the end, eof will be B_TRUE. 513 * errno - other errors 514 */ 515 int 516 smb_odir_read(smb_request_t *sr, smb_odir_t *od, 517 smb_odirent_t *odirent, boolean_t *eof) 518 { 519 int rc; 520 521 ASSERT(sr); 522 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 523 ASSERT(od); 524 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 525 ASSERT(odirent); 526 527 mutex_enter(&od->d_mutex); 528 ASSERT(od->d_refcnt > 0); 529 530 switch (od->d_state) { 531 case SMB_ODIR_STATE_IN_USE: 532 case SMB_ODIR_STATE_CLOSING: 533 break; 534 case SMB_ODIR_STATE_OPEN: 535 case SMB_ODIR_STATE_CLOSED: 536 default: 537 mutex_exit(&od->d_mutex); 538 return (EBADF); 539 } 540 541 for (;;) { 542 if ((rc = smb_odir_next_odirent(od, odirent)) != 0) 543 break; 544 if (smb_odir_match_name(od, odirent)) 545 break; 546 } 547 548 mutex_exit(&od->d_mutex); 549 550 switch (rc) { 551 case 0: 552 *eof = B_FALSE; 553 return (0); 554 case ENOENT: 555 *eof = B_TRUE; 556 /* FALLTHROUGH */ 557 default: 558 return (rc); 559 } 560 } 561 562 /* 563 * smb_odir_read_fileinfo 564 * 565 * Find the next directory entry matching the search pattern 566 * and attributes: od->d_pattern and od->d_sattr. 567 * 568 * If the search pattern specifies a single filename call 569 * smb_odir_single_fileinfo to get the file attributes and 570 * populate the caller's smb_fileinfo_t. 571 * 572 * If the search pattern contains wildcards call smb_odir_next_odirent 573 * to get the next directory entry then. Repeat until a matching 574 * filename is found. Call smb_odir_wildcard_fileinfo to get the 575 * file attributes and populate the caller's smb_fileinfo_t. 576 * This is repeated until a file matching the search criteria is found. 577 * 578 * Returns: 579 * 0 - success. 580 * - If a matching entry was found eof will be B_FALSE and 581 * fileinfo will be populated. 582 * ENOENT 583 * - If at end of dir, eof will be B_TRUE. 584 * errno - other error 585 */ 586 int 587 smb_odir_read_fileinfo(smb_request_t *sr, smb_odir_t *od, 588 smb_fileinfo_t *fileinfo, uint16_t *eof) 589 { 590 int rc, errnum; 591 smb_odirent_t *odirent; 592 593 ASSERT(sr); 594 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 595 ASSERT(od); 596 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 597 ASSERT(fileinfo); 598 599 mutex_enter(&od->d_mutex); 600 ASSERT(od->d_refcnt > 0); 601 602 switch (od->d_state) { 603 case SMB_ODIR_STATE_IN_USE: 604 case SMB_ODIR_STATE_CLOSING: 605 break; 606 case SMB_ODIR_STATE_OPEN: 607 case SMB_ODIR_STATE_CLOSED: 608 default: 609 mutex_exit(&od->d_mutex); 610 return (EBADF); 611 } 612 613 if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) { 614 if (od->d_eof) 615 rc = ENOENT; 616 else 617 rc = smb_odir_single_fileinfo(sr, od, fileinfo); 618 od->d_eof = B_TRUE; 619 } else { 620 odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 621 for (;;) { 622 bzero(fileinfo, sizeof (smb_fileinfo_t)); 623 if ((rc = smb_odir_next_odirent(od, odirent)) != 0) 624 break; 625 626 /* skip non utf8 filename */ 627 if (u8_validate(odirent->od_name, 628 strlen(odirent->od_name), NULL, 629 U8_VALIDATE_ENTIRE, &errnum) < 0) 630 continue; 631 632 if (!smb_odir_match_name(od, odirent)) 633 continue; 634 635 rc = smb_odir_wildcard_fileinfo(sr, od, odirent, 636 fileinfo); 637 if (rc == 0) 638 break; 639 } 640 kmem_free(odirent, sizeof (smb_odirent_t)); 641 } 642 mutex_exit(&od->d_mutex); 643 644 switch (rc) { 645 case 0: 646 *eof = 0; 647 return (0); 648 case ENOENT: 649 *eof = 1; /* per. FindFirst, FindNext spec. */ 650 /* FALLTHROUGH */ 651 default: 652 return (rc); 653 } 654 } 655 656 /* 657 * smb_odir_read_streaminfo 658 * 659 * Find the next directory entry whose name begins with SMB_STREAM_PREFIX, 660 * and thus represents an NTFS named stream. 661 * No search attribute matching is performed. 662 * No case conflict name mangling is required for NTFS named stream names. 663 * 664 * Returns: 665 * 0 - success. 666 * - If a matching entry was found eof will be B_FALSE and 667 * sinfo will be populated. 668 * - If there are no matching entries eof will be B_TRUE. 669 * errno - error 670 */ 671 int 672 smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od, 673 smb_streaminfo_t *sinfo, boolean_t *eof) 674 { 675 int rc; 676 cred_t *kcr; 677 smb_odirent_t *odirent; 678 smb_node_t *fnode; 679 smb_attr_t attr; 680 681 ASSERT(sr); 682 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 683 ASSERT(od); 684 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 685 ASSERT(sinfo); 686 687 kcr = zone_kcred(); 688 689 mutex_enter(&od->d_mutex); 690 ASSERT(od->d_refcnt > 0); 691 692 switch (od->d_state) { 693 case SMB_ODIR_STATE_IN_USE: 694 case SMB_ODIR_STATE_CLOSING: 695 break; 696 case SMB_ODIR_STATE_OPEN: 697 case SMB_ODIR_STATE_CLOSED: 698 default: 699 mutex_exit(&od->d_mutex); 700 return (EBADF); 701 } 702 703 /* Check that odir represents an xattr directory */ 704 if (!(od->d_flags & SMB_ODIR_FLAG_XATTR)) { 705 *eof = B_TRUE; 706 mutex_exit(&od->d_mutex); 707 return (0); 708 } 709 710 odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 711 bzero(&attr, sizeof (attr)); 712 713 for (;;) { 714 bzero(sinfo, sizeof (smb_streaminfo_t)); 715 if ((rc = smb_odir_next_odirent(od, odirent)) != 0) 716 break; 717 718 if (strncmp(odirent->od_name, SMB_STREAM_PREFIX, 719 SMB_STREAM_PREFIX_LEN)) { 720 continue; 721 } 722 723 rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode, 724 od->d_dnode, odirent->od_name, &fnode); 725 if (rc == 0) { 726 /* 727 * We just need the file sizes, and don't want 728 * EACCES failures here, so use kcred and pass 729 * NULL as the sr to skip sr->fid-ofile checks. 730 */ 731 attr.sa_mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ; 732 rc = smb_node_getattr(NULL, fnode, kcr, NULL, &attr); 733 smb_node_release(fnode); 734 } 735 736 if (rc == 0) { 737 (void) strlcpy(sinfo->si_name, 738 odirent->od_name + SMB_STREAM_PREFIX_LEN, 739 sizeof (sinfo->si_name)); 740 sinfo->si_size = attr.sa_vattr.va_size; 741 sinfo->si_alloc_size = attr.sa_allocsz; 742 break; 743 } 744 } 745 mutex_exit(&od->d_mutex); 746 747 kmem_free(odirent, sizeof (smb_odirent_t)); 748 749 switch (rc) { 750 case 0: 751 *eof = B_FALSE; 752 return (0); 753 case ENOENT: 754 *eof = B_TRUE; 755 return (0); 756 default: 757 return (rc); 758 } 759 } 760 761 /* 762 * smb_odir_save_cookie 763 * 764 * Callers can save up to SMB_MAX_SEARCH cookies in the odir 765 * to be used as resume points for a 'find next' request. 766 */ 767 void 768 smb_odir_save_cookie(smb_odir_t *od, int idx, uint32_t cookie) 769 { 770 ASSERT(od); 771 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 772 ASSERT(idx >= 0 && idx < SMB_MAX_SEARCH); 773 774 mutex_enter(&od->d_mutex); 775 od->d_cookies[idx] = cookie; 776 mutex_exit(&od->d_mutex); 777 } 778 779 /* 780 * smb_odir_save_fname 781 * 782 * Save a filename / offset pair, which are basically a 783 * one entry cache. See smb_com_trans2_find_next2. 784 */ 785 void 786 smb_odir_save_fname(smb_odir_t *od, uint32_t cookie, const char *fname) 787 { 788 ASSERT(od); 789 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 790 791 mutex_enter(&od->d_mutex); 792 793 od->d_last_cookie = cookie; 794 bzero(od->d_last_name, MAXNAMELEN); 795 if (fname != NULL) 796 (void) strlcpy(od->d_last_name, fname, MAXNAMELEN); 797 798 mutex_exit(&od->d_mutex); 799 } 800 801 /* 802 * smb_odir_resume_at 803 * 804 * If SMB_ODIR_FLAG_WILDCARDS is not set, and we're rewinding, 805 * assume we're no longer at EOF. 806 * 807 * Wildcard searching can be resumed from: 808 * - the cookie saved at a specified index (SMBsearch, SMBfind). 809 * - a specified cookie (SMB_trans2_find) 810 * - a specified filename (SMB_trans2_find) - NOT SUPPORTED. 811 * Defaults to continuing from where the last search ended. 812 * 813 * Continuation from where the last search ended (SMB_trans2_find) 814 * is implemented by saving the last cookie at a specific index (0) 815 * smb_odir_resume_at indicates a new request, so reset od->d_bufptr 816 * and d_eof to force a vop_readdir. 817 */ 818 void 819 smb_odir_resume_at(smb_odir_t *od, smb_odir_resume_t *resume) 820 { 821 uint64_t save_offset; 822 823 ASSERT(od); 824 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 825 ASSERT(resume); 826 827 if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) { 828 if (resume->or_type == SMB_ODIR_RESUME_COOKIE) 829 od->d_eof = B_FALSE; 830 return; 831 } 832 mutex_enter(&od->d_mutex); 833 834 save_offset = od->d_offset; 835 switch (resume->or_type) { 836 837 default: 838 case SMB_ODIR_RESUME_CONT: 839 /* Continue where we left off. */ 840 break; 841 842 case SMB_ODIR_RESUME_IDX: 843 /* 844 * This is used only by the (ancient) SMB_SEARCH. 845 * Modern clients use trans2 FindFirst, FindNext. 846 */ 847 ASSERT(resume->or_idx >= 0); 848 ASSERT(resume->or_idx < SMB_MAX_SEARCH); 849 850 if ((resume->or_idx < 0) || 851 (resume->or_idx >= SMB_MAX_SEARCH)) { 852 resume->or_idx = 0; 853 } 854 od->d_offset = od->d_cookies[resume->or_idx]; 855 break; 856 857 case SMB_ODIR_RESUME_COOKIE: 858 od->d_offset = resume->or_cookie; 859 break; 860 861 case SMB_ODIR_RESUME_FNAME: 862 /* 863 * If the name matches the last one saved, 864 * use the offset that was saved with it in 865 * the odir. Otherwise use the cookie value 866 * in the resume data from the client. 867 */ 868 if (strcmp(resume->or_fname, od->d_last_name) && 869 od->d_last_cookie != 0) { 870 od->d_offset = od->d_last_cookie; 871 } else if (resume->or_cookie != 0) { 872 od->d_offset = resume->or_cookie; 873 } /* else continue where we left off */ 874 break; 875 } 876 877 if (od->d_offset != save_offset) { 878 /* Force a vop_readdir to refresh d_buf */ 879 od->d_bufptr = NULL; 880 od->d_eof = B_FALSE; 881 } 882 883 mutex_exit(&od->d_mutex); 884 } 885 886 887 /* *** static functions *** */ 888 889 /* 890 * smb_odir_create 891 * Allocate and populate an odir obect and add it to the tree's list. 892 */ 893 static smb_odir_t * 894 smb_odir_create(smb_request_t *sr, smb_node_t *dnode, 895 const char *pattern, uint16_t sattr, uint16_t odid, cred_t *cr) 896 { 897 smb_odir_t *od; 898 smb_tree_t *tree; 899 900 ASSERT(sr); 901 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 902 ASSERT(sr->tid_tree); 903 ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC); 904 ASSERT(dnode); 905 ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 906 907 tree = sr->tid_tree; 908 909 od = kmem_cache_alloc(smb_cache_odir, KM_SLEEP); 910 bzero(od, sizeof (smb_odir_t)); 911 912 mutex_init(&od->d_mutex, NULL, MUTEX_DEFAULT, NULL); 913 914 /* 915 * Return this to the caller as if they had done 916 * smb_tree_lookup_odir() to obtain the odir. 917 */ 918 od->d_refcnt = 1; 919 od->d_state = SMB_ODIR_STATE_IN_USE; 920 od->d_magic = SMB_ODIR_MAGIC; 921 od->d_opened_by_pid = sr->smb_pid; 922 od->d_session = tree->t_session; 923 od->d_cred = cr; 924 /* 925 * grab a ref for od->d_user 926 * released in smb_odir_delete() 927 */ 928 smb_user_hold_internal(sr->uid_user); 929 od->d_user = sr->uid_user; 930 od->d_tree = tree; 931 od->d_dnode = dnode; 932 smb_node_ref(dnode); 933 od->d_odid = odid; 934 od->d_sattr = sattr; 935 (void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern)); 936 od->d_flags = 0; 937 if (smb_contains_wildcards(od->d_pattern)) 938 od->d_flags |= SMB_ODIR_FLAG_WILDCARDS; 939 if (vfs_has_feature(dnode->vp->v_vfsp, VFSFT_DIRENTFLAGS)) 940 od->d_flags |= SMB_ODIR_FLAG_EDIRENT; 941 if (smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE)) 942 od->d_flags |= SMB_ODIR_FLAG_IGNORE_CASE; 943 if (smb_tree_has_feature(tree, SMB_TREE_SHORTNAMES)) 944 od->d_flags |= SMB_ODIR_FLAG_SHORTNAMES; 945 if (SMB_TREE_SUPPORTS_CATIA(sr)) 946 od->d_flags |= SMB_ODIR_FLAG_CATIA; 947 if (SMB_TREE_SUPPORTS_ABE(sr)) 948 od->d_flags |= SMB_ODIR_FLAG_ABE; 949 if (dnode->flags & NODE_XATTR_DIR) 950 od->d_flags |= SMB_ODIR_FLAG_XATTR; 951 od->d_eof = B_FALSE; 952 953 smb_llist_enter(&tree->t_odir_list, RW_WRITER); 954 smb_llist_insert_tail(&tree->t_odir_list, od); 955 smb_llist_exit(&tree->t_odir_list); 956 957 atomic_inc_32(&tree->t_session->s_dir_cnt); 958 return (od); 959 } 960 961 /* 962 * Set a new pattern, attributes, and rewind. 963 */ 964 void 965 smb_odir_reopen(smb_odir_t *od, const char *pattern, uint16_t sattr) 966 { 967 968 SMB_ODIR_VALID(od); 969 970 mutex_enter(&od->d_mutex); 971 od->d_sattr = sattr; 972 (void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern)); 973 if (smb_contains_wildcards(od->d_pattern)) 974 od->d_flags |= SMB_ODIR_FLAG_WILDCARDS; 975 else 976 od->d_flags &= ~SMB_ODIR_FLAG_WILDCARDS; 977 978 /* Internal smb_odir_resume_at */ 979 od->d_offset = 0; 980 od->d_bufptr = NULL; 981 od->d_eof = B_FALSE; 982 983 mutex_exit(&od->d_mutex); 984 } 985 986 /* 987 * Delete an odir. 988 * 989 * Remove the odir from the tree list before freeing resources 990 * associated with the odir. 991 */ 992 void 993 smb_odir_delete(void *arg) 994 { 995 smb_tree_t *tree; 996 smb_odir_t *od = (smb_odir_t *)arg; 997 998 SMB_ODIR_VALID(od); 999 ASSERT(od->d_refcnt == 0); 1000 ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED); 1001 1002 tree = od->d_tree; 1003 smb_llist_enter(&tree->t_odir_list, RW_WRITER); 1004 smb_llist_remove(&tree->t_odir_list, od); 1005 if (od->d_odid != 0) 1006 smb_idpool_free(&tree->t_odid_pool, od->d_odid); 1007 atomic_dec_32(&tree->t_session->s_dir_cnt); 1008 smb_llist_exit(&tree->t_odir_list); 1009 1010 mutex_enter(&od->d_mutex); 1011 mutex_exit(&od->d_mutex); 1012 1013 od->d_magic = 0; 1014 smb_node_release(od->d_dnode); 1015 smb_user_release(od->d_user); 1016 mutex_destroy(&od->d_mutex); 1017 kmem_cache_free(smb_cache_odir, od); 1018 } 1019 1020 /* 1021 * smb_odir_next_odirent 1022 * 1023 * Find the next directory entry in d_buf. If d_bufptr is NULL (buffer 1024 * is empty or we've reached the end of it), read the next set of 1025 * entries from the file system (vop_readdir). 1026 * 1027 * File systems which support VFSFT_EDIRENT_FLAGS will return the 1028 * directory entries as a buffer of edirent_t structure. Others will 1029 * return a buffer of dirent64_t structures. For simplicity translate 1030 * the data into an smb_odirent_t structure. 1031 * The ed_name/d_name in d_buf is NULL terminated by the file system. 1032 * 1033 * Some file systems can have directories larger than SMB_MAXDIRSIZE. 1034 * If the odirent offset >= SMB_MAXDIRSIZE return ENOENT and set d_eof 1035 * to true to stop subsequent calls to smb_vop_readdir. 1036 * 1037 * Returns: 1038 * 0 - success. odirent is populated with the next directory entry 1039 * ENOENT - no more directory entries 1040 * errno - error 1041 */ 1042 static int 1043 smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent) 1044 { 1045 int rc; 1046 int reclen; 1047 int eof; 1048 dirent64_t *dp; 1049 edirent_t *edp; 1050 char *np; 1051 uint32_t abe_flag = 0; 1052 1053 ASSERT(MUTEX_HELD(&od->d_mutex)); 1054 1055 bzero(odirent, sizeof (smb_odirent_t)); 1056 1057 if (od->d_bufptr != NULL) { 1058 if (od->d_flags & SMB_ODIR_FLAG_EDIRENT) 1059 reclen = od->d_edp->ed_reclen; 1060 else 1061 reclen = od->d_dp->d_reclen; 1062 1063 if (reclen == 0) { 1064 od->d_bufptr = NULL; 1065 } else { 1066 od->d_bufptr += reclen; 1067 if (od->d_bufptr >= od->d_buf + od->d_bufsize) 1068 od->d_bufptr = NULL; 1069 } 1070 } 1071 1072 if (od->d_bufptr == NULL) { 1073 if (od->d_eof) 1074 return (ENOENT); 1075 1076 od->d_bufsize = sizeof (od->d_buf); 1077 1078 if (od->d_flags & SMB_ODIR_FLAG_ABE) 1079 abe_flag = SMB_ABE; 1080 1081 rc = smb_vop_readdir(od->d_dnode->vp, od->d_offset, 1082 od->d_buf, &od->d_bufsize, &eof, abe_flag, od->d_cred); 1083 1084 if ((rc == 0) && (od->d_bufsize == 0)) 1085 rc = ENOENT; 1086 1087 if (rc != 0) { 1088 od->d_bufptr = NULL; 1089 od->d_bufsize = 0; 1090 return (rc); 1091 } 1092 1093 od->d_eof = (eof != 0); 1094 od->d_bufptr = od->d_buf; 1095 } 1096 1097 if (od->d_flags & SMB_ODIR_FLAG_EDIRENT) 1098 od->d_offset = od->d_edp->ed_off; 1099 else 1100 od->d_offset = od->d_dp->d_off; 1101 1102 if (od->d_offset >= SMB_MAXDIRSIZE) { 1103 od->d_bufptr = NULL; 1104 od->d_bufsize = 0; 1105 od->d_eof = B_TRUE; 1106 return (ENOENT); 1107 } 1108 1109 if (od->d_flags & SMB_ODIR_FLAG_EDIRENT) { 1110 edp = od->d_edp; 1111 odirent->od_ino = edp->ed_ino; 1112 odirent->od_eflags = edp->ed_eflags; 1113 np = edp->ed_name; 1114 } else { 1115 dp = od->d_dp; 1116 odirent->od_ino = dp->d_ino; 1117 odirent->od_eflags = 0; 1118 np = dp->d_name; 1119 } 1120 1121 if ((od->d_flags & SMB_ODIR_FLAG_CATIA) && 1122 ((od->d_flags & SMB_ODIR_FLAG_XATTR) == 0)) { 1123 smb_vop_catia_v4tov5(np, odirent->od_name, 1124 sizeof (odirent->od_name)); 1125 } else { 1126 (void) strlcpy(odirent->od_name, np, 1127 sizeof (odirent->od_name)); 1128 } 1129 1130 return (0); 1131 } 1132 1133 /* 1134 * smb_odir_single_fileinfo 1135 * 1136 * Lookup the file identified by od->d_pattern. 1137 * 1138 * If the looked up file is a link, we attempt to lookup the link target 1139 * to use its attributes in place of those of the files's. 1140 * If we fail to lookup the target of the link we use the original 1141 * file's attributes. 1142 * Check if the attributes match the search attributes. 1143 * 1144 * Returns: 0 - success 1145 * ENOENT - no match 1146 * errno - error 1147 */ 1148 static int 1149 smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od, 1150 smb_fileinfo_t *fileinfo) 1151 { 1152 int rc; 1153 smb_node_t *fnode, *tgt_node; 1154 smb_attr_t attr; 1155 ino64_t fid; 1156 char *name; 1157 boolean_t case_conflict = B_FALSE; 1158 int lookup_flags, flags = 0; 1159 vnode_t *vp; 1160 1161 ASSERT(sr); 1162 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 1163 ASSERT(od); 1164 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1165 1166 ASSERT(MUTEX_HELD(&od->d_mutex)); 1167 bzero(fileinfo, sizeof (smb_fileinfo_t)); 1168 1169 rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode, 1170 od->d_dnode, od->d_pattern, &fnode); 1171 if (rc != 0) 1172 return (rc); 1173 1174 /* 1175 * If case sensitive, do a case insensitive smb_vop_lookup to 1176 * check for case conflict 1177 */ 1178 if (od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) { 1179 lookup_flags = SMB_IGNORE_CASE; 1180 if (od->d_flags & SMB_ODIR_FLAG_CATIA) 1181 lookup_flags |= SMB_CATIA; 1182 1183 rc = smb_vop_lookup(od->d_dnode->vp, fnode->od_name, &vp, 1184 NULL, lookup_flags, &flags, od->d_tree->t_snode->vp, 1185 NULL, od->d_cred); 1186 if (rc != 0) 1187 return (rc); 1188 VN_RELE(vp); 1189 1190 if (flags & ED_CASE_CONFLICT) 1191 case_conflict = B_TRUE; 1192 } 1193 1194 bzero(&attr, sizeof (attr)); 1195 attr.sa_mask = SMB_AT_ALL; 1196 rc = smb_node_getattr(NULL, fnode, zone_kcred(), NULL, &attr); 1197 if (rc != 0) { 1198 smb_node_release(fnode); 1199 return (rc); 1200 } 1201 1202 1203 /* follow link to get target node & attr */ 1204 if (smb_node_is_symlink(fnode) && 1205 smb_odir_lookup_link(sr, od, fnode->od_name, &tgt_node)) { 1206 smb_node_release(fnode); 1207 fnode = tgt_node; 1208 attr.sa_mask = SMB_AT_ALL; 1209 rc = smb_node_getattr(NULL, fnode, zone_kcred(), NULL, &attr); 1210 if (rc != 0) { 1211 smb_node_release(fnode); 1212 return (rc); 1213 } 1214 } 1215 1216 /* check search attributes */ 1217 if (!smb_sattr_check(attr.sa_dosattr, od->d_sattr)) { 1218 smb_node_release(fnode); 1219 return (ENOENT); 1220 } 1221 1222 name = fnode->od_name; 1223 if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) { 1224 fid = attr.sa_vattr.va_nodeid; 1225 if (case_conflict || smb_needs_mangled(name)) { 1226 smb_mangle(name, fid, fileinfo->fi_shortname, 1227 SMB_SHORTNAMELEN); 1228 } 1229 if (case_conflict) 1230 name = fileinfo->fi_shortname; 1231 } 1232 1233 (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name)); 1234 1235 fileinfo->fi_dosattr = attr.sa_dosattr; 1236 fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid; 1237 fileinfo->fi_size = attr.sa_vattr.va_size; 1238 fileinfo->fi_alloc_size = attr.sa_allocsz; 1239 fileinfo->fi_atime = attr.sa_vattr.va_atime; 1240 fileinfo->fi_mtime = attr.sa_vattr.va_mtime; 1241 fileinfo->fi_ctime = attr.sa_vattr.va_ctime; 1242 if (attr.sa_crtime.tv_sec) 1243 fileinfo->fi_crtime = attr.sa_crtime; 1244 else 1245 fileinfo->fi_crtime = attr.sa_vattr.va_mtime; 1246 1247 smb_node_release(fnode); 1248 return (0); 1249 } 1250 1251 /* 1252 * smb_odir_wildcard_fileinfo 1253 * 1254 * odirent contains a directory entry, obtained from a vop_readdir. 1255 * If a case conflict is identified the filename is mangled and the 1256 * shortname is used as 'name', in place of odirent->od_name. 1257 * 1258 * If the looked up file is a link, we attempt to lookup the link target 1259 * to use its attributes in place of those of the files's. 1260 * If we fail to lookup the target of the link we use the original 1261 * file's attributes. 1262 * Check if the attributes match the search attributes. 1263 * 1264 * Although some file systems can have directories larger than 1265 * SMB_MAXDIRSIZE smb_odir_next_odirent ensures that no offset larger 1266 * than SMB_MAXDIRSIZE is returned. It is therefore safe to use the 1267 * offset as the cookie (uint32_t). 1268 * 1269 * Returns: 0 - success 1270 * ENOENT - no match, proceed to next entry 1271 * errno - error 1272 */ 1273 static int 1274 smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od, 1275 smb_odirent_t *odirent, smb_fileinfo_t *fileinfo) 1276 { 1277 int rc; 1278 cred_t *cr; 1279 smb_node_t *fnode, *tgt_node; 1280 smb_attr_t attr; 1281 char *name; 1282 boolean_t case_conflict; 1283 1284 ASSERT(sr); 1285 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 1286 ASSERT(od); 1287 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1288 1289 ASSERT(MUTEX_HELD(&od->d_mutex)); 1290 bzero(fileinfo, sizeof (smb_fileinfo_t)); 1291 1292 rc = smb_fsop_lookup(sr, od->d_cred, SMB_CASE_SENSITIVE, 1293 od->d_tree->t_snode, od->d_dnode, odirent->od_name, &fnode); 1294 if (rc != 0) 1295 return (rc); 1296 1297 /* follow link to get target node & attr */ 1298 if (smb_node_is_symlink(fnode) && 1299 smb_odir_lookup_link(sr, od, odirent->od_name, &tgt_node)) { 1300 smb_node_release(fnode); 1301 fnode = tgt_node; 1302 } 1303 1304 /* skip system files */ 1305 if (smb_node_is_system(fnode)) { 1306 smb_node_release(fnode); 1307 return (ENOENT); 1308 } 1309 1310 /* 1311 * Windows directory listings return not only names, but 1312 * also some attributes. In Unix, you need some access to 1313 * get those attributes. Which credential should we use to 1314 * get those? If we're doing Access Based Enumeration (ABE) 1315 * we want this getattr to fail, which will cause the caller 1316 * to skip this entry. If we're NOT doing ABE, we normally 1317 * want to show all the directory entries (including their 1318 * attributes) so we want this getattr to succeed! 1319 */ 1320 if (smb_tree_has_feature(od->d_tree, SMB_TREE_ABE)) 1321 cr = od->d_cred; 1322 else 1323 cr = zone_kcred(); 1324 1325 bzero(&attr, sizeof (attr)); 1326 attr.sa_mask = SMB_AT_ALL; 1327 rc = smb_node_getattr(NULL, fnode, cr, NULL, &attr); 1328 if (rc != 0) { 1329 smb_node_release(fnode); 1330 return (rc); 1331 } 1332 1333 /* check search attributes */ 1334 if (!smb_sattr_check(attr.sa_dosattr, od->d_sattr)) { 1335 smb_node_release(fnode); 1336 return (ENOENT); 1337 } 1338 1339 name = odirent->od_name; 1340 if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) { 1341 case_conflict = ((od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) && 1342 (odirent->od_eflags & ED_CASE_CONFLICT)); 1343 if (case_conflict || smb_needs_mangled(name)) { 1344 smb_mangle(name, odirent->od_ino, 1345 fileinfo->fi_shortname, SMB_SHORTNAMELEN); 1346 } 1347 if (case_conflict) 1348 name = fileinfo->fi_shortname; 1349 } 1350 1351 (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name)); 1352 1353 fileinfo->fi_cookie = (uint32_t)od->d_offset; 1354 fileinfo->fi_dosattr = attr.sa_dosattr; 1355 fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid; 1356 fileinfo->fi_size = attr.sa_vattr.va_size; 1357 fileinfo->fi_alloc_size = attr.sa_allocsz; 1358 fileinfo->fi_atime = attr.sa_vattr.va_atime; 1359 fileinfo->fi_mtime = attr.sa_vattr.va_mtime; 1360 fileinfo->fi_ctime = attr.sa_vattr.va_ctime; 1361 if (attr.sa_crtime.tv_sec) 1362 fileinfo->fi_crtime = attr.sa_crtime; 1363 else 1364 fileinfo->fi_crtime = attr.sa_vattr.va_mtime; 1365 1366 smb_node_release(fnode); 1367 return (0); 1368 } 1369 1370 /* 1371 * smb_odir_lookup_link 1372 * 1373 * If the file is a symlink we lookup the object to which the 1374 * symlink refers so that we can return its attributes. 1375 * This can cause a problem if a symlink in a sub-directory 1376 * points to a parent directory (some UNIX GUI's create a symlink 1377 * in $HOME/.desktop that points to the user's home directory). 1378 * Some Windows applications (e.g. virus scanning) loop/hang 1379 * trying to follow this recursive path and there is little 1380 * we can do because the path is constructed on the client. 1381 * smb_dirsymlink_enable allows an end-user to disable 1382 * symlinks to directories. Symlinks to other object types 1383 * should be unaffected. 1384 * 1385 * Returns: B_TRUE - followed link. tgt_node and tgt_attr set 1386 * B_FALSE - link not followed 1387 */ 1388 static boolean_t 1389 smb_odir_lookup_link(smb_request_t *sr, smb_odir_t *od, 1390 char *fname, smb_node_t **tgt_node) 1391 { 1392 int rc; 1393 uint32_t flags = SMB_FOLLOW_LINKS | SMB_CASE_SENSITIVE; 1394 1395 rc = smb_fsop_lookup(sr, od->d_cred, flags, 1396 od->d_tree->t_snode, od->d_dnode, fname, tgt_node); 1397 if (rc != 0) { 1398 *tgt_node = NULL; 1399 return (B_FALSE); 1400 } 1401 1402 if (smb_node_is_dir(*tgt_node) && (!smb_dirsymlink_enable)) { 1403 smb_node_release(*tgt_node); 1404 *tgt_node = NULL; 1405 return (B_FALSE); 1406 } 1407 1408 return (B_TRUE); 1409 } 1410 1411 /* 1412 * smb_odir_match_name 1413 * 1414 * Check if the directory entry name matches the search pattern: 1415 * - Don't match reserved dos filenames. 1416 * - Check if odirent->od_name matches od->d_pattern. 1417 * - If shortnames are supported, generate the shortname from 1418 * odirent->od_name and check if it matches od->d_pattern. 1419 */ 1420 static boolean_t 1421 smb_odir_match_name(smb_odir_t *od, smb_odirent_t *odirent) 1422 { 1423 char *name = odirent->od_name; 1424 char shortname[SMB_SHORTNAMELEN]; 1425 ino64_t ino = odirent->od_ino; 1426 boolean_t ci = (od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) != 0; 1427 1428 if (smb_is_reserved_dos_name(name)) 1429 return (B_FALSE); 1430 1431 if (smb_match(od->d_pattern, name, ci)) 1432 return (B_TRUE); 1433 1434 if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) { 1435 smb_mangle(name, ino, shortname, SMB_SHORTNAMELEN); 1436 if (smb_match(od->d_pattern, shortname, ci)) 1437 return (B_TRUE); 1438 } 1439 1440 return (B_FALSE); 1441 } 1442