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_status(sr, NT_STATUS_NO_SUCH_FILE, 348 ERRDOS, ERROR_FILE_NOT_FOUND); 349 return (SDRC_ERROR); 350 } 351 352 if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || 353 (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { 354 smb_odir_close(od); 355 } /* else leave odir open for trans2_find_next2 */ 356 357 (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww", 358 od->d_odid, /* Search ID */ 359 count, /* Search Count */ 360 args.fa_eos, /* End Of Search */ 361 0, /* EA Error Offset */ 362 args.fa_lno); /* Last Name Offset */ 363 364 smb_odir_release(od); 365 366 return (SDRC_SUCCESS); 367 } 368 369 /* 370 * smb_com_trans2_find_next2 371 * 372 * Client Request Value 373 * ================================== ================================= 374 * 375 * WordCount 15 376 * SetupCount 1 377 * Setup[0] TRANS2_FIND_NEXT2 378 * 379 * Parameter Block Encoding Description 380 * ================================== ================================= 381 * 382 * USHORT Sid; Search handle 383 * USHORT SearchCount; Maximum number of entries to 384 * return 385 * USHORT InformationLevel; Levels described in 386 * TRANS2_FIND_FIRST2 request 387 * ULONG ResumeKey; Value returned by previous find2 388 * call 389 * USHORT Flags; Additional information: bit set- 390 * 0 - close search after this 391 * request 392 * 1 - close search if end of search 393 * reached 394 * 2 - return resume keys for each 395 * entry found 396 * 3 - resume/continue from previous 397 * ending place 398 * 4 - find with backup intent 399 * STRING FileName; Resume file name 400 * 401 * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2 402 * call. If Bit3 of Flags is set, then FileName may be the NULL string, 403 * since the search is continued from the previous TRANS2_FIND request. 404 * Otherwise, FileName must not be more than 256 characters long. 405 * 406 * Response Field Description 407 * ================================== ================================= 408 * 409 * USHORT SearchCount; Number of entries returned 410 * USHORT EndOfSearch; Was last entry returned? 411 * USHORT EaErrorOffset; Offset into EA list if EA error 412 * USHORT LastNameOffset; Offset into data to file name of 413 * last entry, if server needs it to 414 * resume search; else 0 415 * UCHAR Data[TotalDataCount] Level dependent info about the 416 * matches found in the search 417 * 418 * 419 * The last parameter in the request is a filename, which is a 420 * null-terminated unicode string. 421 * 422 * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr, 423 * &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname) 424 * 425 * The filename parameter is not currently decoded because we 426 * expect a 2-byte null but Mac OS 10 clients send a 1-byte null, 427 * which leads to a decode error. 428 * Thus, we do not support resume by filename. We treat a request 429 * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST. 430 */ 431 smb_sdrc_t 432 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa) 433 { 434 int count; 435 uint16_t odid; 436 smb_odir_t *od; 437 smb_find_args_t args; 438 smb_odir_resume_t odir_resume; 439 440 bzero(&args, sizeof (args)); 441 bzero(&odir_resume, sizeof (odir_resume)); 442 443 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 444 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 445 ERRDOS, ERROR_ACCESS_DENIED); 446 return (SDRC_ERROR); 447 } 448 449 if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlwu", sr, 450 &odid, &args.fa_maxcount, &args.fa_infolev, 451 &odir_resume.or_cookie, &args.fa_fflag, 452 &odir_resume.or_fname) != 0) { 453 return (SDRC_ERROR); 454 } 455 456 if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) 457 sr->user_cr = smb_user_getprivcred(sr->uid_user); 458 459 args.fa_fixedsize = 460 smb_trans2_find_get_fixedsize(sr, args.fa_infolev, args.fa_fflag); 461 if (args.fa_fixedsize == 0) 462 return (SDRC_ERROR); 463 464 od = smb_tree_lookup_odir(sr, odid); 465 if (od == NULL) { 466 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 467 ERRDOS, ERROR_INVALID_HANDLE); 468 return (SDRC_ERROR); 469 } 470 471 /* 472 * Set the correct position in the directory. 473 * 474 * "Continue from last" is easy, but due to a history of 475 * buggy server implementations, most clients don't use 476 * that method. The most widely used (and reliable) is 477 * resume by file name. Unfortunately, that can't really 478 * be fully supported unless your file system stores all 479 * directory entries in some sorted order (like NTFS). 480 * We can partially support resume by name, where the only 481 * name we're ever asked to resume on is the same as the 482 * most recent we returned. That's always what the client 483 * gives us as the resume name, so we can simply remember 484 * the last name/offset pair and use that to position on 485 * the following FindNext call. In the unlikely event 486 * that the client asks to resume somewhere else, we'll 487 * use the numeric resume key, and hope the client gives 488 * correctly uses one of the resume keys we provided. 489 */ 490 if (args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) { 491 odir_resume.or_type = SMB_ODIR_RESUME_CONT; 492 } else { 493 odir_resume.or_type = SMB_ODIR_RESUME_FNAME; 494 } 495 smb_odir_resume_at(od, &odir_resume); 496 497 count = smb_trans2_find_entries(sr, xa, od, &args); 498 if (count == -1) { 499 smb_odir_close(od); 500 smb_odir_release(od); 501 return (SDRC_ERROR); 502 } 503 504 if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || 505 (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { 506 smb_odir_close(od); 507 } /* else leave odir open for trans2_find_next2 */ 508 509 smb_odir_release(od); 510 511 (void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", 512 count, /* Search Count */ 513 args.fa_eos, /* End Of Search */ 514 0, /* EA Error Offset */ 515 args.fa_lno); /* Last Name Offset */ 516 517 return (SDRC_SUCCESS); 518 } 519 520 521 /* 522 * smb_trans2_find_entries 523 * 524 * Find and encode up to args->fa_maxcount directory entries. 525 * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1. 526 * 527 * Returns: 528 * count - count of entries encoded 529 * *eos = B_TRUE if no more directory entries 530 * -1 - error 531 */ 532 static int 533 smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od, 534 smb_find_args_t *args) 535 { 536 smb_fileinfo_t fileinfo; 537 smb_odir_resume_t odir_resume; 538 uint16_t count, maxcount; 539 int rc = -1; 540 int LastEntryOffset = 0; 541 boolean_t need_rewind = B_FALSE; 542 543 /* 544 * EAs are not current supported, so a search for level 545 * SMB_INFO_QUERY_EAS_FROM_LIST should always return an 546 * empty list. Returning zero for this case gives the 547 * client an empty response, which is better than an 548 * NT_STATUS_INVALID_LEVEL return (and test failures). 549 * 550 * If and when we do support EAs, this level will modify 551 * the search here, and then return results just like 552 * SMB_INFO_QUERY_EA_SIZE, but only including files 553 * that have an EA in the provided list. 554 */ 555 if (args->fa_infolev == SMB_INFO_QUERY_EAS_FROM_LIST) 556 return (0); 557 558 if ((maxcount = args->fa_maxcount) == 0) 559 maxcount = 1; 560 561 if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max)) 562 maxcount = smb_trans2_find_max; 563 564 count = 0; 565 while (count < maxcount) { 566 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos); 567 if (rc != 0 || args->fa_eos != 0) 568 break; 569 570 LastEntryOffset = xa->rep_data_mb.chain_offset; 571 rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args); 572 if (rc == -1) 573 return (-1); /* fatal encoding error */ 574 if (rc == 1) { 575 need_rewind = B_TRUE; 576 break; /* output space exhausted */ 577 } 578 579 /* 580 * Save the info about the last file returned. 581 */ 582 args->fa_lastkey = fileinfo.fi_cookie; 583 bcopy(fileinfo.fi_name, args->fa_lastname, MAXNAMELEN); 584 585 ++count; 586 } 587 if (args->fa_eos != 0 && rc == ENOENT) 588 rc = 0; 589 590 /* 591 * All but the ancient info levels start with NextEntryOffset. 592 * That's supposed to be zero in the last entry returned. 593 */ 594 if (args->fa_infolev >= SMB_FIND_FILE_DIRECTORY_INFO) { 595 (void) smb_mbc_poke(&xa->rep_data_mb, 596 LastEntryOffset, "l", 0); 597 } 598 599 /* save the last cookie returned to client */ 600 if (count != 0) 601 smb_odir_save_fname(od, args->fa_lastkey, args->fa_lastname); 602 603 /* 604 * If all retrieved entries have been successfully encoded 605 * and eos has not already been detected, check if there are 606 * any more entries. eos will be set if there are no more. 607 */ 608 if ((rc == 0) && (args->fa_eos == 0)) { 609 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos); 610 /* 611 * If rc == ENOENT, we did not read any additional data. 612 * if rc != 0, there's no need to rewind. 613 */ 614 if (rc == 0) 615 need_rewind = B_TRUE; 616 } 617 618 /* 619 * When the last entry we read from the directory did not 620 * fit in the return buffer, we will have read one entry 621 * that will not be returned in this call. That, and the 622 * check for EOS just above both can leave the directory 623 * position incorrect for the next call. Fix that now. 624 */ 625 if (need_rewind) { 626 bzero(&odir_resume, sizeof (odir_resume)); 627 odir_resume.or_type = SMB_ODIR_RESUME_COOKIE; 628 odir_resume.or_cookie = args->fa_lastkey; 629 smb_odir_resume_at(od, &odir_resume); 630 } 631 632 return (count); 633 } 634 635 /* 636 * smb_trans2_find_get_fixedsize 637 * 638 * Calculate the sizeof the fixed part of the response for the 639 * specified information level. 640 * 641 * A non-zero return value provides the fixed size. 642 * A return value of zero indicates an unknown information level. 643 */ 644 static int 645 smb_trans2_find_get_fixedsize(smb_request_t *sr, uint16_t infolev, 646 uint16_t fflag) 647 { 648 int maxdata = 0; 649 650 switch (infolev) { 651 case SMB_INFO_STANDARD : 652 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 653 maxdata += sizeof (int32_t); 654 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1; 655 break; 656 657 case SMB_INFO_QUERY_EA_SIZE: 658 case SMB_INFO_QUERY_EAS_FROM_LIST: 659 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 660 maxdata += sizeof (int32_t); 661 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1; 662 break; 663 664 case SMB_FIND_FILE_DIRECTORY_INFO: 665 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4; 666 break; 667 668 case SMB_FIND_FILE_FULL_DIRECTORY_INFO: 669 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4; 670 break; 671 672 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: 673 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8; 674 break; 675 676 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 677 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24; 678 break; 679 680 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: 681 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24 682 + 2 + 8; 683 break; 684 685 case SMB_FIND_FILE_NAMES_INFO: 686 maxdata += 4 + 4 + 4; 687 break; 688 689 case SMB_MAC_FIND_BOTH_HFS_INFO: 690 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 + 691 4 + 32 + 4 + 1 + 1 + 24 + 4; 692 break; 693 694 default: 695 maxdata = 0; 696 smbsr_error(sr, NT_STATUS_INVALID_LEVEL, 697 ERRDOS, ERROR_INVALID_LEVEL); 698 } 699 700 return (maxdata); 701 } 702 703 /* 704 * This is an experimental feature that allows us to return zero 705 * for all numeric resume keys, to match Windows behavior with an 706 * NTFS share. Setting this variable to zero does that. 707 * 708 * It's possible we could remove this variable and always set 709 * numeric resume keys to zero, but that would leave us unable 710 * to handle a FindNext call with an arbitrary start position. 711 * In practice we never see these, but in theory we could. 712 * 713 * See the long comment above smb_com_trans2_find_next2() for 714 * more details about resume key / resume name handling. 715 */ 716 int smbd_use_resume_keys = 1; 717 718 /* 719 * smb_trans2_mbc_encode 720 * 721 * This function encodes the mbc for one directory entry. 722 * 723 * The function returns -1 when the max data requested by client 724 * is reached. If the entry is valid and successful encoded, 0 725 * will be returned; otherwise, 1 will be returned. 726 * 727 * We always null terminate the filename. The space for the null 728 * is included in the maxdata calculation and is therefore included 729 * in the next_entry_offset. namelen is the unterminated length of 730 * the filename. For levels except STANDARD and EA_SIZE, if the 731 * filename is ascii the name length returned to the client should 732 * include the null terminator. Otherwise the length returned to 733 * the client should not include the terminator. 734 * 735 * Returns: 0 - data successfully encoded 736 * 1 - client request's maxdata limit reached 737 * -1 - error 738 */ 739 static int 740 smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa, 741 smb_fileinfo_t *fileinfo, smb_find_args_t *args) 742 { 743 int namelen, shortlen; 744 uint32_t next_entry_offset; 745 uint32_t dsize32, asize32; 746 uint32_t mb_flags = 0; 747 uint32_t resume_key; 748 char buf83[26]; 749 smb_msgbuf_t mb; 750 int pad = 0; 751 752 namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name); 753 if (namelen == -1) 754 return (-1); 755 756 if (args->fa_infolev < SMB_FIND_FILE_DIRECTORY_INFO) { 757 /* 758 * Ancient info levels don't have a NextEntryOffset 759 * field, so there's no padding for alignment. 760 * The client expects a null after the file name, 761 * and then the next entry. The namelength field 762 * never includes the null for these old levels. 763 * Using the pad value to write the null because 764 * we don't want to add that to namelen. 765 * [MS-CIFS] sec. 2.8.1.{1-3} 766 */ 767 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0) 768 pad = 2; /* Unicode null */ 769 else 770 pad = 1; /* ascii null */ 771 next_entry_offset = args->fa_fixedsize + namelen + pad; 772 if (!MBC_ROOM_FOR(&xa->rep_data_mb, next_entry_offset)) 773 return (1); 774 } else { 775 /* 776 * Later info levels: The file name is written WITH 777 * null termination, and the size of that null _is_ 778 * included in the namelen field. There may also 779 * be padding, and we pad to align(4) like Windows. 780 * Don't include the padding in the "room for" test 781 * because we want to ignore any error writing the 782 * pad bytes after the last element. 783 */ 784 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0) 785 namelen += 2; 786 else 787 namelen += 1; 788 next_entry_offset = args->fa_fixedsize + namelen; 789 if (!MBC_ROOM_FOR(&xa->rep_data_mb, next_entry_offset)) 790 return (1); 791 if ((next_entry_offset & 3) != 0) { 792 pad = 4 - (next_entry_offset & 3); 793 next_entry_offset += pad; 794 } 795 } 796 797 mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0; 798 dsize32 = (fileinfo->fi_size > UINT_MAX) ? 799 UINT_MAX : (uint32_t)fileinfo->fi_size; 800 asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ? 801 UINT_MAX : (uint32_t)fileinfo->fi_alloc_size; 802 803 resume_key = fileinfo->fi_cookie; 804 if (smbd_use_resume_keys == 0) 805 resume_key = 0; 806 807 /* 808 * This switch handles all the "information levels" (formats) 809 * that we support. Note that all formats have the file name 810 * placed after some fixed-size data, and the code to write 811 * the file name is factored out at the end of this switch. 812 */ 813 switch (args->fa_infolev) { 814 case SMB_INFO_STANDARD: 815 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) 816 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 817 resume_key); 818 819 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwb", sr, 820 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), 821 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), 822 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), 823 dsize32, 824 asize32, 825 fileinfo->fi_dosattr, 826 namelen); 827 break; 828 829 case SMB_INFO_QUERY_EA_SIZE: 830 case SMB_INFO_QUERY_EAS_FROM_LIST: 831 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) 832 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 833 resume_key); 834 835 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb", sr, 836 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), 837 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), 838 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), 839 dsize32, 840 asize32, 841 fileinfo->fi_dosattr, 842 0L, /* EA Size */ 843 namelen); 844 break; 845 846 case SMB_FIND_FILE_DIRECTORY_INFO: 847 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqll", sr, 848 next_entry_offset, 849 resume_key, 850 &fileinfo->fi_crtime, 851 &fileinfo->fi_atime, 852 &fileinfo->fi_mtime, 853 &fileinfo->fi_ctime, 854 fileinfo->fi_size, 855 fileinfo->fi_alloc_size, 856 fileinfo->fi_dosattr, 857 namelen); 858 break; 859 860 case SMB_FIND_FILE_FULL_DIRECTORY_INFO: 861 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll", sr, 862 next_entry_offset, 863 resume_key, 864 &fileinfo->fi_crtime, 865 &fileinfo->fi_atime, 866 &fileinfo->fi_mtime, 867 &fileinfo->fi_ctime, 868 fileinfo->fi_size, 869 fileinfo->fi_alloc_size, 870 fileinfo->fi_dosattr, 871 namelen, 872 0L); 873 break; 874 875 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: 876 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.q", sr, 877 next_entry_offset, 878 resume_key, 879 &fileinfo->fi_crtime, 880 &fileinfo->fi_atime, 881 &fileinfo->fi_mtime, 882 &fileinfo->fi_ctime, 883 fileinfo->fi_size, 884 fileinfo->fi_alloc_size, 885 fileinfo->fi_dosattr, 886 namelen, 887 0L, 888 fileinfo->fi_nodeid); 889 break; 890 891 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 892 bzero(buf83, sizeof (buf83)); 893 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), 894 mb_flags); 895 if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) { 896 smb_msgbuf_term(&mb); 897 return (-1); 898 } 899 shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname); 900 901 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24c", 902 sr, 903 next_entry_offset, 904 resume_key, 905 &fileinfo->fi_crtime, 906 &fileinfo->fi_atime, 907 &fileinfo->fi_mtime, 908 &fileinfo->fi_ctime, 909 fileinfo->fi_size, 910 fileinfo->fi_alloc_size, 911 fileinfo->fi_dosattr, 912 namelen, 913 0L, 914 shortlen, 915 buf83); 916 917 smb_msgbuf_term(&mb); 918 break; 919 920 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: 921 bzero(buf83, sizeof (buf83)); 922 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), 923 mb_flags); 924 if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) { 925 smb_msgbuf_term(&mb); 926 return (-1); 927 } 928 shortlen = smb_ascii_or_unicode_strlen(sr, 929 fileinfo->fi_shortname); 930 931 (void) smb_mbc_encodef(&xa->rep_data_mb, 932 "%llTTTTqqlllb.24c2.q", 933 sr, 934 next_entry_offset, 935 resume_key, 936 &fileinfo->fi_crtime, 937 &fileinfo->fi_atime, 938 &fileinfo->fi_mtime, 939 &fileinfo->fi_ctime, 940 fileinfo->fi_size, 941 fileinfo->fi_alloc_size, 942 fileinfo->fi_dosattr, 943 namelen, 944 0L, 945 shortlen, 946 buf83, 947 fileinfo->fi_nodeid); 948 949 smb_msgbuf_term(&mb); 950 break; 951 952 case SMB_FIND_FILE_NAMES_INFO: 953 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lll", sr, 954 next_entry_offset, 955 resume_key, 956 namelen); 957 break; 958 959 default: 960 /* invalid info. level */ 961 return (-1); 962 } 963 964 /* 965 * At this point we have written all the fixed-size data 966 * for the specified info. level, and we're about to put 967 * the file name string in the message. We may later 968 * need the offset in the trans2 data where this string 969 * is placed, so save the message position now. Note: 970 * We also need to account for the alignment padding 971 * that may precede the unicode string. 972 */ 973 args->fa_lno = xa->rep_data_mb.chain_offset; 974 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0 && 975 (args->fa_lno & 1) != 0) 976 args->fa_lno++; 977 978 (void) smb_mbc_encodef(&xa->rep_data_mb, "%#u", sr, 979 namelen, fileinfo->fi_name); 980 981 if (pad) 982 (void) smb_mbc_encodef(&xa->rep_data_mb, "#.", pad); 983 984 return (0); 985 } 986 987 /* 988 * Close a search started by a Trans2FindFirst2 request. 989 */ 990 smb_sdrc_t 991 smb_pre_find_close2(smb_request_t *sr) 992 { 993 DTRACE_SMB_START(op__FindClose2, smb_request_t *, sr); 994 return (SDRC_SUCCESS); 995 } 996 997 void 998 smb_post_find_close2(smb_request_t *sr) 999 { 1000 DTRACE_SMB_DONE(op__FindClose2, smb_request_t *, sr); 1001 } 1002 1003 smb_sdrc_t 1004 smb_com_find_close2(smb_request_t *sr) 1005 { 1006 uint16_t odid; 1007 smb_odir_t *od; 1008 1009 if (smbsr_decode_vwv(sr, "w", &odid) != 0) 1010 return (SDRC_ERROR); 1011 1012 od = smb_tree_lookup_odir(sr, odid); 1013 if (od == NULL) { 1014 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 1015 ERRDOS, ERROR_INVALID_HANDLE); 1016 return (SDRC_ERROR); 1017 } 1018 1019 smb_odir_close(od); 1020 smb_odir_release(od); 1021 1022 if (smbsr_encode_empty_result(sr)) 1023 return (SDRC_ERROR); 1024 1025 return (SDRC_SUCCESS); 1026 } 1027