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