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 2008 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 static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t); 180 181 int smb_trans2_find_get_dents(smb_request_t *, smb_xa_t *, 182 uint16_t, uint16_t, int, smb_node_t *, 183 uint16_t, uint16_t, int, char *, uint32_t *, int *, int *); 184 185 int smb_gather_dents_info(char *, ino_t, int, char *, uint32_t, int32_t *, 186 smb_attr_t *, smb_node_t *, char *, char *); 187 188 int smb_trans2_find_process_ients(smb_request_t *, smb_xa_t *, 189 smb_dent_info_hdr_t *, uint16_t, uint16_t, int, 190 smb_node_t *, int *, uint32_t *); 191 192 int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *, 193 smb_dent_info_t *, int, uint16_t, uint16_t, 194 uint32_t, smb_node_t *, smb_node_t *); 195 196 /* 197 * The UNIX characters below are considered illegal in Windows file names. 198 * The following character conversions are used to support sites in which 199 * Catia v4 is in use on UNIX and Catia v5 is in use on Windows. 200 * 201 * --------------------------- 202 * Unix-char | Windows-char 203 * --------------------------- 204 * " | (0x00a8) Diaeresis 205 * * | (0x00a4) Currency Sign 206 * : | (0x00f7) Division Sign 207 * < | (0x00ab) Left-Pointing Double Angle Quotation Mark 208 * > | (0x00bb) Right-Pointing Double Angle Quotation Mark 209 * ? | (0x00bf) Inverted Question mark 210 * \ | (0x00ff) Latin Small Letter Y with Diaeresis 211 * | | (0x00a6) Broken Bar 212 */ 213 static int (*catia_callback)(uint8_t *, uint8_t *, int) = NULL; 214 void smb_register_catia_callback( 215 int (*catia_v4tov5)(uint8_t *, uint8_t *, int)); 216 void smb_unregister_catia_callback(); 217 218 /* 219 * Tunable parameter to limit the maximum 220 * number of entries to be returned. 221 */ 222 uint16_t smb_trans2_find_max = 128; 223 224 /* 225 * smb_register_catia_callback 226 * 227 * This function will be invoked by the catia module to register its 228 * function that translates filename in version 4 to a format that is 229 * compatible to version 5. 230 */ 231 void 232 smb_register_catia_callback( 233 int (*catia_v4tov5)(uint8_t *, uint8_t *, int)) 234 { 235 catia_callback = catia_v4tov5; 236 } 237 238 /* 239 * smb_unregister_catia_callback 240 * 241 * This function will unregister the catia callback prior to the catia 242 * module gets unloaded. 243 */ 244 void 245 smb_unregister_catia_callback() 246 { 247 catia_callback = 0; 248 } 249 250 /* 251 * smb_com_trans2_find_first2 252 * 253 * Client Request Value 254 * ============================ ================================== 255 * 256 * UCHAR WordCount 15 257 * UCHAR TotalDataCount Total size of extended attribute list 258 * UCHAR SetupCount 1 259 * UCHAR Setup[0] TRANS2_FIND_FIRST2 260 * 261 * Parameter Block Encoding Description 262 * ============================ ================================== 263 * USHORT SearchAttributes; 264 * USHORT SearchCount; Maximum number of entries to return 265 * USHORT Flags; Additional information: 266 * Bit 0 - close search after this request 267 * Bit 1 - close search if end of search 268 * reached 269 * Bit 2 - return resume keys for each 270 * entry found 271 * Bit 3 - continue search from previous 272 * ending place 273 * Bit 4 - find with backup intent 274 * USHORT InformationLevel; See below 275 * ULONG SearchStorageType; 276 * STRING FileName; Pattern for the search 277 * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is 278 * QUERY_EAS_FROM_LIST 279 * 280 * Response Parameter Block Description 281 * ============================ ================================== 282 * 283 * USHORT Sid; Search handle 284 * USHORT SearchCount; Number of entries returned 285 * USHORT EndOfSearch; Was last entry returned? 286 * USHORT EaErrorOffset; Offset into EA list if EA error 287 * USHORT LastNameOffset; Offset into data to file name of last 288 * entry, if server needs it to resume 289 * search; else 0 290 * UCHAR Data[ TotalDataCount ] Level dependent info about the matches 291 * found in the search 292 */ 293 smb_sdrc_t 294 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) 295 { 296 int more = 0, rc; 297 uint16_t sattr, fflag, infolev; 298 uint16_t maxcount = 0; 299 int maxdata; 300 int count, wildcards; 301 uint32_t cookie; 302 char *path; 303 smb_node_t *dir_snode; 304 char *pattern; 305 uint16_t sid; 306 307 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 308 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 309 ERRDOS, ERROR_ACCESS_DENIED); 310 return (SDRC_ERROR); 311 } 312 313 if (smb_decode_mbc(&xa->req_param_mb, "%wwww4.u", sr, 314 &sattr, &maxcount, &fflag, &infolev, &path) != 0) { 315 return (SDRC_ERROR); 316 } 317 318 maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag); 319 if (maxdata == 0) { 320 smbsr_error(sr, NT_STATUS_INVALID_LEVEL, 321 ERRDOS, ERROR_INVALID_LEVEL); 322 return (SDRC_ERROR); 323 } 324 325 /* 326 * When maxcount is zero Windows behaves as if it was 1. 327 */ 328 if (maxcount == 0) 329 maxcount = 1; 330 331 if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max)) 332 maxcount = smb_trans2_find_max; 333 334 if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) 335 (void) smb_convert_unicode_wildcards(path); 336 337 if (smb_rdir_open(sr, path, sattr) != 0) 338 return (SDRC_ERROR); 339 340 /* 341 * Get a copy of information 342 */ 343 dir_snode = sr->sid_odir->d_dir_snode; 344 pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP); 345 (void) strcpy(pattern, sr->sid_odir->d_pattern); 346 347 if (strcmp(pattern, "*.*") == 0) 348 (void) strncpy(pattern, "*", sizeof (pattern)); 349 350 wildcards = sr->sid_odir->d_wildcards; 351 sattr = sr->sid_odir->d_sattr; 352 cookie = 0; 353 354 rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata, 355 dir_snode, sattr, maxcount, wildcards, 356 pattern, &cookie, &more, &count); 357 358 if (!count) 359 rc = ENOENT; 360 361 if (rc) { 362 smb_rdir_close(sr); 363 kmem_free(pattern, MAXNAMELEN); 364 if (rc == ENOENT) 365 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 366 ERRDOS, ERROR_INVALID_NAME); 367 else 368 smbsr_errno(sr, rc); 369 return (SDRC_ERROR); 370 } 371 372 /* 373 * Save the sid here in case the search is closed below, 374 * which will invalidate sr->smb_sid. We return the 375 * sid, even though the search has been closed, to be 376 * compatible with Windows. 377 */ 378 sid = sr->smb_sid; 379 380 if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST || 381 (!more && fflag & SMB_FIND_CLOSE_AT_EOS)) { 382 smb_rdir_close(sr); 383 } else { 384 mutex_enter(&sr->sid_odir->d_mutex); 385 sr->sid_odir->d_cookie = cookie; 386 mutex_exit(&sr->sid_odir->d_mutex); 387 } 388 389 (void) smb_encode_mbc(&xa->rep_param_mb, "wwwww", 390 sid, count, (more ? 0 : 1), 0, 0); 391 392 kmem_free(pattern, MAXNAMELEN); 393 return (SDRC_SUCCESS); 394 } 395 396 /* 397 * smb_com_trans2_find_next2 398 * 399 * Client Request Value 400 * ================================== ================================= 401 * 402 * WordCount 15 403 * SetupCount 1 404 * Setup[0] TRANS2_FIND_NEXT2 405 * 406 * Parameter Block Encoding Description 407 * ================================== ================================= 408 * 409 * USHORT Sid; Search handle 410 * USHORT SearchCount; Maximum number of entries to 411 * return 412 * USHORT InformationLevel; Levels described in 413 * TRANS2_FIND_FIRST2 request 414 * ULONG ResumeKey; Value returned by previous find2 415 * call 416 * USHORT Flags; Additional information: bit set- 417 * 0 - close search after this 418 * request 419 * 1 - close search if end of search 420 * reached 421 * 2 - return resume keys for each 422 * entry found 423 * 3 - resume/continue from previous 424 * ending place 425 * 4 - find with backup intent 426 * STRING FileName; Resume file name 427 * 428 * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2 429 * call. If Bit3 of Flags is set, then FileName may be the NULL string, 430 * since the search is continued from the previous TRANS2_FIND request. 431 * Otherwise, FileName must not be more than 256 characters long. 432 * 433 * Response Field Description 434 * ================================== ================================= 435 * 436 * USHORT SearchCount; Number of entries returned 437 * USHORT EndOfSearch; Was last entry returned? 438 * USHORT EaErrorOffset; Offset into EA list if EA error 439 * USHORT LastNameOffset; Offset into data to file name of 440 * last entry, if server needs it to 441 * resume search; else 0 442 * UCHAR Data[TotalDataCount] Level dependent info about the 443 * matches found in the search 444 */ 445 smb_sdrc_t 446 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa) 447 { 448 uint16_t fflag, infolev; 449 int maxdata, count, wildcards, more = 0, rc; 450 uint32_t cookie; 451 uint16_t maxcount = 0; 452 smb_node_t *dir_snode; 453 char *pattern; 454 uint16_t sattr; 455 456 /* 457 * The last parameter in the request is a path, which is a 458 * null-terminated unicode string. 459 * 460 * smb_decode_mbc(&xa->req_param_mb, "%www lwu", sr, 461 * &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &path) 462 * 463 * We don't reference this parameter and it is not currently 464 * decoded because we a expect 2-byte null but Mac OS 10 465 * clients send a 1-byte null, which leads to a decode error. 466 */ 467 if (smb_decode_mbc(&xa->req_param_mb, "%www lw", sr, 468 &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag) != 0) { 469 return (SDRC_ERROR); 470 } 471 472 sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid); 473 if (sr->sid_odir == NULL) { 474 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 475 return (SDRC_ERROR); 476 } 477 478 maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag); 479 if (maxdata == 0) { 480 smb_rdir_close(sr); 481 smbsr_error(sr, NT_STATUS_INVALID_LEVEL, 482 ERRDOS, ERROR_INVALID_LEVEL); 483 return (SDRC_ERROR); 484 } 485 486 /* 487 * When maxcount is zero Windows behaves as if it was 1. 488 */ 489 if (maxcount == 0) 490 maxcount = 1; 491 492 if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max)) 493 maxcount = smb_trans2_find_max; 494 495 /* 496 * Get a copy of information 497 */ 498 dir_snode = sr->sid_odir->d_dir_snode; 499 pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP); 500 (void) strcpy(pattern, sr->sid_odir->d_pattern); 501 wildcards = sr->sid_odir->d_wildcards; 502 sattr = sr->sid_odir->d_sattr; 503 if (fflag & SMB_FIND_CONTINUE_FROM_LAST) { 504 mutex_enter(&sr->sid_odir->d_mutex); 505 cookie = sr->sid_odir->d_cookie; 506 mutex_exit(&sr->sid_odir->d_mutex); 507 } 508 509 rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata, 510 dir_snode, sattr, maxcount, wildcards, pattern, &cookie, 511 &more, &count); 512 513 if (rc) { 514 smb_rdir_close(sr); 515 kmem_free(pattern, MAXNAMELEN); 516 smbsr_errno(sr, rc); 517 return (SDRC_ERROR); 518 } 519 520 if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST || 521 (!more && fflag & SMB_FIND_CLOSE_AT_EOS)) 522 smb_rdir_close(sr); 523 else { 524 mutex_enter(&sr->sid_odir->d_mutex); 525 sr->sid_odir->d_cookie = cookie; 526 mutex_exit(&sr->sid_odir->d_mutex); 527 } 528 529 (void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 530 count, (more ? 0 : 1), 0, 0); 531 532 kmem_free(pattern, MAXNAMELEN); 533 return (SDRC_SUCCESS); 534 } 535 536 /* 537 * smb_trans2_find_get_maxdata 538 * 539 * Calculate the minimum response space required for the specified 540 * information level. 541 * 542 * A non-zero return value provides the minimum space required. 543 * A return value of zero indicates an unknown information level. 544 */ 545 static int 546 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag) 547 { 548 int maxdata; 549 550 maxdata = smb_ascii_or_unicode_null_len(sr); 551 552 switch (infolev) { 553 case SMB_INFO_STANDARD : 554 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 555 maxdata += sizeof (int32_t); 556 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1; 557 break; 558 559 case SMB_INFO_QUERY_EA_SIZE: 560 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 561 maxdata += sizeof (int32_t); 562 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1; 563 break; 564 565 case SMB_FIND_FILE_DIRECTORY_INFO: 566 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4; 567 break; 568 569 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 570 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24; 571 break; 572 573 case SMB_FIND_FILE_NAMES_INFO: 574 maxdata += 4 + 4 + 4; 575 break; 576 577 case SMB_MAC_FIND_BOTH_HFS_INFO: 578 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 + 579 4 + 32 + 4 + 1 + 1 + 24 + 4; 580 break; 581 582 default: 583 maxdata = 0; 584 } 585 586 return (maxdata); 587 } 588 589 /* 590 * smb_trans2_find_get_dents 591 * 592 * This function will get all the directory entry information and mbc 593 * encode it in the xa. If there is an error, it will be returned; 594 * otherwise, 0 is returned. 595 * 596 * The more field will be updated. If the value returned is one, it means 597 * there are more entries; otherwise, the returned value will be zero. The 598 * cookie will also be updated to indicate the next start point for the 599 * search. The count value will also be updated to stores the total entries 600 * encoded. 601 */ 602 int smb_trans2_find_get_dents( 603 smb_request_t *sr, 604 smb_xa_t *xa, 605 uint16_t fflag, 606 uint16_t infolev, 607 int maxdata, 608 smb_node_t *dir_snode, 609 uint16_t sattr, 610 uint16_t maxcount, 611 int wildcards, 612 char *pattern, 613 uint32_t *cookie, 614 int *more, 615 int *count) 616 { 617 smb_dent_info_hdr_t *ihdr; 618 smb_dent_info_t *ient; 619 int dent_buf_size; 620 int i; 621 int total; 622 int maxentries; 623 int rc; 624 625 ihdr = kmem_zalloc(sizeof (smb_dent_info_hdr_t), KM_SLEEP); 626 *count = 0; 627 628 if (!wildcards) 629 maxentries = maxcount = 1; 630 else { 631 maxentries = (xa->rep_data_mb.max_bytes - 632 xa->rep_data_mb.chain_offset) / maxdata; 633 if (maxcount > SMB_MAX_DENTS_IOVEC) 634 maxcount = SMB_MAX_DENTS_IOVEC; 635 if (maxentries > maxcount) 636 maxentries = maxcount; 637 } 638 639 /* Each entry will need to be aligned so add _POINTER_ALIGNMENT */ 640 dent_buf_size = 641 maxentries * (SMB_MAX_DENT_INFO_SIZE + _POINTER_ALIGNMENT); 642 ihdr->iov->iov_base = kmem_alloc(dent_buf_size, KM_SLEEP); 643 644 ihdr->sattr = sattr; 645 ihdr->pattern = pattern; 646 ihdr->sr = sr; 647 648 ihdr->uio.uio_iovcnt = maxcount; 649 ihdr->uio.uio_resid = dent_buf_size; 650 ihdr->uio.uio_iov = ihdr->iov; 651 ihdr->uio.uio_loffset = 0; 652 653 rc = smb_get_dents(sr, cookie, dir_snode, wildcards, ihdr, more); 654 if (rc != 0) { 655 goto out; 656 } 657 658 if (ihdr->iov->iov_len == 0) 659 *count = 0; 660 else 661 *count = smb_trans2_find_process_ients(sr, xa, ihdr, fflag, 662 infolev, maxdata, dir_snode, more, cookie); 663 rc = 0; 664 665 out: 666 667 total = maxcount - ihdr->uio.uio_iovcnt; 668 ASSERT((total >= 0) && (total <= SMB_MAX_DENTS_IOVEC)); 669 for (i = 0; i < total; i++) { 670 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 671 ient = (smb_dent_info_t *)ihdr->iov[i].iov_base; 672 ASSERT(ient); 673 smb_node_release(ient->snode); 674 } 675 676 kmem_free(ihdr->iov->iov_base, dent_buf_size); 677 kmem_free(ihdr, sizeof (smb_dent_info_hdr_t)); 678 return (0); 679 } 680 681 682 683 /* 684 * smb_get_dents 685 * 686 * This function utilizes "smb_fsop_getdents()" to get dir entries. 687 * The "smb_gather_dents_info()" is the call back function called 688 * inside the file system. It is very important that the function 689 * does not sleep or yield since it is processed inside a file 690 * system transaction. 691 * 692 * The function returns 0 when successful and error code when failed. 693 * If more is provided, the return value of 1 is returned indicating 694 * more entries; otherwise, 0 is returned. 695 */ 696 int smb_get_dents( 697 smb_request_t *sr, 698 uint32_t *cookie, 699 smb_node_t *dir_snode, 700 uint32_t wildcards, 701 smb_dent_info_hdr_t *ihdr, 702 int *more) 703 { 704 int rc; 705 char *namebuf; 706 smb_node_t *snode; 707 smb_attr_t file_attr; 708 uint32_t maxcnt = ihdr->uio.uio_iovcnt; 709 char shortname[MANGLE_NAMELEN], name83[MANGLE_NAMELEN]; 710 fsvol_attr_t vol_attr; 711 712 namebuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 713 if (more) 714 *more = 0; 715 716 if ((rc = fsd_getattr(&sr->tid_tree->t_fsd, &vol_attr)) != 0) { 717 kmem_free(namebuf, MAXNAMELEN); 718 return (rc); 719 } 720 721 if (!wildcards) { 722 /* Already found entry? */ 723 if (*cookie != 0) 724 return (0); 725 shortname[0] = '\0'; 726 727 rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode, 728 dir_snode, ihdr->pattern, &snode, &file_attr, shortname, 729 name83); 730 731 if (rc) { 732 kmem_free(namebuf, MAXNAMELEN); 733 return (rc); 734 } 735 736 (void) strlcpy(namebuf, ihdr->pattern, MAXNAMELEN); 737 738 /* 739 * It is not necessary to set the "force" flag (i.e. to 740 * take into account mangling for case-insensitive collisions) 741 */ 742 743 if (shortname[0] == '\0') 744 (void) smb_mangle_name(snode->attr.sa_vattr.va_nodeid, 745 namebuf, shortname, name83, 0); 746 (void) smb_gather_dents_info((char *)ihdr, 747 snode->attr.sa_vattr.va_nodeid, 748 strlen(namebuf), namebuf, -1, (int *)&maxcnt, 749 &snode->attr, snode, shortname, name83); 750 kmem_free(namebuf, MAXNAMELEN); 751 return (0); 752 } 753 754 if ((rc = smb_fsop_getdents(sr, sr->user_cr, dir_snode, cookie, 755 0, (int *)&maxcnt, (char *)ihdr, ihdr->pattern)) != 0) { 756 if (rc == ENOENT) { 757 kmem_free(namebuf, MAXNAMELEN); 758 return (0); 759 } 760 kmem_free(namebuf, MAXNAMELEN); 761 return (rc); 762 } 763 764 if (*cookie != 0x7FFFFFFF && more) 765 *more = 1; 766 767 kmem_free(namebuf, MAXNAMELEN); 768 return (0); 769 } 770 771 772 773 774 /* 775 * smb_gather_dents_info 776 * 777 * The function will accept information of each directory entry and put 778 * the needed information in the buffer. It is passed as the call back 779 * function for smb_fsop_getdents() to gather trans2 find info. 780 * 781 * If the buffer space is not enough, -1 will be returned. Regardless 782 * of valid entry or not, 0 will be returned; however, only valid entry 783 * will be stored in the buffer. 784 */ 785 int /*ARGSUSED*/ 786 smb_gather_dents_info( 787 char *args, 788 ino_t fileid, 789 int namelen, 790 char *name, 791 uint32_t cookie, 792 int32_t *countp, 793 smb_attr_t *attr, 794 smb_node_t *snode, 795 char *shortname, 796 char *name83) 797 { 798 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 799 smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)args; 800 smb_dent_info_t *ient; 801 uint8_t *v5_name = NULL; 802 uint8_t *np = (uint8_t *)name; 803 int reclen = sizeof (smb_dent_info_t) + namelen; 804 805 v5_name = kmem_alloc(MAXNAMELEN-1, KM_SLEEP); 806 807 if (!ihdr->uio.uio_iovcnt || ihdr->uio.uio_resid < reclen) { 808 kmem_free(v5_name, MAXNAMELEN-1); 809 smb_node_release(snode); 810 return (-1); 811 } 812 813 if (!smb_sattr_check(attr, name, ihdr->sattr)) { 814 kmem_free(v5_name, MAXNAMELEN-1); 815 smb_node_release(snode); 816 return (0); 817 } 818 819 if (catia_callback) { 820 catia_callback(v5_name, (uint8_t *)name, MAXNAMELEN-1); 821 np = v5_name; 822 reclen = sizeof (smb_dent_info_t) + strlen((char *)v5_name); 823 } 824 825 ASSERT(snode); 826 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 827 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 828 829 /* 830 * Each entry needs to be properly aligned or we may get an alignment 831 * fault on sparc. 832 */ 833 ihdr->uio.uio_loffset = (offset_t)PTRALIGN(ihdr->uio.uio_loffset); 834 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 835 ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_loffset]; 836 837 ient->cookie = cookie; 838 ient->attr = *attr; 839 ient->snode = snode; 840 841 (void) strcpy(ient->name, (char *)np); 842 (void) strcpy(ient->shortname, shortname); 843 (void) strcpy(ient->name83, name83); 844 ihdr->uio.uio_iov->iov_base = (char *)ient; 845 ihdr->uio.uio_iov->iov_len = reclen; 846 847 ihdr->uio.uio_iov++; 848 ihdr->uio.uio_iovcnt--; 849 ihdr->uio.uio_resid -= reclen; 850 ihdr->uio.uio_loffset += reclen; 851 852 kmem_free(v5_name, MAXNAMELEN-1); 853 return (0); 854 } 855 856 857 858 /* 859 * smb_trans2_find_process_ients 860 * 861 * This function encodes the directory entry information store in 862 * the iov structure of the ihdr structure. 863 * 864 * The total entries encoded will be returned. If the entries encoded 865 * is less than the total entries in the iov, the more field will 866 * be updated to 1. Also, the next cookie wil be updated as well. 867 */ 868 int 869 smb_trans2_find_process_ients( 870 smb_request_t *sr, 871 smb_xa_t *xa, 872 smb_dent_info_hdr_t *ihdr, 873 uint16_t fflag, 874 uint16_t infolev, 875 int maxdata, 876 smb_node_t *dir_snode, 877 int *more, 878 uint32_t *cookie) 879 { 880 int i, err = 0; 881 smb_dent_info_t *ient; 882 uint32_t mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) 883 ? SMB_MSGBUF_UNICODE : 0; 884 885 for (i = 0; i < SMB_MAX_DENTS_IOVEC; i++) { 886 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 887 if ((ient = (smb_dent_info_t *)ihdr->iov[i].iov_base) == 0) 888 break; 889 890 /* 891 * Observed differences between our response and Windows 892 * response, which hasn't caused a problem yet! 893 * 894 * 1. The NextEntryOffset field for the last entry should 895 * be 0. This code always calculate the record length 896 * and puts the result in the NextEntryOffset field. 897 * 898 * 2. The FileIndex field is always 0. This code puts 899 * the cookie in the FileIndex field. 900 */ 901 err = smb_trans2_find_mbc_encode(sr, xa, ient, maxdata, infolev, 902 fflag, mb_flags, dir_snode, NULL); 903 904 if (err) 905 break; 906 } 907 908 /* 909 * Not enough space to store all the entries returned, 910 * which is indicated by setting more. 911 */ 912 if (more && err < 0) { 913 *more = 1; 914 915 /* 916 * Assume the space will be at least enough for 1 entry. 917 */ 918 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 919 ient = (smb_dent_info_t *)ihdr->iov[i-1].iov_base; 920 *cookie = ient->cookie; 921 } 922 return (i); 923 } 924 925 /* 926 * smb_trans2_find_mbc_encode 927 * 928 * This function encodes the mbc for one directory entry. 929 * 930 * The function returns -1 when the max data requested by client 931 * is reached. If the entry is valid and successful encoded, 0 932 * will be returned; otherwise, 1 will be returned. 933 */ 934 int /*ARGSUSED*/ 935 smb_trans2_find_mbc_encode( 936 smb_request_t *sr, 937 smb_xa_t *xa, 938 smb_dent_info_t *ient, 939 int maxdata, 940 uint16_t infolev, 941 uint16_t fflag, 942 uint32_t mb_flags, 943 smb_node_t *dir_snode, 944 smb_node_t *sd_snode) 945 { 946 int uni_namelen; 947 int shortlen; 948 uint32_t next_entry_offset; 949 char buf83[26]; 950 smb_msgbuf_t mb; 951 uint32_t dattr = 0; 952 uint32_t dsize32 = 0; 953 uint32_t asize32 = 0; 954 u_offset_t datasz = 0; 955 u_offset_t allocsz = 0; 956 smb_node_t *lnk_snode; 957 smb_attr_t lnkattr; 958 int rc; 959 960 uni_namelen = smb_ascii_or_unicode_strlen(sr, ient->name); 961 if (uni_namelen == -1) 962 return (1); 963 964 next_entry_offset = maxdata + uni_namelen; 965 966 if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + uni_namelen)) == 0) 967 return (-1); 968 969 if (ient->attr.sa_vattr.va_type == VLNK) { 970 rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, 971 sr->tid_tree->t_snode, dir_snode, ient->name, &lnk_snode, 972 &lnkattr, 0, 0); 973 974 /* 975 * We normally want to resolve the object to which a symlink 976 * refers so that CIFS clients can access sub-directories and 977 * find the correct association for files. This causes a 978 * problem, however, if a symlink in a sub-directory points 979 * to a parent directory (some UNIX GUI's create a symlink in 980 * $HOME/.desktop that points to the user's home directory). 981 * Some Windows applications (i.e. virus scanning) loop/hang 982 * trying to follow this recursive path and there is little 983 * we can do because the path is constructed on the client. 984 * skc_dirsymlink_enable allows an end-user to disable 985 * symlinks to directories. Symlinks to other object types 986 * should be unaffected. 987 */ 988 if (rc == 0) { 989 if (smb_dirsymlink_enable || 990 (lnkattr.sa_vattr.va_type != VDIR)) { 991 smb_node_release(ient->snode); 992 ient->snode = lnk_snode; 993 ient->attr = lnkattr; 994 } else { 995 smb_node_release(lnk_snode); 996 } 997 } 998 } 999 1000 if (infolev != SMB_FIND_FILE_NAMES_INFO) { 1001 /* data size */ 1002 datasz = smb_node_get_size(ient->snode, &ient->attr); 1003 dsize32 = (datasz > UINT_MAX) ? UINT_MAX : (uint32_t)datasz; 1004 1005 /* allocation size */ 1006 allocsz = ient->attr.sa_vattr.va_nblocks * DEV_BSIZE; 1007 asize32 = (allocsz > UINT_MAX) ? UINT_MAX : (uint32_t)allocsz; 1008 1009 dattr = smb_mode_to_dos_attributes(&ient->attr); 1010 } 1011 1012 switch (infolev) { 1013 case SMB_INFO_STANDARD: 1014 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 1015 (void) smb_encode_mbc(&xa->rep_data_mb, "l", 1016 ient->cookie); 1017 1018 (void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwbu", sr, 1019 ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec : 1020 ient->attr.sa_vattr.va_mtime.tv_sec, 1021 ient->attr.sa_vattr.va_atime.tv_sec, 1022 ient->attr.sa_vattr.va_mtime.tv_sec, 1023 dsize32, 1024 asize32, 1025 dattr, 1026 uni_namelen, 1027 ient->name); 1028 break; 1029 1030 case SMB_INFO_QUERY_EA_SIZE: 1031 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 1032 (void) smb_encode_mbc(&xa->rep_data_mb, "l", 1033 ient->cookie); 1034 1035 (void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwlbu", sr, 1036 ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec : 1037 ient->attr.sa_vattr.va_mtime.tv_sec, 1038 ient->attr.sa_vattr.va_atime.tv_sec, 1039 ient->attr.sa_vattr.va_mtime.tv_sec, 1040 dsize32, 1041 asize32, 1042 dattr, 1043 0L, /* EA Size */ 1044 uni_namelen, 1045 ient->name); 1046 break; 1047 1048 case SMB_FIND_FILE_DIRECTORY_INFO: 1049 (void) smb_encode_mbc(&xa->rep_data_mb, "%llTTTTqqllu", sr, 1050 next_entry_offset, 1051 ient->cookie, 1052 ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime : 1053 &ient->attr.sa_vattr.va_mtime, 1054 &ient->attr.sa_vattr.va_atime, 1055 &ient->attr.sa_vattr.va_mtime, 1056 &ient->attr.sa_vattr.va_ctime, 1057 (uint64_t)datasz, 1058 (uint64_t)allocsz, 1059 dattr, 1060 uni_namelen, 1061 ient->name); 1062 break; 1063 1064 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 1065 bzero(buf83, sizeof (buf83)); 1066 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), 1067 mb_flags); 1068 if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) { 1069 smb_msgbuf_term(&mb); 1070 return (-1); 1071 } 1072 shortlen = smb_ascii_or_unicode_strlen(sr, ient->shortname); 1073 1074 (void) smb_encode_mbc(&xa->rep_data_mb, "%llTTTTqqlllb.24cu", 1075 sr, 1076 next_entry_offset, 1077 ient->cookie, 1078 ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime : 1079 &ient->attr.sa_vattr.va_mtime, 1080 &ient->attr.sa_vattr.va_atime, 1081 &ient->attr.sa_vattr.va_mtime, 1082 &ient->attr.sa_vattr.va_ctime, 1083 (uint64_t)datasz, 1084 (uint64_t)allocsz, 1085 dattr, 1086 uni_namelen, 1087 0L, 1088 shortlen, 1089 buf83, 1090 ient->name); 1091 1092 smb_msgbuf_term(&mb); 1093 break; 1094 1095 case SMB_FIND_FILE_NAMES_INFO: 1096 (void) smb_encode_mbc(&xa->rep_data_mb, "%lllu", sr, 1097 next_entry_offset, 1098 ient->cookie, 1099 uni_namelen, 1100 ient->name); 1101 break; 1102 } 1103 1104 return (0); 1105 } 1106 1107 /* 1108 * Close a search started by a Trans2FindFirst2 request. 1109 */ 1110 smb_sdrc_t 1111 smb_pre_find_close2(smb_request_t *sr) 1112 { 1113 int rc; 1114 1115 rc = smbsr_decode_vwv(sr, "w", &sr->smb_sid); 1116 1117 DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr); 1118 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1119 } 1120 1121 void 1122 smb_post_find_close2(smb_request_t *sr) 1123 { 1124 DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr); 1125 } 1126 1127 smb_sdrc_t 1128 smb_com_find_close2(smb_request_t *sr) 1129 { 1130 sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid); 1131 if (sr->sid_odir == NULL) { 1132 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 1133 return (SDRC_ERROR); 1134 } 1135 1136 smb_rdir_close(sr); 1137 1138 if (smbsr_encode_empty_result(sr)) 1139 return (SDRC_ERROR); 1140 1141 return (SDRC_SUCCESS); 1142 } 1143