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