1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. 14 * Copyright 2022 RackTop Systems, Inc. 15 */ 16 17 /* 18 * Dispatch function for SMB2_QUERY_INFO 19 * 20 * [MS-FSCC 2.4] If a file system does not support ... 21 * an Information Classs, NT_STATUS_INVALID_PARAMETER... 22 */ 23 24 #include <smbsrv/smb2_kproto.h> 25 #include <smbsrv/smb_fsops.h> 26 #include <smbsrv/ntifs.h> 27 28 static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *); 29 static uint32_t smb2_qif_basic(smb_request_t *, smb_queryinfo_t *); 30 static uint32_t smb2_qif_standard(smb_request_t *, smb_queryinfo_t *); 31 static uint32_t smb2_qif_internal(smb_request_t *, smb_queryinfo_t *); 32 static uint32_t smb2_qif_ea_size(smb_request_t *, smb_queryinfo_t *); 33 static uint32_t smb2_qif_access(smb_request_t *, smb_queryinfo_t *); 34 static uint32_t smb2_qif_name(smb_request_t *, smb_queryinfo_t *); 35 static uint32_t smb2_qif_position(smb_request_t *, smb_queryinfo_t *); 36 static uint32_t smb2_qif_full_ea(smb_request_t *, smb_queryinfo_t *); 37 static uint32_t smb2_qif_mode(smb_request_t *, smb_queryinfo_t *); 38 static uint32_t smb2_qif_alignment(smb_request_t *, smb_queryinfo_t *); 39 static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *); 40 static uint32_t smb2_qif_altname(smb_request_t *, smb_queryinfo_t *); 41 static uint32_t smb2_qif_stream(smb_request_t *, smb_queryinfo_t *); 42 static uint32_t smb2_qif_pipe(smb_request_t *, smb_queryinfo_t *); 43 static uint32_t smb2_qif_pipe_lcl(smb_request_t *, smb_queryinfo_t *); 44 static uint32_t smb2_qif_pipe_rem(smb_request_t *, smb_queryinfo_t *); 45 static uint32_t smb2_qif_compr(smb_request_t *, smb_queryinfo_t *); 46 static uint32_t smb2_qif_opens(smb_request_t *, smb_queryinfo_t *); 47 static uint32_t smb2_qif_tags(smb_request_t *, smb_queryinfo_t *); 48 49 50 uint32_t 51 smb2_qinfo_file(smb_request_t *sr, smb_queryinfo_t *qi) 52 { 53 smb_ofile_t *of = sr->fid_ofile; 54 uint_t mask = 0; 55 boolean_t getstd = B_FALSE; 56 boolean_t getname = B_FALSE; 57 uint32_t status; 58 59 /* 60 * Which attributes do we need from the FS? 61 */ 62 switch (qi->qi_InfoClass) { 63 case FileBasicInformation: 64 mask = SMB_AT_BASIC; 65 break; 66 case FileStandardInformation: 67 mask = SMB_AT_STANDARD; 68 getstd = B_TRUE; 69 break; 70 case FileInternalInformation: 71 mask = SMB_AT_NODEID; 72 break; 73 case FileAllInformation: 74 mask = SMB_AT_ALL; 75 getstd = B_TRUE; 76 if (sr->session->dialect < SMB_VERS_3_11) { 77 /* See smb2_qif_all() */ 78 getname = B_TRUE; 79 } 80 break; 81 82 case FileNameInformation: 83 getname = B_TRUE; 84 break; 85 86 case FileAlternateNameInformation: 87 mask = SMB_AT_NODEID; 88 getname = B_TRUE; 89 break; 90 91 case FileStreamInformation: 92 mask = SMB_AT_STANDARD; 93 getstd = B_TRUE; 94 break; 95 96 case FileCompressionInformation: 97 mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ; 98 break; 99 100 case FileNetworkOpenInformation: 101 mask = SMB_AT_BASIC | SMB_AT_STANDARD; 102 103 default: 104 break; 105 } 106 107 qi->qi_attr.sa_mask = mask; 108 qi->qi_node = of->f_node; 109 if (mask & SMB_AT_ALL) { 110 status = smb2_ofile_getattr(sr, of, &qi->qi_attr); 111 if (status) 112 return (status); 113 } 114 if (getstd) { 115 status = smb2_ofile_getstd(of, qi); 116 if (status) 117 return (status); 118 } 119 if (getname) { 120 status = smb2_ofile_getname(of, qi); 121 if (status) 122 return (status); 123 } 124 125 switch (qi->qi_InfoClass) { 126 case FileBasicInformation: 127 status = smb2_qif_basic(sr, qi); 128 break; 129 case FileStandardInformation: 130 status = smb2_qif_standard(sr, qi); 131 break; 132 case FileInternalInformation: 133 status = smb2_qif_internal(sr, qi); 134 break; 135 case FileEaInformation: 136 status = smb2_qif_ea_size(sr, qi); 137 break; 138 case FileAccessInformation: 139 status = smb2_qif_access(sr, qi); 140 break; 141 case FileNameInformation: 142 status = smb2_qif_name(sr, qi); 143 break; 144 case FilePositionInformation: 145 status = smb2_qif_position(sr, qi); 146 break; 147 case FileFullEaInformation: 148 status = smb2_qif_full_ea(sr, qi); 149 break; 150 case FileModeInformation: 151 status = smb2_qif_mode(sr, qi); 152 break; 153 case FileAlignmentInformation: 154 status = smb2_qif_alignment(sr, qi); 155 break; 156 case FileAllInformation: 157 status = smb2_qif_all(sr, qi); 158 break; 159 case FileAlternateNameInformation: 160 status = smb2_qif_altname(sr, qi); 161 break; 162 case FileStreamInformation: 163 status = smb2_qif_stream(sr, qi); 164 break; 165 case FilePipeInformation: 166 status = smb2_qif_pipe(sr, qi); 167 break; 168 case FilePipeLocalInformation: 169 status = smb2_qif_pipe_lcl(sr, qi); 170 break; 171 case FilePipeRemoteInformation: 172 status = smb2_qif_pipe_rem(sr, qi); 173 break; 174 case FileCompressionInformation: 175 status = smb2_qif_compr(sr, qi); 176 break; 177 case FileNetworkOpenInformation: 178 status = smb2_qif_opens(sr, qi); 179 break; 180 case FileAttributeTagInformation: 181 status = smb2_qif_tags(sr, qi); 182 break; 183 default: 184 status = NT_STATUS_INVALID_INFO_CLASS; 185 break; 186 } 187 188 return (status); 189 } 190 191 /* 192 * FileAllInformation 193 * 194 * This returns a concatenation of: 195 * FileBasicInformation 196 * FileStandardInformation 197 * FileInternalInformation 198 * FileEaInformation 199 * FilePositionInformation 200 * FileModeInformation 201 * FileAlignmentInformation 202 * FileNameInformation 203 * 204 * Note: FileNameInformation is all zero on Win2016 and later. 205 */ 206 static uint32_t 207 smb2_qif_all(smb_request_t *sr, smb_queryinfo_t *qi) 208 { 209 uint32_t status; 210 211 status = smb2_qif_basic(sr, qi); 212 if (status) 213 return (status); 214 status = smb2_qif_standard(sr, qi); 215 if (status) 216 return (status); 217 status = smb2_qif_internal(sr, qi); 218 if (status) 219 return (status); 220 status = smb2_qif_ea_size(sr, qi); 221 if (status) 222 return (status); 223 status = smb2_qif_position(sr, qi); 224 if (status) 225 return (status); 226 status = smb2_qif_mode(sr, qi); 227 if (status) 228 return (status); 229 status = smb2_qif_alignment(sr, qi); 230 if (status) 231 return (status); 232 233 /* 234 * MS-SMB2 3.3.5.20.1 says (in a windows behavior note) that 235 * 2012R2 and older fill in the FileNameInformation. 236 * We could let this depend on sr->sr_cfg->skc_version 237 * but doing it based on dialect is a lot easier and 238 * has nearly the same effect. 239 */ 240 if (sr->session->dialect < SMB_VERS_3_11) { 241 /* Win2012r2 and earlier fill it in. (SMB 3.0) */ 242 status = smb2_qif_name(sr, qi); 243 } else { 244 /* Win2016 and later just put zeros (SMB 3.11) */ 245 int rc = smb_mbc_encodef(&sr->raw_data, "10."); 246 status = (rc == 0) ? 0 : NT_STATUS_BUFFER_OVERFLOW; 247 } 248 249 return (status); 250 } 251 252 /* 253 * FileBasicInformation 254 * See also: 255 * case SMB_QUERY_FILE_BASIC_INFO: 256 * case SMB_FILE_BASIC_INFORMATION: 257 */ 258 static uint32_t 259 smb2_qif_basic(smb_request_t *sr, smb_queryinfo_t *qi) 260 { 261 smb_attr_t *sa = &qi->qi_attr; 262 int rc; 263 264 ASSERT((sa->sa_mask & SMB_AT_BASIC) == SMB_AT_BASIC); 265 266 rc = smb_mbc_encodef( 267 &sr->raw_data, "TTTTll", 268 &sa->sa_crtime, /* T */ 269 &sa->sa_vattr.va_atime, /* T */ 270 &sa->sa_vattr.va_mtime, /* T */ 271 &sa->sa_vattr.va_ctime, /* T */ 272 sa->sa_dosattr, /* l */ 273 0); /* reserved */ /* l */ 274 if (rc != 0) 275 return (NT_STATUS_BUFFER_OVERFLOW); 276 277 return (0); 278 } 279 280 /* 281 * FileStandardInformation 282 * See also: 283 * SMB_QUERY_FILE_STANDARD_INFO 284 * SMB_FILE_STANDARD_INFORMATION 285 */ 286 static uint32_t 287 smb2_qif_standard(smb_request_t *sr, smb_queryinfo_t *qi) 288 { 289 smb_attr_t *sa = &qi->qi_attr; 290 int rc; 291 292 ASSERT((sa->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD); 293 294 rc = smb_mbc_encodef( 295 &sr->raw_data, "qqlbbw", 296 sa->sa_allocsz, /* q */ 297 sa->sa_vattr.va_size, /* q */ 298 sa->sa_vattr.va_nlink, /* l */ 299 qi->qi_delete_on_close, /* b */ 300 qi->qi_isdir, /* b */ 301 0); /* reserved */ /* w */ 302 if (rc != 0) 303 return (NT_STATUS_BUFFER_OVERFLOW); 304 305 return (0); 306 } 307 308 /* 309 * FileInternalInformation 310 * See also: 311 * SMB_FILE_INTERNAL_INFORMATION 312 */ 313 static uint32_t 314 smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi) 315 { 316 smb_attr_t *sa = &qi->qi_attr; 317 u_longlong_t nodeid; 318 int rc; 319 320 ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID); 321 nodeid = sa->sa_vattr.va_nodeid; 322 323 if (smb2_aapl_use_file_ids == 0 && 324 (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0) 325 nodeid = 0; 326 327 rc = smb_mbc_encodef( 328 &sr->raw_data, "q", 329 nodeid); /* q */ 330 if (rc != 0) 331 return (NT_STATUS_BUFFER_OVERFLOW); 332 333 return (0); 334 } 335 336 /* 337 * FileEaInformation 338 * See also: 339 * SMB_QUERY_FILE_EA_INFO 340 * SMB_FILE_EA_INFORMATION 341 */ 342 static uint32_t 343 smb2_qif_ea_size(smb_request_t *sr, smb_queryinfo_t *qi) 344 { 345 _NOTE(ARGUNUSED(qi)) 346 int rc; 347 348 rc = smb_mbc_encodef( 349 &sr->raw_data, "l", 0); 350 if (rc != 0) 351 return (NT_STATUS_BUFFER_OVERFLOW); 352 353 return (0); 354 } 355 356 /* 357 * FileFullEaInformation 358 * We could put EAs in a named stream... 359 */ 360 /* ARGSUSED */ 361 static uint32_t 362 smb2_qif_full_ea(smb_request_t *sr, smb_queryinfo_t *qi) 363 { 364 return (NT_STATUS_NO_EAS_ON_FILE); 365 } 366 367 /* 368 * FileAccessInformation 369 */ 370 static uint32_t 371 smb2_qif_access(smb_request_t *sr, smb_queryinfo_t *qi) 372 { 373 _NOTE(ARGUNUSED(qi)) 374 smb_ofile_t *of = sr->fid_ofile; 375 int rc; 376 377 rc = smb_mbc_encodef( 378 &sr->raw_data, "l", 379 of->f_granted_access); 380 if (rc != 0) 381 return (NT_STATUS_BUFFER_OVERFLOW); 382 383 return (0); 384 } 385 386 /* 387 * FileNameInformation 388 * See also: 389 * SMB_QUERY_FILE_NAME_INFO 390 * SMB_FILE_NAME_INFORMATION 391 */ 392 static uint32_t 393 smb2_qif_name(smb_request_t *sr, smb_queryinfo_t *qi) 394 { 395 int rc; 396 397 ASSERT(qi->qi_namelen > 0); 398 399 rc = smb_mbc_encodef( 400 &sr->raw_data, "llU", 401 0, /* FileIndex (l) */ 402 qi->qi_namelen, /* l */ 403 qi->qi_name); /* U */ 404 if (rc != 0) 405 return (NT_STATUS_BUFFER_OVERFLOW); 406 407 return (0); 408 } 409 410 /* 411 * FilePositionInformation 412 */ 413 static uint32_t 414 smb2_qif_position(smb_request_t *sr, smb_queryinfo_t *qi) 415 { 416 _NOTE(ARGUNUSED(qi)) 417 smb_ofile_t *of = sr->fid_ofile; 418 uint64_t pos; 419 int rc; 420 421 mutex_enter(&of->f_mutex); 422 pos = of->f_seek_pos; 423 mutex_exit(&of->f_mutex); 424 425 rc = smb_mbc_encodef( 426 &sr->raw_data, "q", pos); 427 if (rc != 0) 428 return (NT_STATUS_BUFFER_OVERFLOW); 429 430 return (0); 431 } 432 433 /* 434 * FileModeInformation [MS-FSA 2.4.24] 435 * XXX: These mode flags are supposed to be on the open handle, 436 * XXX: or I think so. Not yet... (just put zero for now) 437 */ 438 static uint32_t 439 smb2_qif_mode(smb_request_t *sr, smb_queryinfo_t *qi) 440 { 441 _NOTE(ARGUNUSED(qi)) 442 int rc; 443 444 rc = smb_mbc_encodef( 445 &sr->raw_data, "l", 0); 446 if (rc != 0) 447 return (NT_STATUS_BUFFER_OVERFLOW); 448 449 return (0); 450 } 451 452 /* 453 * FileAlignmentInformation 454 */ 455 static uint32_t 456 smb2_qif_alignment(smb_request_t *sr, smb_queryinfo_t *qi) 457 { 458 _NOTE(ARGUNUSED(qi)) 459 int rc; 460 461 rc = smb_mbc_encodef( 462 &sr->raw_data, "l", 0); 463 if (rc != 0) 464 return (NT_STATUS_BUFFER_OVERFLOW); 465 466 return (0); 467 } 468 469 /* 470 * FileAlternateNameInformation 471 * See also: 472 * SMB_QUERY_FILE_ALT_NAME_INFO 473 * SMB_FILE_ALT_NAME_INFORMATION 474 */ 475 static uint32_t 476 smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi) 477 { 478 smb_ofile_t *of = sr->fid_ofile; 479 int rc; 480 481 ASSERT(qi->qi_namelen > 0); 482 ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID); 483 484 if (of->f_ftype != SMB_FTYPE_DISK) 485 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 486 if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0) 487 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 488 489 /* fill in qi->qi_shortname */ 490 smb_query_shortname(of->f_node, qi); 491 492 rc = smb_mbc_encodef( 493 &sr->raw_data, "%lU", sr, 494 smb_wcequiv_strlen(qi->qi_shortname), 495 qi->qi_shortname); 496 if (rc != 0) 497 return (NT_STATUS_BUFFER_OVERFLOW); 498 499 return (0); 500 } 501 502 /* 503 * FileStreamInformation 504 */ 505 static uint32_t 506 smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi) 507 { 508 smb_ofile_t *of = sr->fid_ofile; 509 smb_attr_t *attr = &qi->qi_attr; 510 uint32_t status; 511 512 ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD); 513 if (of->f_ftype != SMB_FTYPE_DISK) { 514 (void) smb_mbc_encodef( 515 &sr->raw_data, "l", 0); 516 return (0); 517 } 518 519 status = smb_query_stream_info(sr, &sr->raw_data, qi); 520 return (status); 521 } 522 523 /* 524 * FilePipeInformation 525 */ 526 static uint32_t 527 smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi) 528 { 529 _NOTE(ARGUNUSED(qi)) 530 smb_ofile_t *of = sr->fid_ofile; 531 uint32_t pipe_mode; 532 uint32_t nonblock; 533 int rc; 534 535 switch (of->f_ftype) { 536 case SMB_FTYPE_BYTE_PIPE: 537 pipe_mode = 0; /* FILE_PIPE_BYTE_STREAM_MODE */ 538 break; 539 case SMB_FTYPE_MESG_PIPE: 540 pipe_mode = 1; /* FILE_PIPE_MESSAGE_MODE */ 541 break; 542 case SMB_FTYPE_DISK: 543 case SMB_FTYPE_PRINTER: 544 default: 545 return (NT_STATUS_INVALID_PARAMETER); 546 } 547 nonblock = 0; /* XXX todo: Get this from the pipe handle. */ 548 549 rc = smb_mbc_encodef( 550 &sr->raw_data, "ll", 551 pipe_mode, nonblock); 552 if (rc != 0) 553 return (NT_STATUS_BUFFER_OVERFLOW); 554 555 return (0); 556 } 557 558 /* 559 * FilePipeLocalInformation 560 */ 561 /* ARGSUSED */ 562 static uint32_t 563 smb2_qif_pipe_lcl(smb_request_t *sr, smb_queryinfo_t *qi) 564 { 565 return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */ 566 } 567 568 /* 569 * FilePipeRemoteInformation 570 */ 571 /* ARGSUSED */ 572 static uint32_t 573 smb2_qif_pipe_rem(smb_request_t *sr, smb_queryinfo_t *qi) 574 { 575 return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */ 576 } 577 578 /* 579 * FileCompressionInformation 580 * XXX: For now, just say "not compressed". 581 */ 582 static uint32_t 583 smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi) 584 { 585 smb_attr_t *sa = &qi->qi_attr; 586 uint16_t CompressionFormat = 0; /* COMPRESSION_FORMAT_NONE */ 587 int rc; 588 589 ASSERT(sa->sa_mask & SMB_AT_SIZE); 590 591 rc = smb_mbc_encodef( 592 &sr->raw_data, "qw6.", 593 sa->sa_vattr.va_size, /* q */ 594 CompressionFormat); /* w */ 595 if (rc != 0) 596 return (NT_STATUS_BUFFER_OVERFLOW); 597 598 return (0); 599 } 600 601 /* 602 * FileNetworkOpenInformation 603 */ 604 static uint32_t 605 smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi) 606 { 607 smb_attr_t *sa = &qi->qi_attr; 608 int rc; 609 610 rc = smb_mbc_encodef( 611 &sr->raw_data, "TTTTqqll", 612 &sa->sa_crtime, /* T */ 613 &sa->sa_vattr.va_atime, /* T */ 614 &sa->sa_vattr.va_mtime, /* T */ 615 &sa->sa_vattr.va_ctime, /* T */ 616 sa->sa_allocsz, /* q */ 617 sa->sa_vattr.va_size, /* q */ 618 sa->sa_dosattr, /* l */ 619 0); /* reserved */ /* l */ 620 if (rc != 0) 621 return (NT_STATUS_BUFFER_OVERFLOW); 622 623 return (0); 624 } 625 626 /* 627 * FileAttributeTagInformation 628 * 629 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the 630 * second dword should be the reparse tag. Otherwise 631 * the tag value should be set to zero. 632 * We don't support reparse points, so we set the tag 633 * to zero. 634 */ 635 static uint32_t 636 smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi) 637 { 638 _NOTE(ARGUNUSED(qi)) 639 int rc; 640 641 rc = smb_mbc_encodef( 642 &sr->raw_data, "ll", 0, 0); 643 if (rc != 0) 644 return (NT_STATUS_BUFFER_OVERFLOW); 645 646 return (0); 647 } 648