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 2015 Nexenta Systems, 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 244 ASSERT((sa->sa_mask & SMB_AT_BASIC) == SMB_AT_BASIC); 245 246 (void) smb_mbc_encodef( 247 &sr->raw_data, "TTTTll", 248 &sa->sa_crtime, /* T */ 249 &sa->sa_vattr.va_atime, /* T */ 250 &sa->sa_vattr.va_mtime, /* T */ 251 &sa->sa_vattr.va_ctime, /* T */ 252 sa->sa_dosattr, /* l */ 253 0); /* reserved */ /* l */ 254 255 return (0); 256 } 257 258 /* 259 * FileStandardInformation 260 * See also: 261 * SMB_QUERY_FILE_STANDARD_INFO 262 * SMB_FILE_STANDARD_INFORMATION 263 */ 264 static uint32_t 265 smb2_qif_standard(smb_request_t *sr, smb_queryinfo_t *qi) 266 { 267 smb_attr_t *sa = &qi->qi_attr; 268 269 ASSERT((sa->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD); 270 271 (void) smb_mbc_encodef( 272 &sr->raw_data, "qqlbbw", 273 sa->sa_allocsz, /* q */ 274 sa->sa_vattr.va_size, /* q */ 275 sa->sa_vattr.va_nlink, /* l */ 276 qi->qi_delete_on_close, /* b */ 277 qi->qi_isdir, /* b */ 278 0); /* reserved */ /* w */ 279 280 return (0); 281 } 282 283 /* 284 * FileInternalInformation 285 * See also: 286 * SMB_FILE_INTERNAL_INFORMATION 287 */ 288 static uint32_t 289 smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi) 290 { 291 smb_attr_t *sa = &qi->qi_attr; 292 u_longlong_t nodeid; 293 294 ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID); 295 nodeid = sa->sa_vattr.va_nodeid; 296 297 if (smb2_aapl_use_file_ids == 0 && 298 (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0) 299 nodeid = 0; 300 301 (void) smb_mbc_encodef( 302 &sr->raw_data, "q", 303 nodeid); /* q */ 304 305 return (0); 306 } 307 308 /* 309 * FileEaInformation 310 * See also: 311 * SMB_QUERY_FILE_EA_INFO 312 * SMB_FILE_EA_INFORMATION 313 */ 314 static uint32_t 315 smb2_qif_ea_size(smb_request_t *sr, smb_queryinfo_t *qi) 316 { 317 _NOTE(ARGUNUSED(qi)) 318 319 (void) smb_mbc_encodef( 320 &sr->raw_data, "l", 0); 321 322 return (0); 323 } 324 325 /* 326 * FileFullEaInformation 327 * We could put EAs in a named stream... 328 */ 329 /* ARGSUSED */ 330 static uint32_t 331 smb2_qif_full_ea(smb_request_t *sr, smb_queryinfo_t *qi) 332 { 333 return (NT_STATUS_NO_EAS_ON_FILE); 334 } 335 336 /* 337 * FileAccessInformation 338 */ 339 static uint32_t 340 smb2_qif_access(smb_request_t *sr, smb_queryinfo_t *qi) 341 { 342 _NOTE(ARGUNUSED(qi)) 343 smb_ofile_t *of = sr->fid_ofile; 344 345 (void) smb_mbc_encodef( 346 &sr->raw_data, "l", 347 of->f_granted_access); 348 349 return (0); 350 } 351 352 /* 353 * FileNameInformation 354 * See also: 355 * SMB_QUERY_FILE_NAME_INFO 356 * SMB_FILE_NAME_INFORMATION 357 */ 358 static uint32_t 359 smb2_qif_name(smb_request_t *sr, smb_queryinfo_t *qi) 360 { 361 362 ASSERT(qi->qi_namelen > 0); 363 364 (void) smb_mbc_encodef( 365 &sr->raw_data, "llU", 366 0, /* FileIndex (l) */ 367 qi->qi_namelen, /* l */ 368 qi->qi_name); /* U */ 369 370 return (0); 371 } 372 373 /* 374 * FilePositionInformation 375 */ 376 static uint32_t 377 smb2_qif_position(smb_request_t *sr, smb_queryinfo_t *qi) 378 { 379 _NOTE(ARGUNUSED(qi)) 380 smb_ofile_t *of = sr->fid_ofile; 381 uint64_t pos; 382 383 mutex_enter(&of->f_mutex); 384 pos = of->f_seek_pos; 385 mutex_exit(&of->f_mutex); 386 387 (void) smb_mbc_encodef( 388 &sr->raw_data, "q", pos); 389 390 return (0); 391 } 392 393 /* 394 * FileModeInformation [MS-FSA 2.4.24] 395 * XXX: These mode flags are supposed to be on the open handle, 396 * XXX: or I think so. Not yet... (just put zero for now) 397 */ 398 static uint32_t 399 smb2_qif_mode(smb_request_t *sr, smb_queryinfo_t *qi) 400 { 401 _NOTE(ARGUNUSED(qi)) 402 403 (void) smb_mbc_encodef( 404 &sr->raw_data, "l", 0); 405 406 return (0); 407 } 408 409 /* 410 * FileAlignmentInformation 411 */ 412 static uint32_t 413 smb2_qif_alignment(smb_request_t *sr, smb_queryinfo_t *qi) 414 { 415 _NOTE(ARGUNUSED(qi)) 416 417 (void) smb_mbc_encodef( 418 &sr->raw_data, "l", 0); 419 420 return (0); 421 } 422 423 /* 424 * FileAlternateNameInformation 425 * See also: 426 * SMB_QUERY_FILE_ALT_NAME_INFO 427 * SMB_FILE_ALT_NAME_INFORMATION 428 */ 429 static uint32_t 430 smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi) 431 { 432 smb_ofile_t *of = sr->fid_ofile; 433 434 ASSERT(qi->qi_namelen > 0); 435 ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID); 436 437 if (of->f_ftype != SMB_FTYPE_DISK) 438 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 439 if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0) 440 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 441 442 /* fill in qi->qi_shortname */ 443 smb_query_shortname(of->f_node, qi); 444 445 (void) smb_mbc_encodef( 446 &sr->raw_data, "%lU", sr, 447 smb_wcequiv_strlen(qi->qi_shortname), 448 qi->qi_shortname); 449 450 return (0); 451 } 452 453 /* 454 * FileStreamInformation 455 */ 456 static uint32_t 457 smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi) 458 { 459 smb_ofile_t *of = sr->fid_ofile; 460 smb_attr_t *attr = &qi->qi_attr; 461 uint32_t status; 462 463 ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD); 464 if (of->f_ftype != SMB_FTYPE_DISK) { 465 (void) smb_mbc_encodef( 466 &sr->raw_data, "l", 0); 467 return (0); 468 } 469 470 status = smb_query_stream_info(sr, &sr->raw_data, qi); 471 return (status); 472 } 473 474 /* 475 * FilePipeInformation 476 */ 477 static uint32_t 478 smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi) 479 { 480 _NOTE(ARGUNUSED(qi)) 481 smb_ofile_t *of = sr->fid_ofile; 482 uint32_t pipe_mode; 483 uint32_t nonblock; 484 485 switch (of->f_ftype) { 486 case SMB_FTYPE_BYTE_PIPE: 487 pipe_mode = 0; /* FILE_PIPE_BYTE_STREAM_MODE */ 488 break; 489 case SMB_FTYPE_MESG_PIPE: 490 pipe_mode = 1; /* FILE_PIPE_MESSAGE_MODE */ 491 break; 492 case SMB_FTYPE_DISK: 493 case SMB_FTYPE_PRINTER: 494 default: 495 return (NT_STATUS_INVALID_PARAMETER); 496 } 497 nonblock = 0; /* XXX todo: Get this from the pipe handle. */ 498 499 (void) smb_mbc_encodef( 500 &sr->raw_data, "ll", 501 pipe_mode, nonblock); 502 503 return (0); 504 } 505 506 /* 507 * FilePipeLocalInformation 508 */ 509 /* ARGSUSED */ 510 static uint32_t 511 smb2_qif_pipe_lcl(smb_request_t *sr, smb_queryinfo_t *qi) 512 { 513 return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */ 514 } 515 516 /* 517 * FilePipeRemoteInformation 518 */ 519 /* ARGSUSED */ 520 static uint32_t 521 smb2_qif_pipe_rem(smb_request_t *sr, smb_queryinfo_t *qi) 522 { 523 return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */ 524 } 525 526 /* 527 * FileCompressionInformation 528 * XXX: For now, just say "not compressed". 529 */ 530 static uint32_t 531 smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi) 532 { 533 smb_attr_t *sa = &qi->qi_attr; 534 uint16_t CompressionFormat = 0; /* COMPRESSION_FORMAT_NONE */ 535 536 ASSERT(sa->sa_mask & SMB_AT_SIZE); 537 538 (void) smb_mbc_encodef( 539 &sr->raw_data, "qw6.", 540 sa->sa_vattr.va_size, /* q */ 541 CompressionFormat); /* w */ 542 543 return (0); 544 } 545 546 /* 547 * FileNetworkOpenInformation 548 */ 549 static uint32_t 550 smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi) 551 { 552 smb_attr_t *sa = &qi->qi_attr; 553 554 (void) smb_mbc_encodef( 555 &sr->raw_data, "TTTTqqll", 556 &sa->sa_crtime, /* T */ 557 &sa->sa_vattr.va_atime, /* T */ 558 &sa->sa_vattr.va_mtime, /* T */ 559 &sa->sa_vattr.va_ctime, /* T */ 560 sa->sa_allocsz, /* q */ 561 sa->sa_vattr.va_size, /* q */ 562 sa->sa_dosattr, /* l */ 563 0); /* reserved */ /* l */ 564 565 return (0); 566 } 567 568 /* 569 * FileAttributeTagInformation 570 * 571 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the 572 * second dword should be the reparse tag. Otherwise 573 * the tag value should be set to zero. 574 * We don't support reparse points, so we set the tag 575 * to zero. 576 */ 577 static uint32_t 578 smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi) 579 { 580 _NOTE(ARGUNUSED(qi)) 581 (void) smb_mbc_encodef( 582 &sr->raw_data, "ll", 0, 0); 583 584 return (0); 585 } 586