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