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 }