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 26 27 /* 28 * This module provides functions for TRANS2_FIND_FIRST2 and 29 * TRANS2_FIND_NEXT2 requests. The requests allow the client to search 30 * for the file(s) which match the file specification. The search is 31 * started with TRANS2_FIND_FIRST2 and can be continued if necessary with 32 * TRANS2_FIND_NEXT2. There are numerous levels of information which may be 33 * obtained for the returned files, the desired level is specified in the 34 * InformationLevel field of the requests. 35 * 36 * InformationLevel Name Value 37 * ================================= ================ 38 * 39 * SMB_INFO_STANDARD 1 40 * SMB_INFO_QUERY_EA_SIZE 2 41 * SMB_INFO_QUERY_EAS_FROM_LIST 3 42 * SMB_FIND_FILE_DIRECTORY_INFO 0x101 43 * SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 44 * SMB_FIND_FILE_NAMES_INFO 0x103 45 * SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104 46 * SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO 0x105 47 * SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO 0x106 48 * 49 * The following sections detail the data returned for each 50 * InformationLevel. The requested information is placed in the Data 51 * portion of the transaction response. Note: a client which does not 52 * support long names can only request SMB_INFO_STANDARD. 53 * 54 * A four-byte resume key precedes each data item (described below) if bit 55 * 2 in the Flags field is set, i.e. if the request indicates the server 56 * should return resume keys. Note: it is not always the case. If the 57 * data item already includes the resume key, the resume key should not be 58 * added again. 59 * 60 * 4.3.4.1 SMB_INFO_STANDARD 61 * 62 * Response Field Description 63 * ================================ ================================== 64 * 65 * SMB_DATE CreationDate; Date when file was created 66 * SMB_TIME CreationTime; Time when file was created 67 * SMB_DATE LastAccessDate; Date of last file access 68 * SMB_TIME LastAccessTime; Time of last file access 69 * SMB_DATE LastWriteDate; Date of last write to the file 70 * SMB_TIME LastWriteTime; Time of last write to the file 71 * ULONG DataSize; File Size 72 * ULONG AllocationSize; Size of filesystem allocation unit 73 * USHORT Attributes; File Attributes 74 * UCHAR FileNameLength; Length of filename in bytes 75 * STRING FileName; Name of found file 76 * 77 * 4.3.4.2 SMB_INFO_QUERY_EA_SIZE 78 * 79 * Response Field Description 80 * ================================= ================================== 81 * 82 * SMB_DATE CreationDate; Date when file was created 83 * SMB_TIME CreationTime; Time when file was created 84 * SMB_DATE LastAccessDate; Date of last file access 85 * SMB_TIME LastAccessTime; Time of last file access 86 * SMB_DATE LastWriteDate; Date of last write to the file 87 * SMB_TIME LastWriteTime; Time of last write to the file 88 * ULONG DataSize; File Size 89 * ULONG AllocationSize; Size of filesystem allocation unit 90 * USHORT Attributes; File Attributes 91 * ULONG EaSize; Size of file's EA information 92 * UCHAR FileNameLength; Length of filename in bytes 93 * STRING FileName; Name of found file 94 * 95 * 4.3.4.3 SMB_INFO_QUERY_EAS_FROM_LIST 96 * 97 * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but 98 * only for files which have an EA list which match the EA information in 99 * the Data part of the request. 100 * 101 * 4.3.4.4 SMB_FIND_FILE_DIRECTORY_INFO 102 * 103 * Response Field Description 104 * ================================= ================================== 105 * 106 * ULONG NextEntryOffset; Offset from this structure to 107 * beginning of next one 108 * ULONG FileIndex; 109 * LARGE_INTEGER CreationTime; file creation time 110 * LARGE_INTEGER LastAccessTime; last access time 111 * LARGE_INTEGER LastWriteTime; last write time 112 * LARGE_INTEGER ChangeTime; last attribute change time 113 * LARGE_INTEGER EndOfFile; file size 114 * LARGE_INTEGER AllocationSize; size of filesystem allocation information 115 * ULONG ExtFileAttributes; Extended file attributes 116 * (see section 3.11) 117 * ULONG FileNameLength; Length of filename in bytes 118 * STRING FileName; Name of the file 119 * 120 * 4.3.4.5 SMB_FIND_FILE_FULL_DIRECTORY_INFO 121 * 122 * Response Field Description 123 * ================================= ================================== 124 * 125 * ULONG NextEntryOffset; Offset from this structure to 126 * beginning of next one 127 * ULONG FileIndex; 128 * LARGE_INTEGER CreationTime; file creation time 129 * LARGE_INTEGER LastAccessTime; last access time 130 * LARGE_INTEGER LastWriteTime; last write time 131 * LARGE_INTEGER ChangeTime; last attribute change time 132 * LARGE_INTEGER EndOfFile; file size 133 * LARGE_INTEGER AllocationSize; size of filesystem allocation information 134 * ULONG ExtFileAttributes; Extended file attributes 135 * (see section 3.11) 136 * ULONG FileNameLength; Length of filename in bytes 137 * ULONG EaSize; Size of file's extended attributes 138 * STRING FileName; Name of the file 139 * 140 * 141 * SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO 142 * 143 * This is the same as SMB_FIND_FILE_FULL_DIRECTORY_INFO but with 144 * FileId inserted after EaSize. FileId is preceded by a 4 byte 145 * alignment padding. 146 * 147 * Response Field Description 148 * ================================= ================================== 149 * ... 150 * ULONG EaSize; Size of file's extended attributes 151 * UCHAR Reserved[4] 152 * LARGE_INTEGER FileId Internal file system unique id. 153 * STRING FileName; Name of the file 154 * 155 * 4.3.4.6 SMB_FIND_FILE_BOTH_DIRECTORY_INFO 156 * 157 * Response Field Description 158 * ================================= ================================== 159 * 160 * ULONG NextEntryOffset; Offset from this structure to 161 * beginning of next one 162 * ULONG FileIndex; 163 * LARGE_INTEGER CreationTime; file creation time 164 * LARGE_INTEGER LastAccessTime; last access time 165 * LARGE_INTEGER LastWriteTime; last write time 166 * LARGE_INTEGER ChangeTime; last attribute change time 167 * LARGE_INTEGER EndOfFile; file size 168 * LARGE_INTEGER AllocationSize; size of filesystem allocation information 169 * ULONG ExtFileAttributes; Extended file attributes 170 * (see section 3.11) 171 * ULONG FileNameLength; Length of FileName in bytes 172 * ULONG EaSize; Size of file's extended attributes 173 * UCHAR ShortNameLength; Length of file's short name in bytes 174 * UCHAR Reserved 175 * WCHAR ShortName[12]; File's 8.3 conformant name in Unicode 176 * STRING FileName; Files full length name 177 * 178 * 179 * SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO 180 * 181 * This is the same as SMB_FIND_FILE_BOTH_DIRECTORY_INFO but with 182 * FileId inserted after ShortName. FileId is preceded by a 2 byte 183 * alignment pad. 184 * 185 * Response Field Description 186 * ================================= ================================== 187 * ... 188 * WCHAR ShortName[12]; File's 8.3 conformant name in Unicode 189 * UCHAR Reserved[2] 190 * LARGE_INTEGER FileId Internal file system unique id. 191 * STRING FileName; Files full length name 192 * 193 * 4.3.4.7 SMB_FIND_FILE_NAMES_INFO 194 * 195 * Response Field Description 196 * ================================= ================================== 197 * 198 * ULONG NextEntryOffset; Offset from this structure to 199 * beginning of next one 200 * ULONG FileIndex; 201 * ULONG FileNameLength; Length of FileName in bytes 202 * STRING FileName; Files full length name 203 */ 204 205 #include <smbsrv/smb_kproto.h> 206 #include <smbsrv/msgbuf.h> 207 #include <smbsrv/smb_fsops.h> 208 209 typedef struct smb_find_args { 210 uint16_t fa_infolev; 211 uint16_t fa_maxcount; 212 uint16_t fa_fflag; 213 uint32_t fa_maxdata; 214 } smb_find_args_t; 215 216 static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *, 217 smb_odir_t *, smb_find_args_t *, boolean_t *); 218 static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t); 219 static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *, 220 smb_fileinfo_t *, smb_find_args_t *); 221 222 /* 223 * Tunable parameter to limit the maximum 224 * number of entries to be returned. 225 */ 226 uint16_t smb_trans2_find_max = 128; 227 228 /* 229 * smb_com_trans2_find_first2 230 * 231 * Client Request Value 232 * ============================ ================================== 233 * 234 * UCHAR WordCount 15 235 * UCHAR TotalDataCount Total size of extended attribute list 236 * UCHAR SetupCount 1 237 * UCHAR Setup[0] TRANS2_FIND_FIRST2 238 * 239 * Parameter Block Encoding Description 240 * ============================ ================================== 241 * USHORT SearchAttributes; 242 * USHORT SearchCount; Maximum number of entries to return 243 * USHORT Flags; Additional information: 244 * Bit 0 - close search after this request 245 * Bit 1 - close search if end of search 246 * reached 247 * Bit 2 - return resume keys for each 248 * entry found 249 * Bit 3 - continue search from previous 250 * ending place 251 * Bit 4 - find with backup intent 252 * USHORT InformationLevel; See below 253 * ULONG SearchStorageType; 254 * STRING FileName; Pattern for the search 255 * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is 256 * QUERY_EAS_FROM_LIST 257 * 258 * Response Parameter Block Description 259 * ============================ ================================== 260 * 261 * USHORT Sid; Search handle 262 * USHORT SearchCount; Number of entries returned 263 * USHORT EndOfSearch; Was last entry returned? 264 * USHORT EaErrorOffset; Offset into EA list if EA error 265 * USHORT LastNameOffset; Offset into data to file name of last 266 * entry, if server needs it to resume 267 * search; else 0 268 * UCHAR Data[ TotalDataCount ] Level dependent info about the matches 269 * found in the search 270 */ 271 smb_sdrc_t 272 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) 273 { 274 int count; 275 uint16_t sattr, odid; 276 smb_pathname_t *pn; 277 smb_odir_t *od; 278 smb_find_args_t args; 279 boolean_t eos; 280 uint32_t odir_flags = 0; 281 282 bzero(&args, sizeof (smb_find_args_t)); 283 284 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 285 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 286 ERRDOS, ERROR_ACCESS_DENIED); 287 return (SDRC_ERROR); 288 } 289 290 pn = &sr->arg.dirop.fqi.fq_path; 291 292 if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr, 293 &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev, 294 &pn->pn_path) != 0) { 295 return (SDRC_ERROR); 296 } 297 298 smb_pathname_init(sr, pn, pn->pn_path); 299 if (!smb_pathname_validate(sr, pn)) 300 return (-1); 301 302 if (smb_is_stream_name(pn->pn_path)) { 303 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 304 ERRDOS, ERROR_INVALID_NAME); 305 return (SDRC_ERROR); 306 } 307 308 if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) { 309 sr->user_cr = smb_user_getprivcred(sr->uid_user); 310 odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT; 311 } 312 313 args.fa_maxdata = 314 smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); 315 if (args.fa_maxdata == 0) 316 return (SDRC_ERROR); 317 318 odid = smb_odir_open(sr, pn->pn_path, sattr, odir_flags); 319 if (odid == 0) { 320 if (sr->smb_error.status == NT_STATUS_OBJECT_PATH_NOT_FOUND) { 321 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 322 ERRDOS, ERROR_FILE_NOT_FOUND); 323 } 324 return (SDRC_ERROR); 325 } 326 327 od = smb_tree_lookup_odir(sr->tid_tree, odid); 328 if (od == NULL) 329 return (SDRC_ERROR); 330 count = smb_trans2_find_entries(sr, xa, od, &args, &eos); 331 332 if (count == -1) { 333 smb_odir_close(od); 334 smb_odir_release(od); 335 return (SDRC_ERROR); 336 } 337 338 if (count == 0) { 339 smb_odir_close(od); 340 smb_odir_release(od); 341 smbsr_errno(sr, ENOENT); 342 return (SDRC_ERROR); 343 } 344 345 if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || 346 (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { 347 smb_odir_close(od); 348 } /* else leave odir open for trans2_find_next2 */ 349 350 smb_odir_release(od); 351 352 (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww", 353 odid, count, (eos) ? 1 : 0, 0, 0); 354 355 return (SDRC_SUCCESS); 356 } 357 358 /* 359 * smb_com_trans2_find_next2 360 * 361 * Client Request Value 362 * ================================== ================================= 363 * 364 * WordCount 15 365 * SetupCount 1 366 * Setup[0] TRANS2_FIND_NEXT2 367 * 368 * Parameter Block Encoding Description 369 * ================================== ================================= 370 * 371 * USHORT Sid; Search handle 372 * USHORT SearchCount; Maximum number of entries to 373 * return 374 * USHORT InformationLevel; Levels described in 375 * TRANS2_FIND_FIRST2 request 376 * ULONG ResumeKey; Value returned by previous find2 377 * call 378 * USHORT Flags; Additional information: bit set- 379 * 0 - close search after this 380 * request 381 * 1 - close search if end of search 382 * reached 383 * 2 - return resume keys for each 384 * entry found 385 * 3 - resume/continue from previous 386 * ending place 387 * 4 - find with backup intent 388 * STRING FileName; Resume file name 389 * 390 * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2 391 * call. If Bit3 of Flags is set, then FileName may be the NULL string, 392 * since the search is continued from the previous TRANS2_FIND request. 393 * Otherwise, FileName must not be more than 256 characters long. 394 * 395 * Response Field Description 396 * ================================== ================================= 397 * 398 * USHORT SearchCount; Number of entries returned 399 * USHORT EndOfSearch; Was last entry returned? 400 * USHORT EaErrorOffset; Offset into EA list if EA error 401 * USHORT LastNameOffset; Offset into data to file name of 402 * last entry, if server needs it to 403 * resume search; else 0 404 * UCHAR Data[TotalDataCount] Level dependent info about the 405 * matches found in the search 406 * 407 * 408 * The last parameter in the request is a filename, which is a 409 * null-terminated unicode string. 410 * 411 * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr, 412 * &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname) 413 * 414 * The filename parameter is not currently decoded because we 415 * expect a 2-byte null but Mac OS 10 clients send a 1-byte null, 416 * which leads to a decode error. 417 * Thus, we do not support resume by filename. We treat a request 418 * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST. 419 */ 420 smb_sdrc_t 421 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa) 422 { 423 int count; 424 uint16_t odid; 425 uint32_t cookie; 426 smb_odir_t *od; 427 smb_find_args_t args; 428 boolean_t eos; 429 smb_odir_resume_t odir_resume; 430 431 bzero(&args, sizeof (smb_find_args_t)); 432 433 if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr, &odid, 434 &args.fa_maxcount, &args.fa_infolev, &cookie, &args.fa_fflag) 435 != 0) { 436 return (SDRC_ERROR); 437 } 438 439 /* continuation by filename not supported */ 440 if ((args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) || (cookie == 0)) { 441 odir_resume.or_type = SMB_ODIR_RESUME_IDX; 442 odir_resume.or_idx = 0; 443 } else { 444 odir_resume.or_type = SMB_ODIR_RESUME_COOKIE; 445 odir_resume.or_cookie = cookie; 446 } 447 448 if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) 449 sr->user_cr = smb_user_getprivcred(sr->uid_user); 450 451 args.fa_maxdata = 452 smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); 453 if (args.fa_maxdata == 0) 454 return (SDRC_ERROR); 455 456 od = smb_tree_lookup_odir(sr->tid_tree, odid); 457 if (od == NULL) { 458 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 459 ERRDOS, ERROR_INVALID_HANDLE); 460 return (SDRC_ERROR); 461 } 462 smb_odir_resume_at(od, &odir_resume); 463 count = smb_trans2_find_entries(sr, xa, od, &args, &eos); 464 465 if (count == -1) { 466 smb_odir_close(od); 467 smb_odir_release(od); 468 return (SDRC_ERROR); 469 } 470 471 if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || 472 (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { 473 smb_odir_close(od); 474 } /* else leave odir open for trans2_find_next2 */ 475 476 smb_odir_release(od); 477 (void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", 478 count, (eos) ? 1 : 0, 0, 0); 479 480 return (SDRC_SUCCESS); 481 } 482 483 484 /* 485 * smb_trans2_find_entries 486 * 487 * Find and encode up to args->fa_maxcount directory entries. 488 * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1. 489 * 490 * Returns: 491 * count - count of entries encoded 492 * *eos = B_TRUE if no more directory entries 493 * -1 - error 494 */ 495 static int 496 smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od, 497 smb_find_args_t *args, boolean_t *eos) 498 { 499 int rc; 500 uint16_t count, maxcount; 501 uint32_t cookie; 502 smb_fileinfo_t fileinfo; 503 504 if ((maxcount = args->fa_maxcount) == 0) 505 maxcount = 1; 506 507 if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max)) 508 maxcount = smb_trans2_find_max; 509 510 count = 0; 511 while (count < maxcount) { 512 if (smb_odir_read_fileinfo(sr, od, &fileinfo, eos) != 0) 513 return (-1); 514 if (*eos == B_TRUE) 515 break; 516 517 rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args); 518 if (rc == -1) 519 return (-1); 520 if (rc == 1) 521 break; 522 523 cookie = fileinfo.fi_cookie; 524 ++count; 525 } 526 527 /* save the last cookie returned to client */ 528 if (count != 0) 529 smb_odir_save_cookie(od, 0, cookie); 530 531 /* 532 * If all retrieved entries have been successfully encoded 533 * and eos has not already been detected, check if there are 534 * any more entries. eos will be set if there are no more. 535 */ 536 if ((rc == 0) && (!*eos)) 537 (void) smb_odir_read_fileinfo(sr, od, &fileinfo, eos); 538 539 return (count); 540 } 541 542 /* 543 * smb_trans2_find_get_maxdata 544 * 545 * Calculate the minimum response space required for the specified 546 * information level. 547 * 548 * A non-zero return value provides the minimum space required. 549 * A return value of zero indicates an unknown information level. 550 */ 551 static int 552 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag) 553 { 554 int maxdata; 555 556 maxdata = smb_ascii_or_unicode_null_len(sr); 557 558 switch (infolev) { 559 case SMB_INFO_STANDARD : 560 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 561 maxdata += sizeof (int32_t); 562 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1; 563 break; 564 565 case SMB_INFO_QUERY_EA_SIZE: 566 if (fflag & SMB_FIND_RETURN_RESUME_KEYS) 567 maxdata += sizeof (int32_t); 568 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1; 569 break; 570 571 case SMB_FIND_FILE_DIRECTORY_INFO: 572 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4; 573 break; 574 575 case SMB_FIND_FILE_FULL_DIRECTORY_INFO: 576 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4; 577 break; 578 579 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: 580 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8; 581 break; 582 583 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 584 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24; 585 break; 586 587 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: 588 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24 589 + 2 + 8; 590 break; 591 592 case SMB_FIND_FILE_NAMES_INFO: 593 maxdata += 4 + 4 + 4; 594 break; 595 596 case SMB_MAC_FIND_BOTH_HFS_INFO: 597 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 + 598 4 + 32 + 4 + 1 + 1 + 24 + 4; 599 break; 600 601 default: 602 maxdata = 0; 603 smbsr_error(sr, NT_STATUS_INVALID_LEVEL, 604 ERRDOS, ERROR_INVALID_LEVEL); 605 } 606 607 return (maxdata); 608 } 609 610 /* 611 * smb_trans2_mbc_encode 612 * 613 * This function encodes the mbc for one directory entry. 614 * 615 * The function returns -1 when the max data requested by client 616 * is reached. If the entry is valid and successful encoded, 0 617 * will be returned; otherwise, 1 will be returned. 618 * 619 * We always null terminate the filename. The space for the null 620 * is included in the maxdata calculation and is therefore included 621 * in the next_entry_offset. namelen is the unterminated length of 622 * the filename. For levels except STANDARD and EA_SIZE, if the 623 * filename is ascii the name length returned to the client should 624 * include the null terminator. Otherwise the length returned to 625 * the client should not include the terminator. 626 * 627 * Returns: 0 - data successfully encoded 628 * 1 - client request's maxdata limit reached 629 * -1 - error 630 */ 631 static int 632 smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa, 633 smb_fileinfo_t *fileinfo, smb_find_args_t *args) 634 { 635 int namelen, shortlen, buflen; 636 uint32_t next_entry_offset; 637 uint32_t dsize32, asize32; 638 uint32_t mb_flags = 0; 639 char buf83[26]; 640 char *tmpbuf; 641 smb_msgbuf_t mb; 642 643 namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name); 644 if (namelen == -1) 645 return (-1); 646 647 next_entry_offset = args->fa_maxdata + namelen; 648 649 if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0) 650 return (1); 651 652 /* 653 * If ascii the filename length returned to the client should 654 * include the null terminator for levels except STANDARD and 655 * EASIZE. 656 */ 657 if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) { 658 if ((args->fa_infolev != SMB_INFO_STANDARD) && 659 (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE)) 660 namelen += 1; 661 } 662 663 mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0; 664 dsize32 = (fileinfo->fi_size > UINT_MAX) ? 665 UINT_MAX : (uint32_t)fileinfo->fi_size; 666 asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ? 667 UINT_MAX : (uint32_t)fileinfo->fi_alloc_size; 668 669 switch (args->fa_infolev) { 670 case SMB_INFO_STANDARD: 671 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) 672 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 673 fileinfo->fi_cookie); 674 675 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr, 676 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), 677 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), 678 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), 679 dsize32, 680 asize32, 681 fileinfo->fi_dosattr, 682 namelen, 683 fileinfo->fi_name); 684 break; 685 686 case SMB_INFO_QUERY_EA_SIZE: 687 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) 688 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 689 fileinfo->fi_cookie); 690 691 /* 692 * Unicode filename should NOT be aligned. Encode ('u') 693 * into a temporary buffer, then encode buffer as a 694 * byte stream ('#c'). 695 * Regardless of whether unicode or ascii, a single 696 * termination byte is used. 697 */ 698 buflen = namelen + sizeof (smb_wchar_t); 699 tmpbuf = kmem_zalloc(buflen, KM_SLEEP); 700 smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags); 701 if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_name) < 0) { 702 smb_msgbuf_term(&mb); 703 kmem_free(tmpbuf, buflen); 704 return (-1); 705 } 706 tmpbuf[namelen] = '\0'; 707 708 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr, 709 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), 710 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), 711 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), 712 dsize32, 713 asize32, 714 fileinfo->fi_dosattr, 715 0L, /* EA Size */ 716 namelen, 717 namelen + 1, 718 tmpbuf); 719 720 smb_msgbuf_term(&mb); 721 kmem_free(tmpbuf, buflen); 722 break; 723 724 case SMB_FIND_FILE_DIRECTORY_INFO: 725 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr, 726 next_entry_offset, 727 fileinfo->fi_cookie, 728 &fileinfo->fi_crtime, 729 &fileinfo->fi_atime, 730 &fileinfo->fi_mtime, 731 &fileinfo->fi_ctime, 732 fileinfo->fi_size, 733 fileinfo->fi_alloc_size, 734 fileinfo->fi_dosattr, 735 namelen, 736 fileinfo->fi_name); 737 break; 738 739 case SMB_FIND_FILE_FULL_DIRECTORY_INFO: 740 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr, 741 next_entry_offset, 742 fileinfo->fi_cookie, 743 &fileinfo->fi_crtime, 744 &fileinfo->fi_atime, 745 &fileinfo->fi_mtime, 746 &fileinfo->fi_ctime, 747 fileinfo->fi_size, 748 fileinfo->fi_alloc_size, 749 fileinfo->fi_dosattr, 750 namelen, 751 0L, 752 fileinfo->fi_name); 753 break; 754 755 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: 756 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr, 757 next_entry_offset, 758 fileinfo->fi_cookie, 759 &fileinfo->fi_crtime, 760 &fileinfo->fi_atime, 761 &fileinfo->fi_mtime, 762 &fileinfo->fi_ctime, 763 fileinfo->fi_size, 764 fileinfo->fi_alloc_size, 765 fileinfo->fi_dosattr, 766 namelen, 767 0L, 768 fileinfo->fi_nodeid, 769 fileinfo->fi_name); 770 break; 771 772 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: 773 bzero(buf83, sizeof (buf83)); 774 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), 775 mb_flags); 776 if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) { 777 smb_msgbuf_term(&mb); 778 return (-1); 779 } 780 shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname); 781 782 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu", 783 sr, 784 next_entry_offset, 785 fileinfo->fi_cookie, 786 &fileinfo->fi_crtime, 787 &fileinfo->fi_atime, 788 &fileinfo->fi_mtime, 789 &fileinfo->fi_ctime, 790 fileinfo->fi_size, 791 fileinfo->fi_alloc_size, 792 fileinfo->fi_dosattr, 793 namelen, 794 0L, 795 shortlen, 796 buf83, 797 fileinfo->fi_name); 798 799 smb_msgbuf_term(&mb); 800 break; 801 802 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: 803 bzero(buf83, sizeof (buf83)); 804 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), 805 mb_flags); 806 if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) { 807 smb_msgbuf_term(&mb); 808 return (-1); 809 } 810 shortlen = smb_ascii_or_unicode_strlen(sr, 811 fileinfo->fi_shortname); 812 813 (void) smb_mbc_encodef(&xa->rep_data_mb, 814 "%llTTTTqqlllb.24c2.qu", 815 sr, 816 next_entry_offset, 817 fileinfo->fi_cookie, 818 &fileinfo->fi_crtime, 819 &fileinfo->fi_atime, 820 &fileinfo->fi_mtime, 821 &fileinfo->fi_ctime, 822 fileinfo->fi_size, 823 fileinfo->fi_alloc_size, 824 fileinfo->fi_dosattr, 825 namelen, 826 0L, 827 shortlen, 828 buf83, 829 fileinfo->fi_nodeid, 830 fileinfo->fi_name); 831 832 smb_msgbuf_term(&mb); 833 break; 834 835 case SMB_FIND_FILE_NAMES_INFO: 836 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr, 837 next_entry_offset, 838 fileinfo->fi_cookie, 839 namelen, 840 fileinfo->fi_name); 841 break; 842 } 843 844 return (0); 845 } 846 847 /* 848 * Close a search started by a Trans2FindFirst2 request. 849 */ 850 smb_sdrc_t 851 smb_pre_find_close2(smb_request_t *sr) 852 { 853 DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr); 854 return (SDRC_SUCCESS); 855 } 856 857 void 858 smb_post_find_close2(smb_request_t *sr) 859 { 860 DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr); 861 } 862 863 smb_sdrc_t 864 smb_com_find_close2(smb_request_t *sr) 865 { 866 uint16_t odid; 867 smb_odir_t *od; 868 869 if (smbsr_decode_vwv(sr, "w", &odid) != 0) 870 return (SDRC_ERROR); 871 872 od = smb_tree_lookup_odir(sr->tid_tree, odid); 873 if (od == NULL) { 874 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 875 ERRDOS, ERROR_INVALID_HANDLE); 876 return (SDRC_ERROR); 877 } 878 879 smb_odir_close(od); 880 smb_odir_release(od); 881 882 if (smbsr_encode_empty_result(sr)) 883 return (SDRC_ERROR); 884 885 return (SDRC_SUCCESS); 886 } 887