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