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 2012 Nexenta Systems, Inc. All rights reserved. 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 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 * SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO 0x105 48 * SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO 0x106 49 * 50 * The following sections detail the data returned for each 51 * InformationLevel. The requested information is placed in the Data 52 * portion of the transaction response. Note: a client which does not 53 * support long names can only request SMB_INFO_STANDARD. 54 * 55 * A four-byte resume key precedes each data item (described below) if bit 56 * 2 in the Flags field is set, i.e. if the request indicates the server 57 * should return resume keys. Note: it is not always the case. If the 58 * data item already includes the resume key, the resume key should not be 59 * added again. 60 * 61 * 4.3.4.1 SMB_INFO_STANDARD 62 * 63 * Response Field Description 64 * ================================ ================================== 65 * 66 * SMB_DATE CreationDate; Date when file was created 67 * SMB_TIME CreationTime; Time when file was created 68 * SMB_DATE LastAccessDate; Date of last file access 69 * SMB_TIME LastAccessTime; Time of last file access 70 * SMB_DATE LastWriteDate; Date of last write to the file 71 * SMB_TIME LastWriteTime; Time of last write to the file 72 * ULONG DataSize; File Size 73 * ULONG AllocationSize; Size of filesystem allocation unit 74 * USHORT Attributes; File Attributes 75 * UCHAR FileNameLength; Length of filename in bytes 76 * STRING FileName; Name of found file 77 * 78 * 4.3.4.2 SMB_INFO_QUERY_EA_SIZE 79 * 80 * Response Field Description 81 * ================================= ================================== 82 * 83 * SMB_DATE CreationDate; Date when file was created 84 * SMB_TIME CreationTime; Time when file was created 85 * SMB_DATE LastAccessDate; Date of last file access 86 * SMB_TIME LastAccessTime; Time of last file access 87 * SMB_DATE LastWriteDate; Date of last write to the file 88 * SMB_TIME LastWriteTime; Time of last write to the file 89 * ULONG DataSize; File Size 90 * ULONG AllocationSize; Size of filesystem allocation unit 91 * USHORT Attributes; File Attributes 92 * ULONG EaSize; Size of file's EA information 93 * UCHAR FileNameLength; Length of filename in bytes 94 * STRING FileName; Name of found file 95 * 96 * 4.3.4.3 SMB_INFO_QUERY_EAS_FROM_LIST 97 * 98 * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but 99 * only for files which have an EA list which match the EA information in 100 * the Data part of the request. 101 * 102 * 4.3.4.4 SMB_FIND_FILE_DIRECTORY_INFO 103 * 104 * Response Field Description 105 * ================================= ================================== 106 * 107 * ULONG NextEntryOffset; Offset from this structure to 108 * beginning of next one 109 * ULONG FileIndex; 110 * LARGE_INTEGER CreationTime; file creation time 111 * LARGE_INTEGER LastAccessTime; last access time 112 * LARGE_INTEGER LastWriteTime; last write time 113 * LARGE_INTEGER ChangeTime; last attribute change time 114 * LARGE_INTEGER EndOfFile; file size 115 * LARGE_INTEGER AllocationSize; size of filesystem allocation information 116 * ULONG ExtFileAttributes; Extended file attributes 117 * (see section 3.11) 118 * ULONG FileNameLength; Length of filename in bytes 119 * STRING FileName; Name of the file 120 * 121 * 4.3.4.5 SMB_FIND_FILE_FULL_DIRECTORY_INFO 122 * 123 * Response Field Description 124 * ================================= ================================== 125 * 126 * ULONG NextEntryOffset; Offset from this structure to 127 * beginning of next one 128 * ULONG FileIndex; 129 * LARGE_INTEGER CreationTime; file creation time 130 * LARGE_INTEGER LastAccessTime; last access time 131 * LARGE_INTEGER LastWriteTime; last write time 132 * LARGE_INTEGER ChangeTime; last attribute change time 133 * LARGE_INTEGER EndOfFile; file size 134 * LARGE_INTEGER AllocationSize; size of filesystem allocation information 135 * ULONG ExtFileAttributes; Extended file attributes 136 * (see section 3.11) 137 * ULONG FileNameLength; Length of filename in bytes 138 * ULONG EaSize; Size of file's extended attributes 139 * STRING FileName; Name of the file 140 * 141 * 142 * SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO 143 * 144 * This is the same as SMB_FIND_FILE_FULL_DIRECTORY_INFO but with 145 * FileId inserted after EaSize. FileId is preceded by a 4 byte 146 * alignment padding. 147 * 148 * Response Field Description 149 * ================================= ================================== 150 * ... 151 * ULONG EaSize; Size of file's extended attributes 152 * UCHAR Reserved[4] 153 * LARGE_INTEGER FileId Internal file system unique id. 154 * STRING FileName; Name of the file 155 * 156 * 4.3.4.6 SMB_FIND_FILE_BOTH_DIRECTORY_INFO 157 * 158 * Response Field Description 159 * ================================= ================================== 160 * 161 * ULONG NextEntryOffset; Offset from this structure to 162 * beginning of next one 163 * ULONG FileIndex; 164 * LARGE_INTEGER CreationTime; file creation time 165 * LARGE_INTEGER LastAccessTime; last access time 166 * LARGE_INTEGER LastWriteTime; last write time 167 * LARGE_INTEGER ChangeTime; last attribute change time 168 * LARGE_INTEGER EndOfFile; file size 169 * LARGE_INTEGER AllocationSize; size of filesystem allocation information 170 * ULONG ExtFileAttributes; Extended file attributes 171 * (see section 3.11) 172 * ULONG FileNameLength; Length of FileName in bytes 173 * ULONG EaSize; Size of file's extended attributes 174 * UCHAR ShortNameLength; Length of file's short name in bytes 175 * UCHAR Reserved 176 * WCHAR ShortName[12]; File's 8.3 conformant name in Unicode 177 * STRING FileName; Files full length name 178 * 179 * 180 * SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO 181 * 182 * This is the same as SMB_FIND_FILE_BOTH_DIRECTORY_INFO but with 183 * FileId inserted after ShortName. FileId is preceded by a 2 byte 184 * alignment pad. 185 * 186 * Response Field Description 187 * ================================= ================================== 188 * ... 189 * WCHAR ShortName[12]; File's 8.3 conformant name in Unicode 190 * UCHAR Reserved[2] 191 * LARGE_INTEGER FileId Internal file system unique id. 192 * STRING FileName; Files full length name 193 * 194 * 4.3.4.7 SMB_FIND_FILE_NAMES_INFO 195 * 196 * Response Field Description 197 * ================================= ================================== 198 * 199 * ULONG NextEntryOffset; Offset from this structure to 200 * beginning of next one 201 * ULONG FileIndex; 202 * ULONG FileNameLength; Length of FileName in bytes 203 * STRING FileName; Files full length name 204 */ 205 206 #include <smbsrv/smb_kproto.h> 207 #include <smbsrv/msgbuf.h> 208 #include <smbsrv/smb_fsops.h> 209 210 /* 211 * Args (and other state) that we carry around among the 212 * various functions involved in FindFirst, FindNext. 213 */ 214 typedef struct smb_find_args { 215 uint32_t fa_maxdata; 216 uint16_t fa_infolev; 217 uint16_t fa_maxcount; 218 uint16_t fa_fflag; 219 uint16_t fa_eos; /* End Of Search */ 220 uint16_t fa_lno; /* Last Name Offset */ 221 uint32_t fa_lastkey; /* Last resume key */ 222 char fa_lastname[MAXNAMELEN]; /* and name */ 223 } smb_find_args_t; 224 225 static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *, 226 smb_odir_t *, smb_find_args_t *); 227 static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t); 228 static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *, 229 smb_fileinfo_t *, smb_find_args_t *); 230 231 /* 232 * Tunable parameter to limit the maximum 233 * number of entries to be returned. 234 */ 235 uint16_t smb_trans2_find_max = 128; 236 237 /* 238 * smb_com_trans2_find_first2 239 * 240 * Client Request Value 241 * ============================ ================================== 242 * 243 * UCHAR WordCount 15 244 * UCHAR TotalDataCount Total size of extended attribute list 245 * UCHAR SetupCount 1 246 * UCHAR Setup[0] TRANS2_FIND_FIRST2 247 * 248 * Parameter Block Encoding Description 249 * ============================ ================================== 250 * USHORT SearchAttributes; 251 * USHORT SearchCount; Maximum number of entries to return 252 * USHORT Flags; Additional information: 253 * Bit 0 - close search after this request 254 * Bit 1 - close search if end of search 255 * reached 256 * Bit 2 - return resume keys for each 257 * entry found 258 * Bit 3 - continue search from previous 259 * ending place 260 * Bit 4 - find with backup intent 261 * USHORT InformationLevel; See below 262 * ULONG SearchStorageType; 263 * STRING FileName; Pattern for the search 264 * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is 265 * QUERY_EAS_FROM_LIST 266 * 267 * Response Parameter Block Description 268 * ============================ ================================== 269 * 270 * USHORT Sid; Search handle 271 * USHORT SearchCount; Number of entries returned 272 * USHORT EndOfSearch; Was last entry returned? 273 * USHORT EaErrorOffset; Offset into EA list if EA error 274 * USHORT LastNameOffset; Offset into data to file name of last 275 * entry, if server needs it to resume 276 * search; else 0 277 * UCHAR Data[ TotalDataCount ] Level dependent info about the matches 278 * found in the search 279 */ 280 smb_sdrc_t 281 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) 282 { 283 int count; 284 uint16_t sattr, odid; 285 smb_pathname_t *pn; 286 smb_odir_t *od; 287 smb_find_args_t args; 288 uint32_t odir_flags = 0; 289 290 bzero(&args, sizeof (smb_find_args_t)); 291 292 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 293 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 294 ERRDOS, ERROR_ACCESS_DENIED); 295 return (SDRC_ERROR); 296 } 297 298 pn = &sr->arg.dirop.fqi.fq_path; 299 300 if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr, 301 &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev, 302 &pn->pn_path) != 0) { 303 return (SDRC_ERROR); 304 } 305 306 smb_pathname_init(sr, pn, pn->pn_path); 307 if (!smb_pathname_validate(sr, pn)) 308 return (-1); 309 310 if (smb_is_stream_name(pn->pn_path)) { 311 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 312 ERRDOS, ERROR_INVALID_NAME); 313 return (SDRC_ERROR); 314 } 315 316 if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) { 317 sr->user_cr = smb_user_getprivcred(sr->uid_user); 318 odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT; 319 } 320 321 args.fa_maxdata = 322 smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); 323 if (args.fa_maxdata == 0) 324 return (SDRC_ERROR); 325 326 odid = smb_odir_open(sr, pn->pn_path, sattr, odir_flags); 327 if (odid == 0) { 328 if (sr->smb_error.status == NT_STATUS_OBJECT_PATH_NOT_FOUND) { 329 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 330 ERRDOS, ERROR_FILE_NOT_FOUND); 331 } 332 return (SDRC_ERROR); 333 } 334 335 od = smb_tree_lookup_odir(sr, odid); 336 if (od == NULL) 337 return (SDRC_ERROR); 338 339 count = smb_trans2_find_entries(sr, xa, od, &args); 340 341 if (count == -1) { 342 smb_odir_close(od); 343 smb_odir_release(od); 344 return (SDRC_ERROR); 345 } 346 347 if (count == 0) { 348 smb_odir_close(od); 349 smb_odir_release(od); 350 smbsr_errno(sr, ENOENT); 351 return (SDRC_ERROR); 352 } 353 354 if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || 355 (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { 356 smb_odir_close(od); 357 } /* else leave odir open for trans2_find_next2 */ 358 359 smb_odir_release(od); 360 361 (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww", 362 odid, /* Search ID */ 363 count, /* Search Count */ 364 args.fa_eos, /* End Of Search */ 365 0, /* EA Error Offset */ 366 args.fa_lno); /* Last Name Offset */ 367 368 return (SDRC_SUCCESS); 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 * 421 * The last parameter in the request is a filename, which is a 422 * null-terminated unicode string. 423 * 424 * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr, 425 * &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname) 426 * 427 * The filename parameter is not currently decoded because we 428 * expect a 2-byte null but Mac OS 10 clients send a 1-byte null, 429 * which leads to a decode error. 430 * Thus, we do not support resume by filename. We treat a request 431 * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST. 432 */ 433 smb_sdrc_t 434 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa) 435 { 436 int count; 437 uint16_t odid; 438 smb_odir_t *od; 439 smb_find_args_t args; 440 smb_odir_resume_t odir_resume; 441 442 bzero(&args, sizeof (args)); 443 bzero(&odir_resume, sizeof (odir_resume)); 444 445 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 446 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 447 ERRDOS, ERROR_ACCESS_DENIED); 448 return (SDRC_ERROR); 449 } 450 451 if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlwu", sr, 452 &odid, &args.fa_maxcount, &args.fa_infolev, 453 &odir_resume.or_cookie, &args.fa_fflag, 454 &odir_resume.or_fname) != 0) { 455 return (SDRC_ERROR); 456 } 457 458 if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) 459 sr->user_cr = smb_user_getprivcred(sr->uid_user); 460 461 args.fa_maxdata = 462 smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); 463 if (args.fa_maxdata == 0) 464 return (SDRC_ERROR); 465 466 od = smb_tree_lookup_odir(sr, odid); 467 if (od == NULL) { 468 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 469 ERRDOS, ERROR_INVALID_HANDLE); 470 return (SDRC_ERROR); 471 } 472 473 /* 474 * Set the correct position in the directory. 475 * 476 * "Continue from last" is easy, but due to a history of 477 * buggy server implementations, most clients don't use 478 * that method. The most widely used (and reliable) is 479 * resume by file name. Unfortunately, that can't really 480 * be fully supported unless your file system stores all 481 * directory entries in some sorted order (like NTFS). 482 * We can partially support resume by name, where the only 483 * name we're ever asked to resume on is the same as the 484 * most recent we returned. That's always what the client 485 * gives us as the resume name, so we can simply remember 486 * the last name/offset pair and use that to position on 487 * the following FindNext call. In the unlikely event 488 * that the client asks to resume somewhere else, we'll 489 * use the numeric resume key, and hope the client gives 490 * correctly uses one of the resume keys we provided. 491 */ 492 if (args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) { 493 odir_resume.or_type = SMB_ODIR_RESUME_CONT; 494 } else { 495 odir_resume.or_type = SMB_ODIR_RESUME_FNAME; 496 } 497 smb_odir_resume_at(od, &odir_resume); 498 499 count = smb_trans2_find_entries(sr, xa, od, &args); 500 if (count == -1) { 501 smb_odir_close(od); 502 smb_odir_release(od); 503 return (SDRC_ERROR); 504 } 505 506 if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || 507 (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { 508 smb_odir_close(od); 509 } /* else leave odir open for trans2_find_next2 */ 510 511 smb_odir_release(od); 512 513 (void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", 514 count, /* Search Count */ 515 args.fa_eos, /* End Of Search */ 516 0, /* EA Error Offset */ 517 args.fa_lno); /* Last Name Offset */ 518 519 return (SDRC_SUCCESS); 520 } 521 522 523 /* 524 * smb_trans2_find_entries 525 * 526 * Find and encode up to args->fa_maxcount directory entries. 527 * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1. 528 * 529 * Returns: 530 * count - count of entries encoded 531 * *eos = B_TRUE if no more directory entries 532 * -1 - error 533 */ 534 static int 535 smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od, 536 smb_find_args_t *args) 537 { 538 int rc; 539 uint16_t count, maxcount; 540 smb_fileinfo_t fileinfo; 541 smb_odir_resume_t odir_resume; 542 543 if ((maxcount = args->fa_maxcount) == 0) 544 maxcount = 1; 545 546 if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max)) 547 maxcount = smb_trans2_find_max; 548 549 count = 0; 550 while (count < maxcount) { 551 if (smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos) 552 != 0) 553 return (-1); 554 if (args->fa_eos != 0) 555 break; 556 557 rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args); 558 if (rc == -1) 559 return (-1); 560 if (rc == 1) 561 break; 562 563 /* 564 * Save the info about the last file returned. 565 */ 566 args->fa_lastkey = fileinfo.fi_cookie; 567 bcopy(fileinfo.fi_name, args->fa_lastname, MAXNAMELEN); 568 569 ++count; 570 } 571 572 /* save the last cookie returned to client */ 573 if (count != 0) 574 smb_odir_save_fname(od, args->fa_lastkey, args->fa_lastname); 575 576 /* 577 * If all retrieved entries have been successfully encoded 578 * and eos has not already been detected, check if there are 579 * any more entries. eos will be set if there are no more. 580 */ 581 if ((rc == 0) && (args->fa_eos == 0)) 582 (void) smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos); 583 584 /* 585 * When the last entry we read from the directory did not 586 * fit in the return buffer, we will have read one entry 587 * that will not be returned in this call. That, and the 588 * check for EOS just above both can leave the directory 589 * position incorrect for the next call. Fix that now. 590 */ 591 bzero(&odir_resume, sizeof (odir_resume)); 592 odir_resume.or_type = SMB_ODIR_RESUME_COOKIE; 593 odir_resume.or_cookie = args->fa_lastkey; 594 smb_odir_resume_at(od, &odir_resume); 595 596 return (count); 597 } 598 599 /* 600 * smb_trans2_find_get_maxdata 601 * 602 * Calculate the minimum response space required for the specified 603 * information level. 604 * 605 * A non-zero return value provides the minimum space required. 606 * A return value of zero indicates an unknown information level. 607 */ 608 static int 609 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag) 610 { 611 int maxdata; 612 613 maxdata = smb_ascii_or_unicode_null_len(sr); 614 615 switch (infolev) { 616 case SMB_INFO_STANDARD : 617 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 618 maxdata += sizeof (int32_t); 619 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1; 620 break; 621 622 case SMB_INFO_QUERY_EA_SIZE: 623 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 624 maxdata += sizeof (int32_t); 625 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1; 626 break; 627 628 case SMB_FIND_FILE_DIRECTORY_INFO: 629 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4; 630 break; 631 632 case SMB_FIND_FILE_FULL_DIRECTORY_INFO: 633 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4; 634 break; 635 636 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: 637 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8; 638 break; 639 640 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 641 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24; 642 break; 643 644 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: 645 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24 646 + 2 + 8; 647 break; 648 649 case SMB_FIND_FILE_NAMES_INFO: 650 maxdata += 4 + 4 + 4; 651 break; 652 653 case SMB_MAC_FIND_BOTH_HFS_INFO: 654 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 + 655 4 + 32 + 4 + 1 + 1 + 24 + 4; 656 break; 657 658 default: 659 maxdata = 0; 660 smbsr_error(sr, NT_STATUS_INVALID_LEVEL, 661 ERRDOS, ERROR_INVALID_LEVEL); 662 } 663 664 return (maxdata); 665 } 666 667 /* 668 * This is an experimental feature that allows us to return zero 669 * for all numeric resume keys, to match Windows behavior with an 670 * NTFS share. Setting this variable to zero does that. 671 * 672 * It's possible we could remove this variable and always set 673 * numeric resume keys to zero, but that would leave us unable 674 * to handle a FindNext call with an arbitrary start position. 675 * In practice we never see these, but in theory we could. 676 * 677 * See the long comment above smb_com_trans2_find_next2() for 678 * more details about resume key / resume name handling. 679 */ 680 int smbd_use_resume_keys = 1; 681 682 /* 683 * smb_trans2_mbc_encode 684 * 685 * This function encodes the mbc for one directory entry. 686 * 687 * The function returns -1 when the max data requested by client 688 * is reached. If the entry is valid and successful encoded, 0 689 * will be returned; otherwise, 1 will be returned. 690 * 691 * We always null terminate the filename. The space for the null 692 * is included in the maxdata calculation and is therefore included 693 * in the next_entry_offset. namelen is the unterminated length of 694 * the filename. For levels except STANDARD and EA_SIZE, if the 695 * filename is ascii the name length returned to the client should 696 * include the null terminator. Otherwise the length returned to 697 * the client should not include the terminator. 698 * 699 * Returns: 0 - data successfully encoded 700 * 1 - client request's maxdata limit reached 701 * -1 - error 702 */ 703 static int 704 smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa, 705 smb_fileinfo_t *fileinfo, smb_find_args_t *args) 706 { 707 int namelen, shortlen; 708 uint32_t next_entry_offset; 709 uint32_t dsize32, asize32; 710 uint32_t mb_flags = 0; 711 uint32_t resume_key; 712 char buf83[26]; 713 smb_msgbuf_t mb; 714 715 namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name); 716 if (namelen == -1) 717 return (-1); 718 719 /* 720 * If ascii the filename length returned to the client should 721 * include the null terminator for levels except STANDARD and 722 * EASIZE. 723 */ 724 if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) { 725 if ((args->fa_infolev != SMB_INFO_STANDARD) && 726 (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE)) 727 namelen += 1; 728 } 729 730 next_entry_offset = args->fa_maxdata + namelen; 731 732 if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0) 733 return (1); 734 735 mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0; 736 dsize32 = (fileinfo->fi_size > UINT_MAX) ? 737 UINT_MAX : (uint32_t)fileinfo->fi_size; 738 asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ? 739 UINT_MAX : (uint32_t)fileinfo->fi_alloc_size; 740 741 resume_key = fileinfo->fi_cookie; 742 if (smbd_use_resume_keys == 0) 743 resume_key = 0; 744 745 /* 746 * This switch handles all the "information levels" (formats) 747 * that we support. Note that all formats have the file name 748 * placed after some fixed-size data, and the code to write 749 * the file name is factored out at the end of this switch. 750 */ 751 switch (args->fa_infolev) { 752 case SMB_INFO_STANDARD: 753 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) 754 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 755 resume_key); 756 757 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwb", sr, 758 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), 759 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), 760 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), 761 dsize32, 762 asize32, 763 fileinfo->fi_dosattr, 764 namelen); 765 break; 766 767 case SMB_INFO_QUERY_EA_SIZE: 768 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) 769 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 770 resume_key); 771 772 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb", sr, 773 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), 774 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), 775 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), 776 dsize32, 777 asize32, 778 fileinfo->fi_dosattr, 779 0L, /* EA Size */ 780 namelen); 781 break; 782 783 case SMB_FIND_FILE_DIRECTORY_INFO: 784 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqll", sr, 785 next_entry_offset, 786 resume_key, 787 &fileinfo->fi_crtime, 788 &fileinfo->fi_atime, 789 &fileinfo->fi_mtime, 790 &fileinfo->fi_ctime, 791 fileinfo->fi_size, 792 fileinfo->fi_alloc_size, 793 fileinfo->fi_dosattr, 794 namelen); 795 break; 796 797 case SMB_FIND_FILE_FULL_DIRECTORY_INFO: 798 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll", sr, 799 next_entry_offset, 800 resume_key, 801 &fileinfo->fi_crtime, 802 &fileinfo->fi_atime, 803 &fileinfo->fi_mtime, 804 &fileinfo->fi_ctime, 805 fileinfo->fi_size, 806 fileinfo->fi_alloc_size, 807 fileinfo->fi_dosattr, 808 namelen, 809 0L); 810 break; 811 812 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: 813 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.q", sr, 814 next_entry_offset, 815 resume_key, 816 &fileinfo->fi_crtime, 817 &fileinfo->fi_atime, 818 &fileinfo->fi_mtime, 819 &fileinfo->fi_ctime, 820 fileinfo->fi_size, 821 fileinfo->fi_alloc_size, 822 fileinfo->fi_dosattr, 823 namelen, 824 0L, 825 fileinfo->fi_nodeid); 826 break; 827 828 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 829 bzero(buf83, sizeof (buf83)); 830 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), 831 mb_flags); 832 if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) { 833 smb_msgbuf_term(&mb); 834 return (-1); 835 } 836 shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname); 837 838 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24c", 839 sr, 840 next_entry_offset, 841 resume_key, 842 &fileinfo->fi_crtime, 843 &fileinfo->fi_atime, 844 &fileinfo->fi_mtime, 845 &fileinfo->fi_ctime, 846 fileinfo->fi_size, 847 fileinfo->fi_alloc_size, 848 fileinfo->fi_dosattr, 849 namelen, 850 0L, 851 shortlen, 852 buf83); 853 854 smb_msgbuf_term(&mb); 855 break; 856 857 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: 858 bzero(buf83, sizeof (buf83)); 859 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), 860 mb_flags); 861 if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) { 862 smb_msgbuf_term(&mb); 863 return (-1); 864 } 865 shortlen = smb_ascii_or_unicode_strlen(sr, 866 fileinfo->fi_shortname); 867 868 (void) smb_mbc_encodef(&xa->rep_data_mb, 869 "%llTTTTqqlllb.24c2.q", 870 sr, 871 next_entry_offset, 872 resume_key, 873 &fileinfo->fi_crtime, 874 &fileinfo->fi_atime, 875 &fileinfo->fi_mtime, 876 &fileinfo->fi_ctime, 877 fileinfo->fi_size, 878 fileinfo->fi_alloc_size, 879 fileinfo->fi_dosattr, 880 namelen, 881 0L, 882 shortlen, 883 buf83, 884 fileinfo->fi_nodeid); 885 886 smb_msgbuf_term(&mb); 887 break; 888 889 case SMB_FIND_FILE_NAMES_INFO: 890 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lll", sr, 891 next_entry_offset, 892 resume_key, 893 namelen); 894 break; 895 896 default: 897 /* invalid info. level */ 898 return (-1); 899 } 900 901 /* 902 * At this point we have written all the fixed-size data 903 * for the specified info. level, and we're about to put 904 * the file name string in the message. We may later 905 * need the offset in the trans2 data where this string 906 * is placed, so save the message position now. Note: 907 * We also need to account for the alignment padding 908 * that may precede the unicode string. 909 */ 910 args->fa_lno = xa->rep_data_mb.chain_offset; 911 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0 && 912 (args->fa_lno & 1) != 0) 913 args->fa_lno++; 914 915 (void) smb_mbc_encodef(&xa->rep_data_mb, "%u", sr, 916 fileinfo->fi_name); 917 918 return (0); 919 } 920 921 /* 922 * Close a search started by a Trans2FindFirst2 request. 923 */ 924 smb_sdrc_t 925 smb_pre_find_close2(smb_request_t *sr) 926 { 927 DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr); 928 return (SDRC_SUCCESS); 929 } 930 931 void 932 smb_post_find_close2(smb_request_t *sr) 933 { 934 DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr); 935 } 936 937 smb_sdrc_t 938 smb_com_find_close2(smb_request_t *sr) 939 { 940 uint16_t odid; 941 smb_odir_t *od; 942 943 if (smbsr_decode_vwv(sr, "w", &odid) != 0) 944 return (SDRC_ERROR); 945 946 od = smb_tree_lookup_odir(sr, odid); 947 if (od == NULL) { 948 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 949 ERRDOS, ERROR_INVALID_HANDLE); 950 return (SDRC_ERROR); 951 } 952 953 smb_odir_close(od); 954 smb_odir_release(od); 955 956 if (smbsr_encode_empty_result(sr)) 957 return (SDRC_ERROR); 958 959 return (SDRC_SUCCESS); 960 } 961