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 2015 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_maxdata; 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_maxdata(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_maxdata = 324 smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); 325 if (args.fa_maxdata == 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_maxdata = 459 smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); 460 if (args.fa_maxdata == 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 boolean_t need_rewind = B_FALSE; 540 541 /* 542 * EAs are not current supported, so a search for level 543 * SMB_INFO_QUERY_EAS_FROM_LIST should always return an 544 * empty list. Returning zero for this case gives the 545 * client an empty response, which is better than an 546 * NT_STATUS_INVALID_LEVEL return (and test failures). 547 * 548 * If and when we do support EAs, this level will modify 549 * the search here, and then return results just like 550 * SMB_INFO_QUERY_EA_SIZE, but only including files 551 * that have an EA in the provided list. 552 */ 553 if (args->fa_infolev == SMB_INFO_QUERY_EAS_FROM_LIST) 554 return (0); 555 556 if ((maxcount = args->fa_maxcount) == 0) 557 maxcount = 1; 558 559 if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max)) 560 maxcount = smb_trans2_find_max; 561 562 count = 0; 563 while (count < maxcount) { 564 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos); 565 if (rc != 0 || args->fa_eos != 0) 566 break; 567 568 rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args); 569 if (rc == -1) 570 return (-1); /* fatal encoding error */ 571 if (rc == 1) { 572 need_rewind = B_TRUE; 573 break; /* output space exhausted */ 574 } 575 576 /* 577 * Save the info about the last file returned. 578 */ 579 args->fa_lastkey = fileinfo.fi_cookie; 580 bcopy(fileinfo.fi_name, args->fa_lastname, MAXNAMELEN); 581 582 ++count; 583 } 584 if (args->fa_eos != 0 && rc == ENOENT) 585 rc = 0; 586 587 /* save the last cookie returned to client */ 588 if (count != 0) 589 smb_odir_save_fname(od, args->fa_lastkey, args->fa_lastname); 590 591 /* 592 * If all retrieved entries have been successfully encoded 593 * and eos has not already been detected, check if there are 594 * any more entries. eos will be set if there are no more. 595 */ 596 if ((rc == 0) && (args->fa_eos == 0)) { 597 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos); 598 /* 599 * If rc == ENOENT, we did not read any additional data. 600 * if rc != 0, there's no need to rewind. 601 */ 602 if (rc == 0) 603 need_rewind = B_TRUE; 604 } 605 606 /* 607 * When the last entry we read from the directory did not 608 * fit in the return buffer, we will have read one entry 609 * that will not be returned in this call. That, and the 610 * check for EOS just above both can leave the directory 611 * position incorrect for the next call. Fix that now. 612 */ 613 if (need_rewind) { 614 bzero(&odir_resume, sizeof (odir_resume)); 615 odir_resume.or_type = SMB_ODIR_RESUME_COOKIE; 616 odir_resume.or_cookie = args->fa_lastkey; 617 smb_odir_resume_at(od, &odir_resume); 618 } 619 620 return (count); 621 } 622 623 /* 624 * smb_trans2_find_get_maxdata 625 * 626 * Calculate the minimum response space required for the specified 627 * information level. 628 * 629 * A non-zero return value provides the minimum space required. 630 * A return value of zero indicates an unknown information level. 631 */ 632 static int 633 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag) 634 { 635 int maxdata; 636 637 maxdata = smb_ascii_or_unicode_null_len(sr); 638 639 switch (infolev) { 640 case SMB_INFO_STANDARD : 641 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 642 maxdata += sizeof (int32_t); 643 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1; 644 break; 645 646 case SMB_INFO_QUERY_EA_SIZE: 647 case SMB_INFO_QUERY_EAS_FROM_LIST: 648 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 649 maxdata += sizeof (int32_t); 650 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1; 651 break; 652 653 case SMB_FIND_FILE_DIRECTORY_INFO: 654 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4; 655 break; 656 657 case SMB_FIND_FILE_FULL_DIRECTORY_INFO: 658 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4; 659 break; 660 661 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: 662 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8; 663 break; 664 665 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 666 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24; 667 break; 668 669 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: 670 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24 671 + 2 + 8; 672 break; 673 674 case SMB_FIND_FILE_NAMES_INFO: 675 maxdata += 4 + 4 + 4; 676 break; 677 678 case SMB_MAC_FIND_BOTH_HFS_INFO: 679 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 + 680 4 + 32 + 4 + 1 + 1 + 24 + 4; 681 break; 682 683 default: 684 maxdata = 0; 685 smbsr_error(sr, NT_STATUS_INVALID_LEVEL, 686 ERRDOS, ERROR_INVALID_LEVEL); 687 } 688 689 return (maxdata); 690 } 691 692 /* 693 * This is an experimental feature that allows us to return zero 694 * for all numeric resume keys, to match Windows behavior with an 695 * NTFS share. Setting this variable to zero does that. 696 * 697 * It's possible we could remove this variable and always set 698 * numeric resume keys to zero, but that would leave us unable 699 * to handle a FindNext call with an arbitrary start position. 700 * In practice we never see these, but in theory we could. 701 * 702 * See the long comment above smb_com_trans2_find_next2() for 703 * more details about resume key / resume name handling. 704 */ 705 int smbd_use_resume_keys = 1; 706 707 /* 708 * smb_trans2_mbc_encode 709 * 710 * This function encodes the mbc for one directory entry. 711 * 712 * The function returns -1 when the max data requested by client 713 * is reached. If the entry is valid and successful encoded, 0 714 * will be returned; otherwise, 1 will be returned. 715 * 716 * We always null terminate the filename. The space for the null 717 * is included in the maxdata calculation and is therefore included 718 * in the next_entry_offset. namelen is the unterminated length of 719 * the filename. For levels except STANDARD and EA_SIZE, if the 720 * filename is ascii the name length returned to the client should 721 * include the null terminator. Otherwise the length returned to 722 * the client should not include the terminator. 723 * 724 * Returns: 0 - data successfully encoded 725 * 1 - client request's maxdata limit reached 726 * -1 - error 727 */ 728 static int 729 smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa, 730 smb_fileinfo_t *fileinfo, smb_find_args_t *args) 731 { 732 int namelen, shortlen; 733 uint32_t next_entry_offset; 734 uint32_t dsize32, asize32; 735 uint32_t mb_flags = 0; 736 uint32_t resume_key; 737 char buf83[26]; 738 smb_msgbuf_t mb; 739 740 namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name); 741 if (namelen == -1) 742 return (-1); 743 744 /* 745 * If ascii the filename length returned to the client should 746 * include the null terminator for levels except STANDARD and 747 * EASIZE. 748 */ 749 if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) { 750 if ((args->fa_infolev != SMB_INFO_STANDARD) && 751 (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE)) 752 namelen += 1; 753 } 754 755 next_entry_offset = args->fa_maxdata + namelen; 756 757 if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0) 758 return (1); 759 760 mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0; 761 dsize32 = (fileinfo->fi_size > UINT_MAX) ? 762 UINT_MAX : (uint32_t)fileinfo->fi_size; 763 asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ? 764 UINT_MAX : (uint32_t)fileinfo->fi_alloc_size; 765 766 resume_key = fileinfo->fi_cookie; 767 if (smbd_use_resume_keys == 0) 768 resume_key = 0; 769 770 /* 771 * This switch handles all the "information levels" (formats) 772 * that we support. Note that all formats have the file name 773 * placed after some fixed-size data, and the code to write 774 * the file name is factored out at the end of this switch. 775 */ 776 switch (args->fa_infolev) { 777 case SMB_INFO_STANDARD: 778 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) 779 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 780 resume_key); 781 782 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwb", sr, 783 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), 784 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), 785 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), 786 dsize32, 787 asize32, 788 fileinfo->fi_dosattr, 789 namelen); 790 break; 791 792 case SMB_INFO_QUERY_EA_SIZE: 793 case SMB_INFO_QUERY_EAS_FROM_LIST: 794 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) 795 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 796 resume_key); 797 798 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb", sr, 799 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), 800 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), 801 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), 802 dsize32, 803 asize32, 804 fileinfo->fi_dosattr, 805 0L, /* EA Size */ 806 namelen); 807 break; 808 809 case SMB_FIND_FILE_DIRECTORY_INFO: 810 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqll", sr, 811 next_entry_offset, 812 resume_key, 813 &fileinfo->fi_crtime, 814 &fileinfo->fi_atime, 815 &fileinfo->fi_mtime, 816 &fileinfo->fi_ctime, 817 fileinfo->fi_size, 818 fileinfo->fi_alloc_size, 819 fileinfo->fi_dosattr, 820 namelen); 821 break; 822 823 case SMB_FIND_FILE_FULL_DIRECTORY_INFO: 824 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll", sr, 825 next_entry_offset, 826 resume_key, 827 &fileinfo->fi_crtime, 828 &fileinfo->fi_atime, 829 &fileinfo->fi_mtime, 830 &fileinfo->fi_ctime, 831 fileinfo->fi_size, 832 fileinfo->fi_alloc_size, 833 fileinfo->fi_dosattr, 834 namelen, 835 0L); 836 break; 837 838 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: 839 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.q", 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 fileinfo->fi_nodeid); 852 break; 853 854 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 855 bzero(buf83, sizeof (buf83)); 856 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), 857 mb_flags); 858 if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) { 859 smb_msgbuf_term(&mb); 860 return (-1); 861 } 862 shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname); 863 864 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24c", 865 sr, 866 next_entry_offset, 867 resume_key, 868 &fileinfo->fi_crtime, 869 &fileinfo->fi_atime, 870 &fileinfo->fi_mtime, 871 &fileinfo->fi_ctime, 872 fileinfo->fi_size, 873 fileinfo->fi_alloc_size, 874 fileinfo->fi_dosattr, 875 namelen, 876 0L, 877 shortlen, 878 buf83); 879 880 smb_msgbuf_term(&mb); 881 break; 882 883 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: 884 bzero(buf83, sizeof (buf83)); 885 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), 886 mb_flags); 887 if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) { 888 smb_msgbuf_term(&mb); 889 return (-1); 890 } 891 shortlen = smb_ascii_or_unicode_strlen(sr, 892 fileinfo->fi_shortname); 893 894 (void) smb_mbc_encodef(&xa->rep_data_mb, 895 "%llTTTTqqlllb.24c2.q", 896 sr, 897 next_entry_offset, 898 resume_key, 899 &fileinfo->fi_crtime, 900 &fileinfo->fi_atime, 901 &fileinfo->fi_mtime, 902 &fileinfo->fi_ctime, 903 fileinfo->fi_size, 904 fileinfo->fi_alloc_size, 905 fileinfo->fi_dosattr, 906 namelen, 907 0L, 908 shortlen, 909 buf83, 910 fileinfo->fi_nodeid); 911 912 smb_msgbuf_term(&mb); 913 break; 914 915 case SMB_FIND_FILE_NAMES_INFO: 916 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lll", sr, 917 next_entry_offset, 918 resume_key, 919 namelen); 920 break; 921 922 default: 923 /* invalid info. level */ 924 return (-1); 925 } 926 927 /* 928 * At this point we have written all the fixed-size data 929 * for the specified info. level, and we're about to put 930 * the file name string in the message. We may later 931 * need the offset in the trans2 data where this string 932 * is placed, so save the message position now. Note: 933 * We also need to account for the alignment padding 934 * that may precede the unicode string. 935 */ 936 args->fa_lno = xa->rep_data_mb.chain_offset; 937 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0 && 938 (args->fa_lno & 1) != 0) 939 args->fa_lno++; 940 941 (void) smb_mbc_encodef(&xa->rep_data_mb, "%u", sr, 942 fileinfo->fi_name); 943 944 return (0); 945 } 946 947 /* 948 * Close a search started by a Trans2FindFirst2 request. 949 */ 950 smb_sdrc_t 951 smb_pre_find_close2(smb_request_t *sr) 952 { 953 DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr); 954 return (SDRC_SUCCESS); 955 } 956 957 void 958 smb_post_find_close2(smb_request_t *sr) 959 { 960 DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr); 961 } 962 963 smb_sdrc_t 964 smb_com_find_close2(smb_request_t *sr) 965 { 966 uint16_t odid; 967 smb_odir_t *od; 968 969 if (smbsr_decode_vwv(sr, "w", &odid) != 0) 970 return (SDRC_ERROR); 971 972 od = smb_tree_lookup_odir(sr, odid); 973 if (od == NULL) { 974 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 975 ERRDOS, ERROR_INVALID_HANDLE); 976 return (SDRC_ERROR); 977 } 978 979 smb_odir_close(od); 980 smb_odir_release(od); 981 982 if (smbsr_encode_empty_result(sr)) 983 return (SDRC_ERROR); 984 985 return (SDRC_SUCCESS); 986 } 987