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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * This module provides functions for TRANS2_FIND_FIRST2 and 30 * TRANS2_FIND_NEXT2 requests. The requests allow the client to search 31 * for the file(s) which match the file specification. The search is 32 * started with TRANS2_FIND_FIRST2 and can be continued if necessary with 33 * TRANS2_FIND_NEXT2. There are numerous levels of information which may be 34 * obtained for the returned files, the desired level is specified in the 35 * InformationLevel field of the requests. 36 * 37 * InformationLevel Name Value 38 * ================================= ================ 39 * 40 * SMB_INFO_STANDARD 1 41 * SMB_INFO_QUERY_EA_SIZE 2 42 * SMB_INFO_QUERY_EAS_FROM_LIST 3 43 * SMB_FIND_FILE_DIRECTORY_INFO 0x101 44 * SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 45 * SMB_FIND_FILE_NAMES_INFO 0x103 46 * SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104 47 * 48 * The following sections detail the data returned for each 49 * InformationLevel. The requested information is placed in the Data 50 * portion of the transaction response. Note: a client which does not 51 * support long names can only request SMB_INFO_STANDARD. 52 * 53 * A four-byte resume key precedes each data item (described below) if bit 54 * 2 in the Flags field is set, i.e. if the request indicates the server 55 * should return resume keys. Note: it is not always the case. If the 56 * data item already includes the resume key, the resume key should not be 57 * added again. 58 * 59 * 4.3.4.1 SMB_INFO_STANDARD 60 * 61 * Response Field Description 62 * ================================ ================================== 63 * 64 * SMB_DATE CreationDate; Date when file was created 65 * SMB_TIME CreationTime; Time when file was created 66 * SMB_DATE LastAccessDate; Date of last file access 67 * SMB_TIME LastAccessTime; Time of last file access 68 * SMB_DATE LastWriteDate; Date of last write to the file 69 * SMB_TIME LastWriteTime; Time of last write to the file 70 * ULONG DataSize; File Size 71 * ULONG AllocationSize; Size of filesystem allocation unit 72 * USHORT Attributes; File Attributes 73 * UCHAR FileNameLength; Length of filename in bytes 74 * STRING FileName; Name of found file 75 * 76 * 4.3.4.2 SMB_INFO_QUERY_EA_SIZE 77 * 78 * Response Field Description 79 * ================================= ================================== 80 * 81 * SMB_DATE CreationDate; Date when file was created 82 * SMB_TIME CreationTime; Time when file was created 83 * SMB_DATE LastAccessDate; Date of last file access 84 * SMB_TIME LastAccessTime; Time of last file access 85 * SMB_DATE LastWriteDate; Date of last write to the file 86 * SMB_TIME LastWriteTime; Time of last write to the file 87 * ULONG DataSize; File Size 88 * ULONG AllocationSize; Size of filesystem allocation unit 89 * USHORT Attributes; File Attributes 90 * ULONG EaSize; Size of file's EA information 91 * UCHAR FileNameLength; Length of filename in bytes 92 * STRING FileName; Name of found file 93 * 94 * 4.3.4.3 SMB_INFO_QUERY_EAS_FROM_LIST 95 * 96 * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but 97 * only for files which have an EA list which match the EA information in 98 * the Data part of the request. 99 * 100 * 4.3.4.4 SMB_FIND_FILE_DIRECTORY_INFO 101 * 102 * Response Field Description 103 * ================================= ================================== 104 * 105 * ULONG NextEntryOffset; Offset from this structure to 106 * beginning of next one 107 * ULONG FileIndex; 108 * LARGE_INTEGER CreationTime; file creation time 109 * LARGE_INTEGER LastAccessTime; last access time 110 * LARGE_INTEGER LastWriteTime; last write time 111 * LARGE_INTEGER ChangeTime; last attribute change time 112 * LARGE_INTEGER EndOfFile; file size 113 * LARGE_INTEGER AllocationSize; size of filesystem allocation information 114 * ULONG ExtFileAttributes; Extended file attributes 115 * (see section 3.11) 116 * ULONG FileNameLength; Length of filename in bytes 117 * STRING FileName; Name of the file 118 * 119 * 4.3.4.5 SMB_FIND_FILE_FULL_DIRECTORY_INFO 120 * 121 * Response Field Description 122 * ================================= ================================== 123 * 124 * ULONG NextEntryOffset; Offset from this structure to 125 * beginning of next one 126 * ULONG FileIndex; 127 * LARGE_INTEGER CreationTime; file creation time 128 * LARGE_INTEGER LastAccessTime; last access time 129 * LARGE_INTEGER LastWriteTime; last write time 130 * LARGE_INTEGER ChangeTime; last attribute change time 131 * LARGE_INTEGER EndOfFile; file size 132 * LARGE_INTEGER AllocationSize; size of filesystem allocation information 133 * ULONG ExtFileAttributes; Extended file attributes 134 * (see section 3.11) 135 * ULONG FileNameLength; Length of filename in bytes 136 * ULONG EaSize; Size of file's extended attributes 137 * STRING FileName; Name of the file 138 * 139 * 4.3.4.6 SMB_FIND_FILE_BOTH_DIRECTORY_INFO 140 * 141 * Response Field Description 142 * ================================= ================================== 143 * 144 * ULONG NextEntryOffset; Offset from this structure to 145 * beginning of next one 146 * ULONG FileIndex; 147 * LARGE_INTEGER CreationTime; file creation time 148 * LARGE_INTEGER LastAccessTime; last access time 149 * LARGE_INTEGER LastWriteTime; last write time 150 * LARGE_INTEGER ChangeTime; last attribute change time 151 * LARGE_INTEGER EndOfFile; file size 152 * LARGE_INTEGER AllocationSize; size of filesystem allocation information 153 * ULONG ExtFileAttributes; Extended file attributes 154 * (see section 3.11) 155 * ULONG FileNameLength; Length of FileName in bytes 156 * ULONG EaSize; Size of file's extended attributes 157 * UCHAR ShortNameLength; Length of file's short name in bytes 158 * UCHAR Reserved 159 * WCHAR ShortName[12]; File's 8.3 conformant name in Unicode 160 * STRING FileName; Files full length name 161 * 162 * 4.3.4.7 SMB_FIND_FILE_NAMES_INFO 163 * 164 * Response Field Description 165 * ================================= ================================== 166 * 167 * ULONG NextEntryOffset; Offset from this structure to 168 * beginning of next one 169 * ULONG FileIndex; 170 * ULONG FileNameLength; Length of FileName in bytes 171 * STRING FileName; Files full length name 172 */ 173 174 #include <smbsrv/smb_incl.h> 175 #include <smbsrv/msgbuf.h> 176 #include <smbsrv/smbtrans.h> 177 #include <smbsrv/smb_fsops.h> 178 179 int smb_trans2_find_get_maxdata(struct smb_request *, unsigned short, 180 unsigned short); 181 182 int smb_trans2_find_get_dents(struct smb_request *, struct smb_xa *, 183 unsigned short, unsigned short, int, struct smb_node *, 184 unsigned short, uint32_t, int, char *, uint32_t *, int *, int *); 185 186 int smb_gather_dents_info(char *, ino_t, int, char *, uint32_t, int32_t *, 187 smb_attr_t *, struct smb_node *, char *, char *); 188 189 int smb_trans2_find_process_ients(struct smb_request *, struct smb_xa *, 190 smb_dent_info_hdr_t *, unsigned short, unsigned short, int, 191 struct smb_node *, int *, uint32_t *); 192 193 int smb_trans2_find_mbc_encode(struct smb_request *, struct smb_xa *, 194 smb_dent_info_t *, int, unsigned short, unsigned short, 195 unsigned int, struct smb_node *, struct smb_node *); 196 197 /* 198 * Support for Catia Version 5 Deployment 199 */ 200 static int (*catia_callback)(unsigned char *, unsigned char *, int) = NULL; 201 void smb_register_catia_callback( 202 int (*catia_v4tov5)(unsigned char *, unsigned char *, int)); 203 void smb_unregister_catia_callback(); 204 205 /* 206 * Patchable parameter for find maximum count 207 */ 208 int max_find_count = 64; 209 210 /* 211 * smb_register_catia_callback 212 * 213 * This function will be invoked by the catia module to register its 214 * function that translates filename in version 4 to a format that is 215 * compatible to version 5. 216 */ 217 void 218 smb_register_catia_callback( 219 int (*catia_v4tov5)(unsigned char *, unsigned char *, int)) 220 { 221 catia_callback = catia_v4tov5; 222 } 223 224 /* 225 * smb_unregister_catia_callback 226 * 227 * This function will unregister the catia callback prior to the catia 228 * module gets unloaded. 229 */ 230 void 231 smb_unregister_catia_callback() 232 { 233 catia_callback = 0; 234 } 235 236 /* 237 * smb_com_trans2_find_first2 238 * 239 * Client Request Value 240 * ============================ ================================== 241 * 242 * UCHAR WordCount 15 243 * UCHAR TotalDataCount Total size of extended attribute list 244 * UCHAR SetupCount 1 245 * UCHAR Setup[0] TRANS2_FIND_FIRST2 246 * 247 * Parameter Block Encoding Description 248 * ============================ ================================== 249 * USHORT SearchAttributes; 250 * USHORT SearchCount; Maximum number of entries to return 251 * USHORT Flags; Additional information: 252 * Bit 0 - close search after this request 253 * Bit 1 - close search if end of search 254 * reached 255 * Bit 2 - return resume keys for each 256 * entry found 257 * Bit 3 - continue search from previous 258 * ending place 259 * Bit 4 - find with backup intent 260 * USHORT InformationLevel; See below 261 * ULONG SearchStorageType; 262 * STRING FileName; Pattern for the search 263 * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is 264 * QUERY_EAS_FROM_LIST 265 * 266 * Response Parameter Block Description 267 * ============================ ================================== 268 * 269 * USHORT Sid; Search handle 270 * USHORT SearchCount; Number of entries returned 271 * USHORT EndOfSearch; Was last entry returned? 272 * USHORT EaErrorOffset; Offset into EA list if EA error 273 * USHORT LastNameOffset; Offset into data to file name of last 274 * entry, if server needs it to resume 275 * search; else 0 276 * UCHAR Data[ TotalDataCount ] Level dependent info about the matches 277 * found in the search 278 */ 279 int 280 smb_com_trans2_find_first2(struct smb_request *sr, struct smb_xa *xa) 281 { 282 int more = 0, rc; 283 unsigned short sattr, fflag, infolev; 284 int maxdata; 285 int count, maxcount = 0, wildcards; 286 uint32_t cookie; 287 char *path; 288 struct smb_node *dir_snode; 289 char *pattern; 290 unsigned short sid; 291 292 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 293 smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED, 294 ERRDOS, ERROR_ACCESS_DENIED); 295 /* NOTREACHED */ 296 } 297 298 if (smb_decode_mbc(&xa->req_param_mb, "%wwww4.u", sr, 299 &sattr, &maxcount, &fflag, &infolev, &path) != 0) { 300 smbsr_decode_error(sr); 301 /* NOTREACHED */ 302 } 303 304 maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag); 305 306 if (maxdata == 0) { 307 smbsr_raise_error(sr, ERRDOS, ERRunknownlevel); 308 /* NOTREACHED */ 309 } 310 311 /* Convert name to our form */ 312 if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) { 313 (void) smb_convert_unicode_wildcards(path); 314 } 315 (void) smb_rdir_open(sr, path, sattr); 316 317 /* 318 * Get a copy of information 319 */ 320 pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP); 321 dir_snode = sr->sid_odir->d_dir_snode; 322 (void) strcpy(pattern, sr->sid_odir->d_pattern); 323 /* this is funky */ 324 if (strcmp(pattern, "*.*") == 0) 325 (void) strncpy(pattern, "*", sizeof (pattern)); 326 wildcards = sr->sid_odir->d_wildcards; 327 sattr = sr->sid_odir->d_sattr; 328 cookie = 0; 329 330 rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata, 331 dir_snode, sattr, maxcount, wildcards, 332 pattern, &cookie, &more, &count); 333 334 if (!count) 335 rc = ENOENT; 336 337 if (rc) { 338 smb_rdir_close(sr); 339 kmem_free(pattern, MAXNAMELEN); 340 smbsr_raise_errno(sr, rc); 341 /* NOTREACHED */ 342 } 343 344 /* 345 * Save the sid here because search might get closed 346 * and sr->smb_sid becomes invalid. 347 * This might not seem important because the search 348 * is going to be finished anyways, but it's just for 349 * the sake of compatibility with Windows. 350 */ 351 sid = sr->smb_sid; 352 353 if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST || 354 (!more && fflag & SMB_FIND_CLOSE_AT_EOS)) 355 smb_rdir_close(sr); 356 else { 357 mutex_enter(&sr->sid_odir->d_mutex); 358 sr->sid_odir->d_cookie = cookie; 359 mutex_exit(&sr->sid_odir->d_mutex); 360 } 361 362 (void) smb_encode_mbc(&xa->rep_param_mb, "wwwww", 363 sid, count, (more ? 0 : 1), 0, 0); 364 365 kmem_free(pattern, MAXNAMELEN); 366 return (SDRC_NORMAL_REPLY); 367 } 368 369 370 371 /* 372 * smb_com_trans2_find_next2 373 * 374 * Client Request Value 375 * ================================== ================================= 376 * 377 * WordCount 15 378 * SetupCount 1 379 * Setup[0] TRANS2_FIND_NEXT2 380 * 381 * Parameter Block Encoding Description 382 * ================================== ================================= 383 * 384 * USHORT Sid; Search handle 385 * USHORT SearchCount; Maximum number of entries to 386 * return 387 * USHORT InformationLevel; Levels described in 388 * TRANS2_FIND_FIRST2 request 389 * ULONG ResumeKey; Value returned by previous find2 390 * call 391 * USHORT Flags; Additional information: bit set- 392 * 0 - close search after this 393 * request 394 * 1 - close search if end of search 395 * reached 396 * 2 - return resume keys for each 397 * entry found 398 * 3 - resume/continue from previous 399 * ending place 400 * 4 - find with backup intent 401 * STRING FileName; Resume file name 402 * 403 * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2 404 * call. If Bit3 of Flags is set, then FileName may be the NULL string, 405 * since the search is continued from the previous TRANS2_FIND request. 406 * Otherwise, FileName must not be more than 256 characters long. 407 * 408 * Response Field Description 409 * ================================== ================================= 410 * 411 * USHORT SearchCount; Number of entries returned 412 * USHORT EndOfSearch; Was last entry returned? 413 * USHORT EaErrorOffset; Offset into EA list if EA error 414 * USHORT LastNameOffset; Offset into data to file name of 415 * last entry, if server needs it to 416 * resume search; else 0 417 * UCHAR Data[TotalDataCount] Level dependent info about the 418 * matches found in the search 419 */ 420 int 421 smb_com_trans2_find_next2(struct smb_request *sr, struct smb_xa *xa) 422 { 423 unsigned short fflag, infolev; 424 int maxdata, count, wildcards, more = 0, rc; 425 uint32_t cookie; 426 uint32_t maxcount = 0; 427 struct smb_node *dir_snode; 428 char *pattern; 429 unsigned short sattr; 430 431 pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP); 432 /* 433 * There is a path field as the last piece of input information: 434 * 435 * smb_decode_mbc(&xa->req_param_mb, "%www lwu", sr, 436 * &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &path) 437 * 438 * This feild has been removed because it's causing problem 439 * with Mac OS 10 and it's not used anyways. 440 * The problem is that code expects to see a 2-byte null 441 * because the strings are supposed to be Unicode, but 442 * Max OS 10 sends a 1-byte null which leads to decode error. 443 */ 444 if (smb_decode_mbc(&xa->req_param_mb, "%www lw", sr, 445 &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag) != 0) { 446 kmem_free(pattern, MAXNAMELEN); 447 smbsr_decode_error(sr); 448 /* NOTREACHED */ 449 } 450 451 maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag); 452 453 sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid); 454 if (sr->sid_odir == NULL) { 455 kmem_free(pattern, MAXNAMELEN); 456 smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE, 457 ERRDOS, ERRbadfid); 458 /* NOTREACHED */ 459 } 460 461 if (maxdata == 0) { 462 smb_rdir_close(sr); 463 kmem_free(pattern, MAXNAMELEN); 464 smbsr_raise_error(sr, ERRDOS, ERRunknownlevel); 465 /* NOTREACHED */ 466 } 467 468 /* 469 * Get a copy of information 470 */ 471 dir_snode = sr->sid_odir->d_dir_snode; 472 (void) strcpy(pattern, sr->sid_odir->d_pattern); 473 wildcards = sr->sid_odir->d_wildcards; 474 sattr = sr->sid_odir->d_sattr; 475 if (fflag & SMB_FIND_CONTINUE_FROM_LAST) { 476 mutex_enter(&sr->sid_odir->d_mutex); 477 cookie = sr->sid_odir->d_cookie; 478 mutex_exit(&sr->sid_odir->d_mutex); 479 } 480 481 /* 482 * XXX this is an optimization made for SFS2 filesystem, it might 483 * not be required for ZFS 484 * 485 * Break the count to smaller counts (less than the default 150) 486 * to reduce the number of transaction failures 487 * which may cause excessive delays and eventually a SMB staled 488 * connection. 489 */ 490 maxcount = (maxcount > max_find_count) ? max_find_count : maxcount; 491 492 rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata, 493 dir_snode, sattr, maxcount, wildcards, pattern, &cookie, 494 &more, &count); 495 496 if (rc) { 497 smb_rdir_close(sr); 498 kmem_free(pattern, MAXNAMELEN); 499 smbsr_raise_errno(sr, rc); 500 /* NOTREACHED */ 501 } 502 503 if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST || 504 (!more && fflag & SMB_FIND_CLOSE_AT_EOS)) 505 smb_rdir_close(sr); 506 else { 507 mutex_enter(&sr->sid_odir->d_mutex); 508 sr->sid_odir->d_cookie = cookie; 509 mutex_exit(&sr->sid_odir->d_mutex); 510 } 511 512 (void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 513 count, (more ? 0 : 1), 0, 0); 514 515 kmem_free(pattern, MAXNAMELEN); 516 return (SDRC_NORMAL_REPLY); 517 } 518 519 520 /* 521 * smb_trans2_find_get_maxdata 522 * 523 * This function calculates the minimum space requirement for the 524 * base on information level and fflag. 525 * 526 * When success, minimum space requirement will be returned; otherwise, 527 * 0 will be returned. 528 */ 529 int 530 smb_trans2_find_get_maxdata( 531 struct smb_request *sr, 532 unsigned short infolev, 533 unsigned short fflag) 534 { 535 int maxdata; 536 537 maxdata = smb_ascii_or_unicode_null_len(sr); 538 539 switch (infolev) { 540 case SMB_INFO_STANDARD : 541 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 542 maxdata += sizeof (int32_t); 543 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1; 544 break; 545 546 case SMB_INFO_QUERY_EA_SIZE: 547 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 548 maxdata += sizeof (int32_t); 549 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1; 550 break; 551 552 case SMB_FIND_FILE_DIRECTORY_INFO: 553 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4; 554 break; 555 556 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 557 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24; 558 break; 559 560 case SMB_FIND_FILE_NAMES_INFO: 561 maxdata += 4 + 4 + 4; 562 break; 563 564 case SMB_MAC_FIND_BOTH_HFS_INFO: 565 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 + 566 4 + 32 + 4 + 1 + 1 + 24 + 4; 567 break; 568 569 default: 570 maxdata = 0; 571 } 572 573 return (maxdata); 574 } 575 576 577 578 /* 579 * smb_trans2_find_get_dents 580 * 581 * This function will get all the directory entry information and mbc 582 * encode it in the xa. If there is an error, it will be returned; 583 * otherwise, 0 is returned. 584 * 585 * The more field will be updated. If the value returned is one, it means 586 * there are more entries; otherwise, the returned value will be zero. The 587 * cookie will also be updated to indicate the next start point for the 588 * search. The count value will also be updated to stores the total entries 589 * encoded. 590 */ 591 int smb_trans2_find_get_dents( 592 smb_request_t *sr, 593 smb_xa_t *xa, 594 unsigned short fflag, 595 unsigned short infolev, 596 int maxdata, 597 smb_node_t *dir_snode, 598 unsigned short sattr, 599 uint32_t maxcount, 600 int wildcards, 601 char *pattern, 602 uint32_t *cookie, 603 int *more, 604 int *count) 605 { 606 smb_dent_info_hdr_t *ihdr; 607 smb_dent_info_t *ient; 608 int dent_buf_size; 609 int i; 610 int total; 611 int maxentries; 612 int rc; 613 614 ihdr = kmem_zalloc(sizeof (smb_dent_info_hdr_t), KM_SLEEP); 615 *count = 0; 616 617 if (!wildcards) 618 maxentries = maxcount = 1; 619 else { 620 maxentries = (xa->rep_data_mb.max_bytes - 621 xa->rep_data_mb.chain_offset) / maxdata; 622 if (maxcount > SMB_MAX_DENTS_IOVEC) 623 maxcount = SMB_MAX_DENTS_IOVEC; 624 if (maxentries > maxcount) 625 maxentries = maxcount; 626 } 627 628 /* Each entry will need to be aligned so add _POINTER_ALIGNMENT */ 629 dent_buf_size = 630 maxentries * (SMB_MAX_DENT_INFO_SIZE + _POINTER_ALIGNMENT); 631 ihdr->iov->iov_base = kmem_alloc(dent_buf_size, KM_SLEEP); 632 633 ihdr->sattr = sattr; 634 ihdr->pattern = pattern; 635 ihdr->sr = sr; 636 637 ihdr->uio.uio_iovcnt = maxcount; 638 ihdr->uio.uio_resid = dent_buf_size; 639 ihdr->uio.uio_iov = ihdr->iov; 640 ihdr->uio.uio_loffset = 0; 641 642 rc = smb_get_dents(sr, cookie, dir_snode, wildcards, ihdr, more); 643 if (rc != 0) { 644 goto out; 645 } 646 647 if (ihdr->iov->iov_len == 0) 648 *count = 0; 649 else 650 *count = smb_trans2_find_process_ients(sr, xa, ihdr, fflag, 651 infolev, maxdata, dir_snode, more, cookie); 652 rc = 0; 653 654 out: 655 656 total = maxcount - ihdr->uio.uio_iovcnt; 657 ASSERT((total >= 0) && (total <= SMB_MAX_DENTS_IOVEC)); 658 for (i = 0; i < total; i++) { 659 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 660 ient = (smb_dent_info_t *)ihdr->iov[i].iov_base; 661 ASSERT(ient); 662 smb_node_release(ient->snode); 663 } 664 665 kmem_free(ihdr->iov->iov_base, dent_buf_size); 666 kmem_free(ihdr, sizeof (smb_dent_info_hdr_t)); 667 return (0); 668 } 669 670 671 672 /* 673 * smb_get_dents 674 * 675 * This function utilizes "smb_fsop_getdents()" to get dir entries. 676 * The "smb_gather_dents_info()" is the call back function called 677 * inside the file system. It is very important that the function 678 * does not sleep or yield since it is processed inside a file 679 * system transaction. 680 * 681 * The function returns 0 when successful and error code when failed. 682 * If more is provided, the return value of 1 is returned indicating 683 * more entries; otherwise, 0 is returned. 684 */ 685 int smb_get_dents( 686 smb_request_t *sr, 687 uint32_t *cookie, 688 smb_node_t *dir_snode, 689 unsigned int wildcards, 690 smb_dent_info_hdr_t *ihdr, 691 int *more) 692 { 693 int rc; 694 char *namebuf; 695 smb_node_t *snode; 696 smb_attr_t file_attr; 697 uint32_t maxcnt = ihdr->uio.uio_iovcnt; 698 char shortname[MANGLE_NAMELEN], name83[MANGLE_NAMELEN]; 699 fsvol_attr_t vol_attr; 700 701 namebuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 702 if (more) 703 *more = 0; 704 705 if ((rc = fsd_getattr(&sr->tid_tree->t_fsd, &vol_attr)) != 0) { 706 kmem_free(namebuf, MAXNAMELEN); 707 return (rc); 708 } 709 710 if (!wildcards) { 711 /* Already found entry? */ 712 if (*cookie != 0) 713 return (0); 714 shortname[0] = '\0'; 715 716 rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode, 717 dir_snode, ihdr->pattern, &snode, &file_attr, shortname, 718 name83); 719 720 if (rc) { 721 kmem_free(namebuf, MAXNAMELEN); 722 return (rc); 723 } 724 725 (void) strlcpy(namebuf, ihdr->pattern, MAXNAMELEN); 726 727 /* 728 * It is not necessary to set the "force" flag (i.e. to 729 * take into account mangling for case-insensitive collisions) 730 */ 731 732 if (shortname[0] == '\0') 733 (void) smb_mangle_name(snode->attr.sa_vattr.va_nodeid, 734 namebuf, shortname, name83, 0); 735 (void) smb_gather_dents_info((char *)ihdr, 736 snode->attr.sa_vattr.va_nodeid, 737 strlen(namebuf), namebuf, -1, (int *)&maxcnt, 738 &snode->attr, snode, shortname, name83); 739 kmem_free(namebuf, MAXNAMELEN); 740 return (0); 741 } 742 743 if ((rc = smb_fsop_getdents(sr, sr->user_cr, dir_snode, cookie, 744 0, (int *)&maxcnt, (char *)ihdr, ihdr->pattern)) != 0) { 745 if (rc == ENOENT) { 746 kmem_free(namebuf, MAXNAMELEN); 747 return (0); 748 } 749 kmem_free(namebuf, MAXNAMELEN); 750 return (rc); 751 } 752 753 if (*cookie != 0x7FFFFFFF && more) 754 *more = 1; 755 756 kmem_free(namebuf, MAXNAMELEN); 757 return (0); 758 } 759 760 761 762 763 /* 764 * smb_gather_dents_info 765 * 766 * The function will accept information of each directory entry and put 767 * the needed information in the buffer. It is passed as the call back 768 * function for smb_fsop_getdents() to gather trans2 find info. 769 * 770 * If the buffer space is not enough, -1 will be returned. Regardless 771 * of valid entry or not, 0 will be returned; however, only valid entry 772 * will be stored in the buffer. 773 */ 774 int /*ARGSUSED*/ 775 smb_gather_dents_info( 776 char *args, 777 ino_t fileid, 778 int namelen, 779 char *name, 780 uint32_t cookie, 781 int32_t *countp, 782 smb_attr_t *attr, 783 smb_node_t *snode, 784 char *shortname, 785 char *name83) 786 { 787 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 788 smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)args; 789 smb_dent_info_t *ient; 790 unsigned char *v5_name = NULL; 791 unsigned char *np = (unsigned char *)name; 792 int reclen = sizeof (smb_dent_info_t) + namelen; 793 794 v5_name = kmem_alloc(MAXNAMELEN-1, KM_SLEEP); 795 796 if (!ihdr->uio.uio_iovcnt || ihdr->uio.uio_resid < reclen) { 797 kmem_free(v5_name, MAXNAMELEN-1); 798 smb_node_release(snode); 799 return (-1); 800 } 801 802 if (!smb_sattr_check(attr, name, ihdr->sattr)) { 803 kmem_free(v5_name, MAXNAMELEN-1); 804 smb_node_release(snode); 805 return (0); 806 } 807 808 /* 809 * If StorEdge is configured to support Catia Version 5 deployments, 810 * any directory entry whose name contains the special Unix character 811 * that is considered to be illegal in Windows environement will be 812 * translated based on the following 813 * Special Character Translation Table. 814 * 815 * --------------------------- 816 * Unix-char | Windows-char 817 * --------------------------- 818 * " | (0x00a8) Diaeresis 819 * * | (0x00a4) Currency Sign 820 * : | (0x00f7) Division Sign 821 * < | (0x00ab) Left-Pointing Double Angle Quotation Mark 822 * > | (0x00bb) Right-Pointing Double Angle Quotation Mark 823 * ? | (0x00bf) Inverted Question mark 824 * \ | (0x00ff) Latin Small Letter Y with Diaeresis 825 * | | (0x00a6) Broken Bar 826 */ 827 if (catia_callback) { 828 /* XXX 255 should be max name len or something */ 829 catia_callback(v5_name, (unsigned char *)name, 255); 830 np = v5_name; 831 reclen = sizeof (smb_dent_info_t) + strlen((char *)v5_name); 832 } 833 834 ASSERT(snode); 835 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 836 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 837 838 /* 839 * Each entry needs to be properly aligned or we may get an alignment 840 * fault on sparc. 841 */ 842 ihdr->uio.uio_loffset = (offset_t)PTRALIGN(ihdr->uio.uio_loffset); 843 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 844 ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_loffset]; 845 846 ient->cookie = cookie; 847 ient->attr = *attr; 848 ient->snode = snode; 849 850 (void) strcpy(ient->name, (char *)np); 851 (void) strcpy(ient->shortname, shortname); 852 (void) strcpy(ient->name83, name83); 853 ihdr->uio.uio_iov->iov_base = (char *)ient; 854 ihdr->uio.uio_iov->iov_len = reclen; 855 856 ihdr->uio.uio_iov++; 857 ihdr->uio.uio_iovcnt--; 858 ihdr->uio.uio_resid -= reclen; 859 ihdr->uio.uio_loffset += reclen; 860 861 kmem_free(v5_name, MAXNAMELEN-1); 862 return (0); 863 } 864 865 866 867 /* 868 * smb_trans2_find_process_ients 869 * 870 * This function encodes the directory entry information store in 871 * the iov structure of the ihdr structure. 872 * 873 * The total entries encoded will be returned. If the entries encoded 874 * is less than the total entries in the iov, the more field will 875 * be updated to 1. Also, the next cookie wil be updated as well. 876 */ 877 int 878 smb_trans2_find_process_ients( 879 struct smb_request *sr, 880 struct smb_xa *xa, 881 smb_dent_info_hdr_t *ihdr, 882 unsigned short fflag, 883 unsigned short infolev, 884 int maxdata, 885 struct smb_node *dir_snode, 886 int *more, 887 uint32_t *cookie) 888 { 889 int i, err = 0; 890 smb_dent_info_t *ient; 891 uint32_t mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) 892 ? SMB_MSGBUF_UNICODE : 0; 893 894 for (i = 0; i < SMB_MAX_DENTS_IOVEC; i++) { 895 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 896 if ((ient = (smb_dent_info_t *)ihdr->iov[i].iov_base) == 0) 897 break; 898 899 /* 900 * FYI: Some observed differences between our response and 901 * Windows response which hasn't caused problem yet! 902 * 903 * 1. The NextEntryOffset field for the last entry should be 0 904 * This code always calculate the record length and put the 905 * result in this field. 906 * 907 * 2. The FileIndex field is always 0. This code put the cookie 908 * in this field. 909 */ 910 err = smb_trans2_find_mbc_encode(sr, xa, ient, maxdata, infolev, 911 fflag, mb_flags, dir_snode, NULL); 912 913 if (err) 914 break; 915 } 916 917 /* 918 * Not enough space to store all the entries returned; therefore, 919 * update the more to 1. 920 */ 921 if (more && err < 0) { 922 *more = 1; 923 924 /* 925 * Assume the space will be at least enough for 1 entry. 926 */ 927 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 928 ient = (smb_dent_info_t *)ihdr->iov[i-1].iov_base; 929 *cookie = ient->cookie; 930 } 931 return (i); 932 } 933 934 935 936 /* 937 * smb_trans2_find_mbc_encode 938 * 939 * This function encodes the mbc for one directory entry. 940 * 941 * The function returns -1 when the max data requested by client 942 * is reached. If the entry is valid and successful encoded, 0 943 * will be returned; otherwise, 1 will be returned. 944 */ 945 int smb_trans2_find_mbc_encode( 946 struct smb_request *sr, 947 struct smb_xa *xa, 948 smb_dent_info_t *ient, 949 int maxdata, 950 unsigned short infolev, 951 unsigned short fflag, 952 unsigned int mb_flags, 953 struct smb_node *dir_snode, /*LINTED E_FUNC_ARG_UNUSED*/ 954 struct smb_node *sd_snode) 955 { 956 int uni_namelen; 957 int sl, rl; 958 char buf83[26]; 959 smb_msgbuf_t mb; 960 uint32_t dattr = 0; 961 uint32_t size32 = 0; 962 uint64_t size64 = 0; 963 struct smb_node *lnk_snode; 964 smb_attr_t lnkattr; 965 int rc; 966 967 uni_namelen = smb_ascii_or_unicode_strlen(sr, ient->name); 968 969 if (uni_namelen == -1) 970 return (1); 971 972 if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + uni_namelen)) == 0) 973 return (-1); 974 975 if (ient->attr.sa_vattr.va_type == VLNK) { 976 977 rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, 978 sr->tid_tree->t_snode, dir_snode, ient->name, &lnk_snode, 979 &lnkattr, 0, 0); 980 981 /* 982 * IR 104598 983 * 984 * We normally want to resolve the object to which a symlink 985 * refers so that CIFS clients can access sub-directories and 986 * find the correct association for files. This causes a 987 * problem, however, if a symlink in a sub-directory points 988 * to a parent directory (some UNIX GUI's create a symlink in 989 * $HOME/.desktop that points to the user's home directory). 990 * Some Windows applications (i.e. virus scanning) loop/hang 991 * trying to follow this recursive path and there is little 992 * we can do because the path is constructed on the client. 993 * So we've added a flag that allows an end-user to disable 994 * symlinks to directories. Symlinks to other object types 995 * should be unaffected. 996 */ 997 if (rc == 0) { 998 if (smb_info.si.skc_dirsymlink_enable || 999 (lnkattr.sa_vattr.va_type != VDIR)) { 1000 smb_node_release(ient->snode); 1001 ient->snode = lnk_snode; 1002 ient->attr = lnkattr; 1003 } else { 1004 smb_node_release(lnk_snode); 1005 } 1006 } 1007 } 1008 1009 if (infolev != SMB_FIND_FILE_NAMES_INFO) { 1010 size64 = smb_node_get_size(ient->snode, &ient->attr); 1011 size32 = (size64 > 0xFFFFFFFF) ? 0xFFFFFFFF : (uint32_t)size64; 1012 dattr = smb_mode_to_dos_attributes(&ient->attr); 1013 } 1014 1015 /* 1016 * we don't send the '.stream' to client. User shouldn't 1017 * see this directory. 1018 */ 1019 switch (infolev) { 1020 case SMB_INFO_STANDARD: 1021 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 1022 (void) smb_encode_mbc(&xa->rep_data_mb, "l", 1023 ient->cookie); 1024 1025 (void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwbu", sr, 1026 ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec : 1027 ient->attr.sa_vattr.va_mtime.tv_sec, 1028 ient->attr.sa_vattr.va_atime.tv_sec, 1029 ient->attr.sa_vattr.va_mtime.tv_sec, 1030 size32, 1031 size32, 1032 dattr, 1033 uni_namelen, 1034 ient->name); 1035 break; 1036 1037 case SMB_INFO_QUERY_EA_SIZE: 1038 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 1039 (void) smb_encode_mbc(&xa->rep_data_mb, 1040 "l", ient->cookie); 1041 1042 (void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwlbu", sr, 1043 ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec : 1044 ient->attr.sa_vattr.va_mtime.tv_sec, 1045 ient->attr.sa_vattr.va_atime.tv_sec, 1046 ient->attr.sa_vattr.va_mtime.tv_sec, 1047 size32, 1048 size32, 1049 dattr, 1050 0L, /* EA Size */ 1051 uni_namelen, 1052 ient->name); 1053 break; 1054 1055 case SMB_FIND_FILE_DIRECTORY_INFO: 1056 /* Use maxdata instead */ 1057 rl = maxdata + uni_namelen; 1058 1059 (void) smb_encode_mbc(&xa->rep_data_mb, "%llTTTTqqllu", sr, 1060 rl, 1061 ient->cookie, 1062 ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime : 1063 &ient->attr.sa_vattr.va_mtime, 1064 &ient->attr.sa_vattr.va_atime, 1065 &ient->attr.sa_vattr.va_mtime, 1066 &ient->attr.sa_vattr.va_ctime, 1067 size64, 1068 size64, 1069 dattr, 1070 uni_namelen, 1071 ient->name); 1072 break; 1073 1074 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 1075 /* Use maxdata instead */ 1076 rl = maxdata + uni_namelen; 1077 bzero(buf83, sizeof (buf83)); 1078 smb_msgbuf_init(&mb, (unsigned char *)buf83, sizeof (buf83), 1079 mb_flags); 1080 if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) { 1081 smb_msgbuf_term(&mb); 1082 return (-1); 1083 } 1084 sl = smb_ascii_or_unicode_strlen(sr, ient->shortname); 1085 1086 (void) smb_encode_mbc(&xa->rep_data_mb, 1087 "%llTTTTqqlllb.24cu", sr, 1088 rl, 1089 ient->cookie, 1090 ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime : 1091 &ient->attr.sa_vattr.va_mtime, 1092 &ient->attr.sa_vattr.va_atime, 1093 &ient->attr.sa_vattr.va_mtime, 1094 &ient->attr.sa_vattr.va_ctime, 1095 size64, 1096 size64, 1097 dattr, 1098 uni_namelen, 1099 0L, 1100 sl, 1101 buf83, 1102 ient->name); 1103 1104 smb_msgbuf_term(&mb); 1105 break; 1106 1107 case SMB_FIND_FILE_NAMES_INFO: 1108 rl = maxdata + uni_namelen; 1109 (void) smb_encode_mbc(&xa->rep_data_mb, "%lllu", sr, 1110 rl, 1111 ient->cookie, 1112 uni_namelen, 1113 ient->name); 1114 break; 1115 } 1116 1117 return (0); 1118 } 1119 1120 /* 1121 * Close a search started by a Trans2FindFirst2 request. 1122 */ 1123 int 1124 smb_com_find_close2(struct smb_request *sr) 1125 { 1126 if (smbsr_decode_vwv(sr, "w", &sr->smb_sid) != 0) { 1127 smbsr_decode_error(sr); 1128 /* NOTREACHED */ 1129 } 1130 1131 sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid); 1132 if (sr->sid_odir == NULL) { 1133 smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE, 1134 ERRDOS, ERRbadfid); 1135 /* NOTREACHED */ 1136 } 1137 1138 smb_rdir_close(sr); 1139 1140 smbsr_encode_empty_result(sr); 1141 return (SDRC_NORMAL_REPLY); 1142 } 1143