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