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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 #include <smbsrv/smb_kproto.h> 27 28 /* 29 * smb_com_search 30 * smb_com_find, smb_com_find_close 31 * smb_find_unique 32 * 33 * These commands are used for directory searching. They share the same 34 * message formats, defined below: 35 * 36 * Client Request Description 37 * ---------------------------------- --------------------------------- 38 * 39 * UCHAR WordCount; Count of parameter words = 2 40 * USHORT MaxCount; Number of dir. entries to return 41 * USHORT SearchAttributes; 42 * USHORT ByteCount; Count of data bytes; min = 5 43 * UCHAR BufferFormat1; 0x04 -- ASCII 44 * UCHAR FileName[]; File name, may be null 45 * UCHAR BufferFormat2; 0x05 -- Variable block 46 * USHORT ResumeKeyLength; Length of resume key, may be 0 47 * UCHAR ResumeKey[]; Resume key 48 * 49 * FileName specifies the file to be sought. SearchAttributes indicates 50 * the attributes that the file must have. If SearchAttributes is 51 * zero then only normal files are returned. If the system file, hidden or 52 * directory attributes are specified then the search is inclusive - both the 53 * specified type(s) of files and normal files are returned. If the volume 54 * label attribute is specified then the search is exclusive, and only the 55 * volume label entry is returned. 56 * 57 * MaxCount specifies the number of directory entries to be returned. 58 * 59 * Server Response Description 60 * ---------------------------------- --------------------------------- 61 * 62 * UCHAR WordCount; Count of parameter words = 1 63 * USHORT Count; Number of entries returned 64 * USHORT ByteCount; Count of data bytes; min = 3 65 * UCHAR BufferFormat; 0x05 -- Variable block 66 * USHORT DataLength; Length of data 67 * UCHAR DirectoryInformationData[]; Data 68 * 69 * The response will contain one or more directory entries as determined by 70 * the Count field. No more than MaxCount entries will be returned. Only 71 * entries that match the sought FileName and SearchAttributes combination 72 * will be returned. 73 * 74 * ResumeKey must be null (length = 0) on the initial search request. 75 * Subsequent search requests intended to continue a search must contain 76 * the ResumeKey field extracted from the last directory entry of the 77 * previous response. ResumeKey is self-contained, for calls containing 78 * a non-zero ResumeKey neither the SearchAttributes or FileName fields 79 * will be valid in the request. ResumeKey has the following format: 80 * 81 * Resume Key Field Description 82 * ---------------------------------- --------------------------------- 83 * 84 * UCHAR Reserved; bit 7 - consumer use 85 * bits 5,6 - system use (must preserve) 86 * bits 0-4 - server use (must preserve) 87 * UCHAR FileName[11]; Name of the returned file 88 * UCHAR ReservedForServer[5]; Client must not modify 89 * byte 0 - uniquely identifies find 90 * through find_close 91 * bytes 1-4 - available for server use 92 * (must be non-zero) 93 * UCHAR ReservedForConsumer[4]; Server must not modify 94 * 95 * FileName is 8.3 format, with the three character extension left 96 * justified into FileName[9-11]. 97 * 98 * There may be multiple matching entries in response to a single request 99 * as wildcards are supported in the last component of FileName of the 100 * initial request. 101 * 102 * Returned directory entries in the DirectoryInformationData field of the 103 * response each have the following format: 104 * 105 * Directory Information Field Description 106 * ---------------------------------- --------------------------------- 107 * 108 * SMB_RESUME_KEY ResumeKey; Described above 109 * UCHAR FileAttributes; Attributes of the found file 110 * SMB_TIME LastWriteTime; Time file was last written 111 * SMB_DATE LastWriteDate; Date file was last written 112 * ULONG FileSize; Size of the file 113 * UCHAR FileName[13]; ASCII, space-filled null terminated 114 * 115 * FileName must conform to 8.3 rules, and is padded after the extension 116 * with 0x20 characters if necessary. 117 * 118 * As can be seen from the above structure, these commands cannot return 119 * long filenames, and cannot return UNICODE filenames. 120 * 121 * Files which have a size greater than 2^32 bytes should have the least 122 * significant 32 bits of their size returned in FileSize. 123 * 124 * smb_com_search 125 * -------------- 126 * 127 * If the client is prior to the LANMAN1.0 dialect, the returned FileName 128 * should be uppercased. 129 * If the client has negotiated a dialect prior to the LANMAN1.0 dialect, 130 * or if bit0 of the Flags2 SMB header field of the request is clear, 131 * the returned FileName should be uppercased. 132 * 133 * SMB_COM_SEARCH terminates when either the requested maximum number of 134 * entries that match the named file are found, or the end of directory is 135 * reached without the maximum number of matches being found. A response 136 * containing no entries indicates that no matching entries were found 137 * between the starting point of the search and the end of directory. 138 * 139 * 140 * The find, find_close and find_unique protocols may be used in place of 141 * the core "search" protocol when LANMAN 1.0 dialect has been negotiated. 142 * 143 * smb_com_find 144 * ------------ 145 * 146 * The find protocol is used to match the find OS/2 system call. 147 * 148 * The format of the find protocol is the same as the core "search" protocol. 149 * The difference is that the directory is logically Opened with a find protocol 150 * and logically closed with the find close protocol. 151 * As is true of a failing open, if a find request (find "first" request where 152 * resume_key is null) fails (no entries are found), no find close protocol is 153 * expected. 154 * 155 * If no global characters are present, a "find unique" protocol should be used 156 * (only one entry is expected and find close need not be sent). 157 * 158 * A find request will terminate when either the requested maximum number of 159 * entries that match the named file are found, or the end of directory is 160 * reached without the maximum number of matches being found. A response 161 * containing no entries indicates that no matching entries were found between 162 * the starting point of the search and the end of directory. 163 * 164 * If a find requests more data than can be placed in a message of the 165 * max-xmit-size for the TID specified, the server will return only the number 166 * of entries which will fit. 167 * 168 * 169 * smb_com_find_close 170 * ------------------ 171 * 172 * The find close protocol is used to match the find close OS/2 system call. 173 * 174 * Whereas the first find protocol logically opens the directory, subsequent 175 * find protocols presenting a resume_key further "read" the directory, the 176 * find close protocol "closes" the directory allowing the server to free any 177 * resources held in support of the directory search. 178 * 179 * In our implementation this translates to closing the odir. 180 * 181 * 182 * smb_com_find_unique 183 * ------------------- 184 * 185 * The format of the find unique protocol is the same as the core "search" 186 * protocol. The difference is that the directory is logically opened, any 187 * matching entries returned, and then the directory is logically closed. 188 * 189 * The resume search key key will be returned as in the find protocol and 190 * search protocol however it may NOT be returned to continue the search. 191 * Only one buffer of entries is expected and find close need not be sent. 192 * 193 * If a find unique requests more data than can be placed in a message of the 194 * max-xmit-size for the TID specified, the server will abort the virtual 195 * circuit to the consumer. 196 */ 197 198 #define SMB_NAME83_BUFLEN 12 199 static void smb_name83(const char *, char *, size_t); 200 201 /* *** smb_com_search *** */ 202 203 smb_sdrc_t 204 smb_pre_search(smb_request_t *sr) 205 { 206 DTRACE_SMB_START(op__Search, smb_request_t *, sr); 207 return (SDRC_SUCCESS); 208 } 209 210 void 211 smb_post_search(smb_request_t *sr) 212 { 213 DTRACE_SMB_DONE(op__Search, smb_request_t *, sr); 214 } 215 216 smb_sdrc_t 217 smb_com_search(smb_request_t *sr) 218 { 219 int rc; 220 uint16_t count, maxcount, index; 221 uint16_t sattr, odid; 222 uint16_t key_len; 223 uint32_t client_key; 224 char name[SMB_SHORTNAMELEN]; 225 char name83[SMB_SHORTNAMELEN]; 226 smb_pathname_t *pn; 227 unsigned char resume_char; 228 unsigned char type; 229 boolean_t find_first, to_upper; 230 smb_tree_t *tree; 231 smb_odir_t *od; 232 smb_fileinfo_t fileinfo; 233 smb_odir_resume_t odir_resume; 234 uint32_t status; 235 uint16_t eos; 236 237 to_upper = B_FALSE; 238 if ((sr->session->dialect <= LANMAN1_0) || 239 ((sr->smb_flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES) == 0)) { 240 to_upper = B_TRUE; 241 } 242 243 /* We only handle 8.3 name here */ 244 sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES; 245 sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE; 246 247 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 248 return (SDRC_ERROR); 249 250 pn = &sr->arg.dirop.fqi.fq_path; 251 rc = smbsr_decode_data(sr, "%Abw", sr, &pn->pn_path, &type, &key_len); 252 if ((rc != 0) || (type != 0x05)) 253 return (SDRC_ERROR); 254 255 smb_pathname_init(sr, pn, pn->pn_path); 256 if (!smb_pathname_validate(sr, pn) || 257 smb_is_stream_name(pn->pn_path)) { 258 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 259 ERRDOS, ERROR_NO_MORE_FILES); 260 return (SDRC_ERROR); 261 } 262 263 tree = sr->tid_tree; 264 265 /* Volume information only */ 266 if ((sattr == FILE_ATTRIBUTE_VOLUME) && (key_len != 21)) { 267 (void) memset(name, ' ', sizeof (name)); 268 (void) strncpy(name, tree->t_volume, sizeof (name)); 269 270 if (key_len >= 21) { 271 (void) smb_mbc_decodef(&sr->smb_data, "17.l", 272 &client_key); 273 } else { 274 client_key = 0; 275 } 276 277 (void) smb_mbc_encodef(&sr->reply, "bwwbwb11c5.lb8.13c", 278 1, 0, VAR_BCC, 5, 0, 0, pn->pn_path+1, 279 client_key, sattr, name); 280 281 rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8; 282 (void) smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 283 1, 1, rc+3, 5, rc); 284 285 return (SDRC_SUCCESS); 286 } 287 288 if ((key_len != 0) && (key_len != 21)) 289 return (SDRC_ERROR); 290 291 find_first = (key_len == 0); 292 resume_char = 0; 293 client_key = 0; 294 295 if (find_first) { 296 status = smb_odir_openpath(sr, pn->pn_path, sattr, 0, &od); 297 if (status != 0) { 298 if (status == NT_STATUS_ACCESS_DENIED) 299 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 300 ERRDOS, ERROR_NO_MORE_FILES); 301 return (SDRC_ERROR); 302 } 303 odid = od->d_odid; 304 } else { 305 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 306 &resume_char, &index, &odid, &client_key) != 0) { 307 return (SDRC_ERROR); 308 } 309 od = smb_tree_lookup_odir(sr, odid); 310 } 311 312 if (od == NULL) { 313 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 314 ERRDOS, ERROR_INVALID_HANDLE); 315 return (SDRC_ERROR); 316 } 317 318 if (!find_first) { 319 if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) { 320 od->d_eof = B_TRUE; 321 } else { 322 odir_resume.or_type = SMB_ODIR_RESUME_IDX; 323 odir_resume.or_idx = index; 324 smb_odir_resume_at(od, &odir_resume); 325 } 326 } 327 328 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 329 330 rc = 0; 331 index = 0; 332 count = 0; 333 if (maxcount > SMB_MAX_SEARCH) 334 maxcount = SMB_MAX_SEARCH; 335 336 while (count < maxcount) { 337 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); 338 if (rc != 0 || eos != 0) 339 break; 340 341 if (*fileinfo.fi_shortname == '\0') { 342 if (smb_needs_mangled(fileinfo.fi_name)) 343 continue; 344 (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, 345 SMB_SHORTNAMELEN - 1); 346 if (to_upper) 347 (void) smb_strupr(fileinfo.fi_shortname); 348 } 349 smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN); 350 351 (void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c", 352 resume_char, name83, index, odid, client_key, 353 fileinfo.fi_dosattr & 0xff, 354 smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec), 355 (int32_t)fileinfo.fi_size, 356 fileinfo.fi_shortname); 357 358 smb_odir_save_cookie(od, index, fileinfo.fi_cookie); 359 360 count++; 361 index++; 362 } 363 if (eos && rc == ENOENT) 364 rc = 0; 365 366 if (rc != 0) { 367 smb_odir_close(od); 368 smb_odir_release(od); 369 return (SDRC_ERROR); 370 } 371 372 if (count == 0 && find_first) { 373 smb_odir_close(od); 374 smb_odir_release(od); 375 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 376 ERRDOS, ERROR_NO_MORE_FILES); 377 return (SDRC_ERROR); 378 } 379 380 rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8; 381 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 382 1, count, rc+3, 5, rc) < 0) { 383 smb_odir_close(od); 384 smb_odir_release(od); 385 return (SDRC_ERROR); 386 } 387 388 smb_odir_release(od); 389 return (SDRC_SUCCESS); 390 } 391 392 393 /* *** smb_com_find *** */ 394 395 smb_sdrc_t 396 smb_pre_find(smb_request_t *sr) 397 { 398 DTRACE_SMB_START(op__Find, smb_request_t *, sr); 399 return (SDRC_SUCCESS); 400 } 401 402 void 403 smb_post_find(smb_request_t *sr) 404 { 405 DTRACE_SMB_DONE(op__Find, smb_request_t *, sr); 406 } 407 408 smb_sdrc_t 409 smb_com_find(smb_request_t *sr) 410 { 411 int rc; 412 uint16_t count, maxcount, index; 413 uint16_t sattr, odid; 414 uint16_t key_len; 415 uint32_t client_key; 416 char name83[SMB_SHORTNAMELEN]; 417 smb_odir_t *od; 418 smb_fileinfo_t fileinfo; 419 uint32_t status; 420 uint16_t eos; 421 422 smb_pathname_t *pn; 423 unsigned char resume_char; 424 unsigned char type; 425 boolean_t find_first = B_TRUE; 426 smb_odir_resume_t odir_resume; 427 428 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 429 return (SDRC_ERROR); 430 431 pn = &sr->arg.dirop.fqi.fq_path; 432 rc = smbsr_decode_data(sr, "%Abw", sr, &pn->pn_path, &type, &key_len); 433 if ((rc != 0) || (type != 0x05)) 434 return (SDRC_ERROR); 435 436 if ((key_len != 0) && (key_len != 21)) 437 return (SDRC_ERROR); 438 439 smb_pathname_init(sr, pn, pn->pn_path); 440 if (!smb_pathname_validate(sr, pn)) 441 return (SDRC_ERROR); 442 443 if (smb_is_stream_name(pn->pn_path)) { 444 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 445 ERRDOS, ERROR_INVALID_NAME); 446 return (SDRC_ERROR); 447 } 448 449 find_first = (key_len == 0); 450 resume_char = 0; 451 client_key = 0; 452 453 if (find_first) { 454 status = smb_odir_openpath(sr, pn->pn_path, sattr, 0, &od); 455 if (status != 0) { 456 smbsr_error(sr, status, 0, 0); 457 return (SDRC_ERROR); 458 } 459 odid = od->d_odid; 460 } else { 461 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 462 &resume_char, &index, &odid, &client_key) != 0) { 463 return (SDRC_ERROR); 464 } 465 od = smb_tree_lookup_odir(sr, odid); 466 } 467 468 if (od == NULL) { 469 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 470 ERRDOS, ERROR_INVALID_HANDLE); 471 return (SDRC_ERROR); 472 } 473 474 if (!find_first) { 475 if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) { 476 od->d_eof = B_TRUE; 477 } else { 478 odir_resume.or_type = SMB_ODIR_RESUME_IDX; 479 odir_resume.or_idx = index; 480 smb_odir_resume_at(od, &odir_resume); 481 } 482 } 483 484 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 485 486 rc = 0; 487 index = 0; 488 count = 0; 489 if (maxcount > SMB_MAX_SEARCH) 490 maxcount = SMB_MAX_SEARCH; 491 492 while (count < maxcount) { 493 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); 494 if (rc != 0 || eos != 0) 495 break; 496 497 if (*fileinfo.fi_shortname == '\0') { 498 if (smb_needs_mangled(fileinfo.fi_name)) 499 continue; 500 (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, 501 SMB_SHORTNAMELEN - 1); 502 } 503 smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN); 504 505 (void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c", 506 resume_char, name83, index, odid, client_key, 507 fileinfo.fi_dosattr & 0xff, 508 smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec), 509 (int32_t)fileinfo.fi_size, 510 fileinfo.fi_shortname); 511 512 smb_odir_save_cookie(od, index, fileinfo.fi_cookie); 513 514 count++; 515 index++; 516 } 517 if (eos && rc == ENOENT) 518 rc = 0; 519 520 if (rc != 0) { 521 smb_odir_close(od); 522 smb_odir_release(od); 523 return (SDRC_ERROR); 524 } 525 526 if (count == 0 && find_first) { 527 smb_odir_close(od); 528 smb_odir_release(od); 529 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 530 ERRDOS, ERROR_NO_MORE_FILES); 531 return (SDRC_ERROR); 532 } 533 534 rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; 535 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 536 1, count, rc+3, 5, rc) < 0) { 537 smb_odir_close(od); 538 smb_odir_release(od); 539 return (SDRC_ERROR); 540 } 541 542 smb_odir_release(od); 543 return (SDRC_SUCCESS); 544 } 545 546 547 /* *** smb_com_find_close *** */ 548 549 smb_sdrc_t 550 smb_pre_find_close(smb_request_t *sr) 551 { 552 DTRACE_SMB_START(op__FindClose, smb_request_t *, sr); 553 return (SDRC_SUCCESS); 554 } 555 556 void 557 smb_post_find_close(smb_request_t *sr) 558 { 559 DTRACE_SMB_DONE(op__FindClose, smb_request_t *, sr); 560 } 561 562 smb_sdrc_t 563 smb_com_find_close(smb_request_t *sr) 564 { 565 int rc; 566 uint16_t maxcount, index; 567 uint16_t sattr, odid; 568 uint16_t key_len; 569 uint32_t client_key; 570 char *path; 571 unsigned char resume_char; 572 unsigned char type; 573 smb_odir_t *od; 574 575 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 576 return (SDRC_ERROR); 577 578 rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len); 579 if ((rc != 0) || (type != 0x05)) 580 return (SDRC_ERROR); 581 582 if (key_len == 0) { 583 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 584 ERRDOS, ERROR_INVALID_HANDLE); 585 return (SDRC_ERROR); 586 } else if (key_len != 21) { 587 return (SDRC_ERROR); 588 } 589 590 odid = 0; 591 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 592 &resume_char, &index, &odid, &client_key) != 0) { 593 return (SDRC_ERROR); 594 } 595 596 od = smb_tree_lookup_odir(sr, odid); 597 if (od == NULL) { 598 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 599 ERRDOS, ERROR_INVALID_HANDLE); 600 return (SDRC_ERROR); 601 } 602 603 smb_odir_close(od); 604 smb_odir_release(od); 605 606 if (smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0)) 607 return (SDRC_ERROR); 608 609 return (SDRC_SUCCESS); 610 } 611 612 613 /* *** smb_com_find_unique *** */ 614 615 smb_sdrc_t 616 smb_pre_find_unique(smb_request_t *sr) 617 { 618 DTRACE_SMB_START(op__FindUnique, smb_request_t *, sr); 619 return (SDRC_SUCCESS); 620 } 621 622 void 623 smb_post_find_unique(smb_request_t *sr) 624 { 625 DTRACE_SMB_DONE(op__FindUnique, smb_request_t *, sr); 626 } 627 628 smb_sdrc_t 629 smb_com_find_unique(struct smb_request *sr) 630 { 631 int rc; 632 uint16_t count, maxcount, index; 633 uint16_t sattr; 634 smb_pathname_t *pn; 635 unsigned char resume_char = '\0'; 636 uint32_t client_key = 0; 637 char name83[SMB_SHORTNAMELEN]; 638 smb_odir_t *od; 639 smb_fileinfo_t fileinfo; 640 uint32_t status; 641 uint16_t eos; 642 smb_vdb_t *vdb; 643 644 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 645 return (SDRC_ERROR); 646 647 pn = &sr->arg.dirop.fqi.fq_path; 648 vdb = kmem_alloc(sizeof (smb_vdb_t), KM_SLEEP); 649 if ((smbsr_decode_data(sr, "%AV", sr, &pn->pn_path, vdb) != 0) || 650 (vdb->vdb_len != 0)) { 651 kmem_free(vdb, sizeof (smb_vdb_t)); 652 return (SDRC_ERROR); 653 } 654 kmem_free(vdb, sizeof (smb_vdb_t)); 655 656 smb_pathname_init(sr, pn, pn->pn_path); 657 if (!smb_pathname_validate(sr, pn)) 658 return (SDRC_ERROR); 659 660 if (smb_is_stream_name(pn->pn_path)) { 661 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 662 ERRDOS, ERROR_INVALID_NAME); 663 return (SDRC_ERROR); 664 } 665 666 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 667 668 status = smb_odir_openpath(sr, pn->pn_path, sattr, 0, &od); 669 if (status != 0) { 670 smbsr_error(sr, status, 0, 0); 671 return (SDRC_ERROR); 672 } 673 if (od == NULL) 674 return (SDRC_ERROR); 675 676 rc = 0; 677 count = 0; 678 index = 0; 679 if (maxcount > SMB_MAX_SEARCH) 680 maxcount = SMB_MAX_SEARCH; 681 682 while (count < maxcount) { 683 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); 684 if (rc != 0 || eos != 0) 685 break; 686 687 if (*fileinfo.fi_shortname == '\0') { 688 if (smb_needs_mangled(fileinfo.fi_name)) 689 continue; 690 (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, 691 SMB_SHORTNAMELEN - 1); 692 } 693 smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN); 694 695 (void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c", 696 resume_char, name83, index, od->d_odid, client_key, 697 fileinfo.fi_dosattr & 0xff, 698 smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec), 699 (int32_t)fileinfo.fi_size, 700 fileinfo.fi_shortname); 701 702 count++; 703 index++; 704 } 705 if (eos && rc == ENOENT) 706 rc = 0; 707 708 smb_odir_close(od); 709 smb_odir_release(od); 710 711 if (rc != 0) 712 return (SDRC_ERROR); 713 714 if (count == 0) { 715 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 716 ERRDOS, ERROR_NO_MORE_FILES); 717 return (SDRC_ERROR); 718 } 719 720 rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; 721 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, 722 "bwwbw", 1, count, rc+3, 5, rc) < 0) { 723 return (SDRC_ERROR); 724 } 725 726 return (SDRC_SUCCESS); 727 } 728 729 /* 730 * smb_name83 731 * 732 * Format the filename for inclusion in the resume key. The filename 733 * returned in the resume key is 11 bytes: 734 * - up to 8 bytes of filename, space padded to 8 bytes 735 * - up to 3 bytes of ext, space padded to 3 bytes 736 * 737 * The name passed to smb_name83 should be a shortname or a name that 738 * doesn't require mangling. 739 * 740 * Examples: 741 * "fname.txt" -> "FNAME TXT" 742 * "fname.tx" -> "FNAME TX " 743 * "filename" -> "FILENAME " 744 * "filename.txt" -> "FILENAMETXT" 745 * "FILE~1.TXT" -> "FILE~1 TXT" 746 */ 747 static void 748 smb_name83(const char *name, char *buf, size_t buflen) 749 { 750 const char *p; 751 char *pbuf; 752 int i; 753 754 ASSERT(name && buf && (buflen >= SMB_NAME83_BUFLEN)); 755 756 (void) strlcpy(buf, " ", SMB_NAME83_BUFLEN); 757 758 /* Process "." and ".." up front */ 759 if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) { 760 (void) strncpy(buf, name, strlen(name)); 761 return; 762 } 763 764 ASSERT(smb_needs_mangled(name) == B_FALSE); 765 766 /* Process basename */ 767 for (i = 0, p = name, pbuf = buf; 768 (i < SMB_NAME83_BASELEN) && (*p != '\0') && (*p != '.'); ++i) 769 *pbuf++ = *p++; 770 771 /* Process the extension from the last dot in name */ 772 if ((p = strchr(name, '.')) != NULL) { 773 ++p; 774 pbuf = &buf[SMB_NAME83_BASELEN]; 775 for (i = 0; (i < SMB_NAME83_EXTLEN) && (*p != '\0'); ++i) 776 *pbuf++ = *p++; 777 } 778 779 (void) smb_strupr(buf); 780 } 781