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 }