1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 #include <smbsrv/smb_kproto.h>
  28 #include <smbsrv/smb_vops.h>
  29 #include <smbsrv/smb_fsops.h>
  30 
  31 /*
  32  * Trans2 Query File/Path Information Levels:
  33  *
  34  * SMB_INFO_STANDARD
  35  * SMB_INFO_QUERY_EA_SIZE
  36  * SMB_INFO_QUERY_EAS_FROM_LIST
  37  * SMB_INFO_QUERY_ALL_EAS - not valid for pipes
  38  * SMB_INFO_IS_NAME_VALID - only valid when query is by path
  39  *
  40  * SMB_QUERY_FILE_BASIC_INFO
  41  * SMB_QUERY_FILE_STANDARD_INFO
  42  * SMB_QUERY_FILE_EA_INFO
  43  * SMB_QUERY_FILE_NAME_INFO
  44  * SMB_QUERY_FILE_ALL_INFO
  45  * SMB_QUERY_FILE_ALT_NAME_INFO - not valid for pipes
  46  * SMB_QUERY_FILE_STREAM_INFO - not valid for pipes
  47  * SMB_QUERY_FILE_COMPRESSION_INFO - not valid for pipes
  48  *
  49  * Supported Passthrough levels:
  50  * SMB_FILE_BASIC_INFORMATION
  51  * SMB_FILE_STANDARD_INFORMATION
  52  * SMB_FILE_INTERNAL_INFORMATION
  53  * SMB_FILE_EA_INFORMATION
  54  * SMB_FILE_ACCESS_INFORMATION - not yet supported when query by path
  55  * SMB_FILE_NAME_INFORMATION
  56  * SMB_FILE_ALL_INFORMATION
  57  * SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes
  58  * SMB_FILE_STREAM_INFORMATION - not valid for pipes
  59  * SMB_FILE_COMPRESSION_INFORMATION - not valid for pipes
  60  * SMB_FILE_NETWORK_OPEN_INFORMATION - not valid for pipes
  61  * SMB_FILE_ATTR_TAG_INFORMATION - not valid for pipes
  62  *
  63  * Internal levels representing non trans2 requests
  64  * SMB_QUERY_INFORMATION
  65  * SMB_QUERY_INFORMATION2
  66  */
  67 
  68 /*
  69  * SMB_STREAM_ENCODE_FIXED_SIZE:
  70  * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
  71  */
  72 #define SMB_STREAM_ENCODE_FIXED_SZ      24
  73 
  74 /* See smb_queryinfo_t in smb_ktypes.h */
  75 #define qi_mtime        qi_attr.sa_vattr.va_mtime
  76 #define qi_ctime        qi_attr.sa_vattr.va_ctime
  77 #define qi_atime        qi_attr.sa_vattr.va_atime
  78 #define qi_crtime       qi_attr.sa_crtime
  79 
  80 static int smb_query_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
  81 static int smb_query_by_path(smb_request_t *, smb_xa_t *, uint16_t);
  82 
  83 static int smb_query_fileinfo(smb_request_t *, smb_node_t *,
  84     uint16_t, smb_queryinfo_t *);
  85 static int smb_query_pipeinfo(smb_request_t *, smb_opipe_t *,
  86     uint16_t, smb_queryinfo_t *);
  87 static boolean_t smb_query_pipe_valid_infolev(smb_request_t *, uint16_t);
  88 
  89 static int smb_query_encode_response(smb_request_t *, smb_xa_t *,
  90     uint16_t, smb_queryinfo_t *);
  91 static boolean_t smb_stream_fits(smb_request_t *, mbuf_chain_t *,
  92     char *, uint32_t);
  93 static int smb_query_pathname(smb_request_t *, smb_node_t *, boolean_t,
  94     smb_queryinfo_t *);
  95 
  96 int smb_query_passthru;
  97 
  98 /*
  99  * smb_com_trans2_query_file_information
 100  */
 101 smb_sdrc_t
 102 smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
 103 {
 104         uint16_t infolev;
 105 
 106         if (smb_mbc_decodef(&xa->req_param_mb, "ww",
 107             &sr->smb_fid, &infolev) != 0)
 108                 return (SDRC_ERROR);
 109 
 110         if (smb_query_by_fid(sr, xa, infolev) != 0)
 111                 return (SDRC_ERROR);
 112 
 113         return (SDRC_SUCCESS);
 114 }
 115 
 116 /*
 117  * smb_com_trans2_query_path_information
 118  */
 119 smb_sdrc_t
 120 smb_com_trans2_query_path_information(smb_request_t *sr, smb_xa_t *xa)
 121 {
 122         uint16_t        infolev;
 123         smb_fqi_t       *fqi = &sr->arg.dirop.fqi;
 124 
 125         if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
 126                 smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
 127                     ERRDOS, ERROR_INVALID_FUNCTION);
 128                 return (SDRC_ERROR);
 129         }
 130 
 131         if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
 132             sr, &infolev, &fqi->fq_path.pn_path) != 0)
 133                 return (SDRC_ERROR);
 134 
 135         if (smb_query_by_path(sr, xa, infolev) != 0)
 136                 return (SDRC_ERROR);
 137 
 138         return (SDRC_SUCCESS);
 139 }
 140 
 141 /*
 142  * smb_com_query_information (aka getattr)
 143  */
 144 smb_sdrc_t
 145 smb_pre_query_information(smb_request_t *sr)
 146 {
 147         int rc;
 148         smb_fqi_t *fqi = &sr->arg.dirop.fqi;
 149 
 150         rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
 151 
 152         DTRACE_SMB_START(op__QueryInformation, smb_request_t *, sr);
 153 
 154         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 155 }
 156 
 157 void
 158 smb_post_query_information(smb_request_t *sr)
 159 {
 160         DTRACE_SMB_DONE(op__QueryInformation, smb_request_t *, sr);
 161 }
 162 
 163 smb_sdrc_t
 164 smb_com_query_information(smb_request_t *sr)
 165 {
 166         uint16_t infolev = SMB_QUERY_INFORMATION;
 167 
 168         if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
 169                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 170                     ERRDOS, ERROR_ACCESS_DENIED);
 171                 return (SDRC_ERROR);
 172         }
 173 
 174         if (smb_query_by_path(sr, NULL, infolev) != 0)
 175                 return (SDRC_ERROR);
 176 
 177         return (SDRC_SUCCESS);
 178 }
 179 
 180 /*
 181  * smb_com_query_information2 (aka getattre)
 182  */
 183 smb_sdrc_t
 184 smb_pre_query_information2(smb_request_t *sr)
 185 {
 186         int rc;
 187         rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
 188 
 189         DTRACE_SMB_START(op__QueryInformation2, smb_request_t *, sr);
 190 
 191         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 192 }
 193 
 194 void
 195 smb_post_query_information2(smb_request_t *sr)
 196 {
 197         DTRACE_SMB_DONE(op__QueryInformation2, smb_request_t *, sr);
 198 }
 199 
 200 smb_sdrc_t
 201 smb_com_query_information2(smb_request_t *sr)
 202 {
 203         uint16_t infolev = SMB_QUERY_INFORMATION2;
 204 
 205         if (smb_query_by_fid(sr, NULL, infolev) != 0)
 206                 return (SDRC_ERROR);
 207 
 208         return (SDRC_SUCCESS);
 209 }
 210 
 211 /*
 212  * smb_query_by_fid
 213  *
 214  * Common code for querying file information by open file (or pipe) id.
 215  * Use the id to identify the node / pipe object and request the
 216  * smb_queryinfo_t data for that object.
 217  */
 218 static int
 219 smb_query_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
 220 {
 221         int             rc;
 222         smb_queryinfo_t *qinfo;
 223         smb_node_t      *node;
 224         smb_opipe_t     *opipe;
 225 
 226         smbsr_lookup_file(sr);
 227 
 228         if (sr->fid_ofile == NULL) {
 229                 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
 230                 return (-1);
 231         }
 232 
 233         if (infolev == SMB_INFO_IS_NAME_VALID) {
 234                 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
 235                 smbsr_release_file(sr);
 236                 return (-1);
 237         }
 238 
 239         if ((sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE) &&
 240             (!smb_query_pipe_valid_infolev(sr, infolev))) {
 241                 smbsr_release_file(sr);
 242                 return (-1);
 243         }
 244 
 245         sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
 246         qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
 247 
 248         switch (sr->fid_ofile->f_ftype) {
 249         case SMB_FTYPE_DISK:
 250                 node = sr->fid_ofile->f_node;
 251                 rc = smb_query_fileinfo(sr, node, infolev, qinfo);
 252                 break;
 253         case SMB_FTYPE_MESG_PIPE:
 254                 opipe = sr->fid_ofile->f_pipe;
 255                 rc = smb_query_pipeinfo(sr, opipe, infolev, qinfo);
 256                 break;
 257         default:
 258                 smbsr_error(sr, 0, ERRDOS, ERRbadfile);
 259                 rc = -1;
 260                 break;
 261         }
 262 
 263         if (rc == 0)
 264                 rc = smb_query_encode_response(sr, xa, infolev, qinfo);
 265 
 266         kmem_free(qinfo, sizeof (smb_queryinfo_t));
 267         smbsr_release_file(sr);
 268         return (rc);
 269 }
 270 
 271 /*
 272  * smb_query_by_path
 273  *
 274  * Common code for querying file information by file name.
 275  * Use the file name to identify the node object and request the
 276  * smb_queryinfo_t data for that node.
 277  *
 278  * Path should be set in sr->arg.dirop.fqi.fq_path prior to
 279  * calling smb_query_by_path.
 280  *
 281  * Querying attributes on a named pipe by name is an error and
 282  * is handled in the calling functions so that they can return
 283  * the appropriate error status code (which differs by caller).
 284  */
 285 static int
 286 smb_query_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
 287 {
 288         smb_queryinfo_t *qinfo;
 289         smb_node_t      *node, *dnode;
 290         smb_pathname_t  *pn;
 291         int             rc;
 292 
 293         /*
 294          * The function smb_query_fileinfo is used here and in
 295          * smb_query_by_fid.  That common function needs this
 296          * one to call it with a NULL fid_ofile, so check here.
 297          * Note: smb_query_by_fid enforces the opposite.
 298          *
 299          * In theory we could ASSERT this, but whether we have
 300          * fid_ofile set here depends on what sequence of SMB
 301          * commands the client has sent in this message, so
 302          * let's be cautious and handle it as an error.
 303          */
 304         if (sr->fid_ofile != NULL)
 305                 return (-1);
 306 
 307 
 308         /* VALID, but not yet supported */
 309         if (infolev == SMB_FILE_ACCESS_INFORMATION) {
 310                 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
 311                 return (-1);
 312         }
 313 
 314         pn = &sr->arg.dirop.fqi.fq_path;
 315         smb_pathname_init(sr, pn, pn->pn_path);
 316         if (!smb_pathname_validate(sr, pn))
 317                 return (-1);
 318 
 319         qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
 320 
 321         rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
 322             sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode,
 323             qinfo->qi_name);
 324 
 325         if (rc == 0) {
 326                 rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
 327                     sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node);
 328                 smb_node_release(dnode);
 329         }
 330 
 331         if (rc != 0) {
 332                 smbsr_errno(sr, rc);
 333 
 334                 kmem_free(qinfo, sizeof (smb_queryinfo_t));
 335                 return (-1);
 336         }
 337 
 338         if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
 339                 smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
 340                 kmem_free(qinfo, sizeof (smb_queryinfo_t));
 341                 smb_node_release(node);
 342                 return (-1);
 343         }
 344 
 345         rc = smb_query_fileinfo(sr, node, infolev, qinfo);
 346         if (rc != 0) {
 347                 kmem_free(qinfo, sizeof (smb_queryinfo_t));
 348                 smb_node_release(node);
 349                 return (rc);
 350         }
 351 
 352         /* If delete_on_close - NT_STATUS_DELETE_PENDING */
 353         if (qinfo->qi_delete_on_close) {
 354                 smbsr_error(sr, NT_STATUS_DELETE_PENDING,
 355                     ERRDOS, ERROR_ACCESS_DENIED);
 356                 kmem_free(qinfo, sizeof (smb_queryinfo_t));
 357                 smb_node_release(node);
 358                 return (-1);
 359         }
 360 
 361         rc = smb_query_encode_response(sr, xa, infolev, qinfo);
 362         kmem_free(qinfo, sizeof (smb_queryinfo_t));
 363         smb_node_release(node);
 364         return (rc);
 365 }
 366 
 367 /*
 368  * smb_size32
 369  * Some responses only support 32 bit file sizes. If the file size
 370  * exceeds UINT_MAX (32 bit) we return UINT_MAX in the response.
 371  */
 372 static uint32_t
 373 smb_size32(u_offset_t size)
 374 {
 375         return ((size > UINT_MAX) ? UINT_MAX : (uint32_t)size);
 376 }
 377 
 378 /*
 379  * smb_query_encode_response
 380  *
 381  * Encode the data from smb_queryinfo_t into client response
 382  */
 383 int
 384 smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa,
 385     uint16_t infolev, smb_queryinfo_t *qinfo)
 386 {
 387         uint16_t dattr;
 388         u_offset_t datasz, allocsz;
 389         uint32_t status;
 390 
 391         dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
 392         datasz = qinfo->qi_attr.sa_vattr.va_size;
 393         allocsz = qinfo->qi_attr.sa_allocsz;
 394 
 395         switch (infolev) {
 396         case SMB_QUERY_INFORMATION:
 397                 (void) smbsr_encode_result(sr, 10, 0, "bwll10.w",
 398                     10,
 399                     dattr,
 400                     smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
 401                     smb_size32(datasz),
 402                     0);
 403                 break;
 404 
 405         case SMB_QUERY_INFORMATION2:
 406                 (void) smbsr_encode_result(sr, 11, 0, "byyyllww",
 407                     11,
 408                     smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
 409                     smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
 410                     smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
 411                     smb_size32(datasz), smb_size32(allocsz), dattr, 0);
 412         break;
 413 
 414         case SMB_FILE_ACCESS_INFORMATION:
 415                 ASSERT(sr->fid_ofile);
 416                 (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
 417                     sr->fid_ofile->f_granted_access);
 418                 break;
 419 
 420         case SMB_INFO_STANDARD:
 421                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 422                 (void) smb_mbc_encodef(&xa->rep_data_mb,
 423                     ((sr->session->native_os == NATIVE_OS_WIN95) ?
 424                     "YYYllw" : "yyyllw"),
 425                     smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
 426                     smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
 427                     smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
 428                     smb_size32(datasz), smb_size32(allocsz), dattr);
 429                 break;
 430 
 431         case SMB_INFO_QUERY_EA_SIZE:
 432                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 433                 (void) smb_mbc_encodef(&xa->rep_data_mb,
 434                     ((sr->session->native_os == NATIVE_OS_WIN95) ?
 435                     "YYYllwl" : "yyyllwl"),
 436                     smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
 437                     smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
 438                     smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
 439                     smb_size32(datasz), smb_size32(allocsz), dattr, 0);
 440                 break;
 441 
 442         case SMB_INFO_QUERY_ALL_EAS:
 443         case SMB_INFO_QUERY_EAS_FROM_LIST:
 444                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 445                 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
 446                 break;
 447 
 448         case SMB_INFO_IS_NAME_VALID:
 449                 break;
 450 
 451         case SMB_QUERY_FILE_BASIC_INFO:
 452         case SMB_FILE_BASIC_INFORMATION:
 453                 /*
 454                  * NT includes 6 bytes (spec says 4) at the end of this
 455                  * response, which are required by NetBench 5.01.
 456                  */
 457                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 458                 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
 459                     &qinfo->qi_crtime,
 460                     &qinfo->qi_atime,
 461                     &qinfo->qi_mtime,
 462                     &qinfo->qi_ctime,
 463                     dattr);
 464                 break;
 465 
 466         case SMB_QUERY_FILE_STANDARD_INFO:
 467         case SMB_FILE_STANDARD_INFORMATION:
 468                 /* 2-byte pad at end */
 469                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 470                 (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
 471                     (uint64_t)allocsz,
 472                     (uint64_t)datasz,
 473                     qinfo->qi_attr.sa_vattr.va_nlink,
 474                     qinfo->qi_delete_on_close,
 475                     qinfo->qi_isdir);
 476                 break;
 477 
 478         case SMB_QUERY_FILE_EA_INFO:
 479         case SMB_FILE_EA_INFORMATION:
 480                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 481                 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
 482                 break;
 483 
 484         case SMB_QUERY_FILE_NAME_INFO:
 485         case SMB_FILE_NAME_INFORMATION:
 486                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 487                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
 488                     qinfo->qi_namelen, qinfo->qi_name);
 489                 break;
 490 
 491         case SMB_QUERY_FILE_ALL_INFO:
 492         case SMB_FILE_ALL_INFORMATION:
 493                 /*
 494                  * There is a 6-byte pad between Attributes and AllocationSize,
 495                  * and a 2-byte pad after the Directory field.
 496                  */
 497                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 498                 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
 499                     &qinfo->qi_crtime,
 500                     &qinfo->qi_atime,
 501                     &qinfo->qi_mtime,
 502                     &qinfo->qi_ctime,
 503                     dattr,
 504                     (uint64_t)allocsz,
 505                     (uint64_t)datasz,
 506                     qinfo->qi_attr.sa_vattr.va_nlink,
 507                     qinfo->qi_delete_on_close,
 508                     qinfo->qi_isdir,
 509                     0);
 510 
 511                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
 512                     sr, qinfo->qi_namelen, qinfo->qi_name);
 513                 break;
 514 
 515         case SMB_QUERY_FILE_ALT_NAME_INFO:
 516         case SMB_FILE_ALT_NAME_INFORMATION:
 517                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 518                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
 519                     smb_wcequiv_strlen(qinfo->qi_shortname),
 520                     qinfo->qi_shortname);
 521                 break;
 522 
 523         case SMB_QUERY_FILE_STREAM_INFO:
 524         case SMB_FILE_STREAM_INFORMATION:
 525                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 526                 status = smb_query_stream_info(sr, &xa->rep_data_mb, qinfo);
 527                 if (status)
 528                         smbsr_status(sr, status, 0, 0);
 529                 break;
 530 
 531         case SMB_QUERY_FILE_COMPRESSION_INFO:
 532         case SMB_FILE_COMPRESSION_INFORMATION:
 533                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 534                 (void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
 535                     datasz, 0, 0, 0, 0);
 536                 break;
 537 
 538         case SMB_FILE_INTERNAL_INFORMATION:
 539                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 540                 (void) smb_mbc_encodef(&xa->rep_data_mb, "q",
 541                     qinfo->qi_attr.sa_vattr.va_nodeid);
 542                 break;
 543 
 544         case SMB_FILE_NETWORK_OPEN_INFORMATION:
 545                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 546                 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTqql4.",
 547                     &qinfo->qi_crtime,
 548                     &qinfo->qi_atime,
 549                     &qinfo->qi_mtime,
 550                     &qinfo->qi_ctime,
 551                     (uint64_t)allocsz,
 552                     (uint64_t)datasz,
 553                     (uint32_t)dattr);
 554                 break;
 555 
 556         case SMB_FILE_ATTR_TAG_INFORMATION:
 557                 /*
 558                  * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
 559                  * second dword should be the reparse tag.  Otherwise
 560                  * the tag value should be set to zero.
 561                  * We don't support reparse points, so we set the tag
 562                  * to zero.
 563                  */
 564                 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 565                 (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
 566                     (uint32_t)dattr, 0);
 567                 break;
 568 
 569         default:
 570                 if ((infolev > 1000) && smb_query_passthru)
 571                         smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
 572                             ERRDOS, ERROR_NOT_SUPPORTED);
 573                 else
 574                         smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
 575                 return (-1);
 576         }
 577 
 578         return (0);
 579 }
 580 
 581 /*
 582  * smb_encode_stream_info
 583  *
 584  * This function encodes the streams information.
 585  * The following rules about how have been derived from observed NT
 586  * behaviour.
 587  *
 588  * If the target is a file:
 589  * 1. If there are no named streams, the response should still contain
 590  *    an entry for the unnamed stream.
 591  * 2. If there are named streams, the response should contain an entry
 592  *    for the unnamed stream followed by the entries for the named
 593  *    streams.
 594  *
 595  * If the target is a directory:
 596  * 1. If there are no streams, the response is complete. Directories
 597  *    do not report the unnamed stream.
 598  * 2. If there are streams, the response should contain entries for
 599  *    those streams but there should not be an entry for the unnamed
 600  *    stream.
 601  *
 602  * Note that the stream name lengths exclude the null terminator but
 603  * the field lengths (i.e. next offset calculations) need to include
 604  * the null terminator and be padded to a multiple of 8 bytes. The
 605  * last entry does not seem to need any padding.
 606  *
 607  * If an error is encountered when trying to read the stream entries
 608  * (smb_odir_read_streaminfo) it is treated as if there are no [more]
 609  * entries. The entries that have been read so far are returned and
 610  * no error is reported.
 611  *
 612  * If the response buffer is not large enough to return all of the
 613  * named stream entries, the entries that do fit are returned and
 614  * a warning code is set (NT_STATUS_BUFFER_OVERFLOW). The next_offset
 615  * value in the last returned entry must be 0.
 616  */
 617 uint32_t
 618 smb_query_stream_info(smb_request_t *sr, mbuf_chain_t *mbc,
 619         smb_queryinfo_t *qinfo)
 620 {
 621         char *stream_name;
 622         uint32_t next_offset;
 623         uint32_t stream_nlen;
 624         uint32_t pad;
 625         u_offset_t datasz, allocsz;
 626         smb_streaminfo_t *sinfo, *sinfo_next;
 627         int rc = 0;
 628         boolean_t done = B_FALSE;
 629         boolean_t eos = B_FALSE;
 630         smb_odir_t *od = NULL;
 631         uint32_t status = 0;
 632 
 633         smb_node_t *fnode = qinfo->qi_node;
 634         smb_attr_t *attr = &qinfo->qi_attr;
 635 
 636         ASSERT(fnode);
 637         if (SMB_IS_STREAM(fnode)) {
 638                 fnode = fnode->n_unode;
 639                 ASSERT(fnode);
 640         }
 641         ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
 642         ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
 643 
 644         sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
 645         sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
 646         datasz = attr->sa_vattr.va_size;
 647         allocsz = attr->sa_allocsz;
 648 
 649         status = smb_odir_openat(sr, fnode, &od);
 650         switch (status) {
 651         case 0:
 652                 break;
 653         case NT_STATUS_OBJECT_NAME_NOT_FOUND:
 654         case NT_STATUS_NO_SUCH_FILE:
 655         case NT_STATUS_NOT_SUPPORTED:
 656                 /* No streams. */
 657                 status = 0;
 658                 done = B_TRUE;
 659                 break;
 660         default:
 661                 return (status);
 662         }
 663 
 664         if (!done) {
 665                 rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
 666                 if ((rc != 0) || (eos))
 667                         done = B_TRUE;
 668         }
 669 
 670         /* If not a directory, encode an entry for the unnamed stream. */
 671         if (qinfo->qi_isdir == 0) {
 672                 stream_name = "::$DATA";
 673                 stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
 674                 next_offset = SMB_STREAM_ENCODE_FIXED_SZ + stream_nlen +
 675                     smb_ascii_or_unicode_null_len(sr);
 676 
 677                 /* Can unnamed stream fit in response buffer? */
 678                 if (MBC_ROOM_FOR(mbc, next_offset) == 0) {
 679                         done = B_TRUE;
 680                         status = NT_STATUS_BUFFER_OVERFLOW;
 681                 } else {
 682                         /* Can first named stream fit in rsp buffer? */
 683                         if (!done && !smb_stream_fits(sr, mbc, sinfo->si_name,
 684                             next_offset)) {
 685                                 done = B_TRUE;
 686                                 status = NT_STATUS_BUFFER_OVERFLOW;
 687                         }
 688 
 689                         if (done)
 690                                 next_offset = 0;
 691 
 692                         (void) smb_mbc_encodef(mbc, "%llqqu", sr,
 693                             next_offset, stream_nlen, datasz, allocsz,
 694                             stream_name);
 695                 }
 696         }
 697 
 698         /*
 699          * If there is no next entry, or there is not enough space in
 700          * the response buffer for the next entry, the next_offset and
 701          * padding are 0.
 702          */
 703         while (!done) {
 704                 stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
 705                 sinfo_next->si_name[0] = 0;
 706 
 707                 rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos);
 708                 if ((rc != 0) || (eos)) {
 709                         done = B_TRUE;
 710                 } else {
 711                         next_offset = SMB_STREAM_ENCODE_FIXED_SZ +
 712                             stream_nlen +
 713                             smb_ascii_or_unicode_null_len(sr);
 714                         pad = smb_pad_align(next_offset, 8);
 715                         next_offset += pad;
 716 
 717                         /* Can next named stream fit in response buffer? */
 718                         if (!smb_stream_fits(sr, mbc, sinfo_next->si_name,
 719                             next_offset)) {
 720                                 done = B_TRUE;
 721                                 status = NT_STATUS_BUFFER_OVERFLOW;
 722                         }
 723                 }
 724 
 725                 if (done) {
 726                         next_offset = 0;
 727                         pad = 0;
 728                 }
 729 
 730                 (void) smb_mbc_encodef(mbc, "%llqqu#.",
 731                     sr, next_offset, stream_nlen,
 732                     sinfo->si_size, sinfo->si_alloc_size,
 733                     sinfo->si_name, pad);
 734 
 735                 (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
 736         }
 737 
 738         kmem_free(sinfo, sizeof (smb_streaminfo_t));
 739         kmem_free(sinfo_next, sizeof (smb_streaminfo_t));
 740         if (od) {
 741                 smb_odir_close(od);
 742                 smb_odir_release(od);
 743         }
 744 
 745         return (status);
 746 }
 747 
 748 /*
 749  * smb_stream_fits
 750  *
 751  * Check if the named stream entry can fit in the response buffer.
 752  *
 753  * Required space =
 754  *      offset (size of current entry)
 755  *      + SMB_STREAM_ENCODE_FIXED_SIZE
 756  *      + length of encoded stream name
 757  *      + length of null terminator
 758  *      + alignment padding
 759  */
 760 static boolean_t
 761 smb_stream_fits(smb_request_t *sr, mbuf_chain_t *mbc,
 762         char *name, uint32_t offset)
 763 {
 764         uint32_t len, pad;
 765 
 766         len = SMB_STREAM_ENCODE_FIXED_SZ +
 767             smb_ascii_or_unicode_strlen(sr, name) +
 768             smb_ascii_or_unicode_null_len(sr);
 769         pad = smb_pad_align(len, 8);
 770         len += pad;
 771 
 772         return (MBC_ROOM_FOR(mbc, offset + len) != 0);
 773 }
 774 
 775 /*
 776  * smb_query_fileinfo
 777  *
 778  * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK
 779  * (This should become an smb_ofile / smb_node function.)
 780  */
 781 int
 782 smb_query_fileinfo(smb_request_t *sr, smb_node_t *node, uint16_t infolev,
 783     smb_queryinfo_t *qinfo)
 784 {
 785         int rc = 0;
 786 
 787         /* If shortname required but not supported -> OBJECT_NAME_NOT_FOUND */
 788         if ((infolev == SMB_QUERY_FILE_ALT_NAME_INFO) ||
 789             (infolev == SMB_FILE_ALT_NAME_INFORMATION)) {
 790                 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_SHORTNAMES)) {
 791                         smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
 792                             ERRDOS, ERROR_FILE_NOT_FOUND);
 793                         return (-1);
 794                 }
 795         }
 796 
 797         (void) bzero(qinfo, sizeof (smb_queryinfo_t));
 798 
 799         /* See: smb_query_encode_response */
 800         qinfo->qi_attr.sa_mask = SMB_AT_ALL;
 801         rc = smb_node_getattr(sr, node, sr->user_cr, sr->fid_ofile,
 802             &qinfo->qi_attr);
 803         if (rc != 0) {
 804                 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
 805                     ERRDOS, ERROR_INTERNAL_ERROR);
 806                 return (-1);
 807         }
 808 
 809         qinfo->qi_node = node;
 810         qinfo->qi_delete_on_close =
 811             (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
 812         qinfo->qi_isdir = smb_node_is_dir(node);
 813 
 814         /*
 815          * The number of links reported should be the number of
 816          * non-deleted links. Thus if delete_on_close is set,
 817          * decrement the link count.
 818          */
 819         if (qinfo->qi_delete_on_close &&
 820             qinfo->qi_attr.sa_vattr.va_nlink > 0) {
 821                 --(qinfo->qi_attr.sa_vattr.va_nlink);
 822         }
 823 
 824         /*
 825          * populate name, namelen and shortname ONLY for the information
 826          * levels that require these fields
 827          */
 828         switch (infolev) {
 829         case SMB_QUERY_FILE_ALL_INFO:
 830         case SMB_FILE_ALL_INFORMATION:
 831                 rc = smb_query_pathname(sr, node, B_TRUE, qinfo);
 832                 break;
 833         case SMB_QUERY_FILE_NAME_INFO:
 834         case SMB_FILE_NAME_INFORMATION:
 835                 rc = smb_query_pathname(sr, node, B_FALSE, qinfo);
 836                 break;
 837         case SMB_QUERY_FILE_ALT_NAME_INFO:
 838         case SMB_FILE_ALT_NAME_INFORMATION:
 839                 smb_query_shortname(node, qinfo);
 840                 break;
 841         default:
 842                 break;
 843         }
 844 
 845         if (rc != 0) {
 846                 smbsr_errno(sr, rc);
 847                 return (-1);
 848         }
 849         return (0);
 850 }
 851 
 852 /*
 853  * smb_query_pathname
 854  *
 855  * Determine the absolute pathname of 'node' within the share.
 856  * For some levels (e.g. ALL_INFO) the pathname should include the
 857  * sharename for others (e.g. NAME_INFO) the pathname should be
 858  * relative to the share.
 859  * For example if the node represents file "test1.txt" in directory
 860  * "dir1" on share "share1"
 861  * - if include_share is TRUE the pathname would be: \share1\dir1\test1.txt
 862  * - if include_share is FALSE the pathname would be: \dir1\test1.txt
 863  *
 864  * For some reason NT will not show the security tab in the root
 865  * directory of a mapped drive unless the filename length is greater
 866  * than one. So if the length is 1 we set it to 2 to persuade NT to
 867  * show the tab. It should be safe because of the null terminator.
 868  */
 869 static int
 870 smb_query_pathname(smb_request_t *sr, smb_node_t *node, boolean_t include_share,
 871     smb_queryinfo_t *qinfo)
 872 {
 873         smb_tree_t *tree = sr->tid_tree;
 874         char *buf = qinfo->qi_name;
 875         size_t buflen = MAXPATHLEN;
 876         size_t len;
 877         int rc;
 878 
 879         if (include_share) {
 880                 len = snprintf(buf, buflen, "\\%s", tree->t_sharename);
 881                 if (len == (buflen - 1))
 882                         return (ENAMETOOLONG);
 883 
 884                 buf += len;
 885                 buflen -= len;
 886         }
 887 
 888         if (node == tree->t_snode) {
 889                 if (!include_share)
 890                         (void) strlcpy(buf, "\\", buflen);
 891                 return (0);
 892         }
 893 
 894         rc =  smb_node_getshrpath(node, tree, buf, buflen);
 895         if (rc == 0) {
 896                 qinfo->qi_namelen =
 897                     smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
 898                 if (qinfo->qi_namelen == 1)
 899                         qinfo->qi_namelen = 2;
 900         }
 901         return (rc);
 902 }
 903 
 904 /*
 905  * smb_query_shortname
 906  *
 907  * If the node is a named stream, use its associated
 908  * unnamed stream name to determine the shortname.
 909  * If a shortname is required (smb_needs_mangle()), generate it
 910  * using smb_mangle(), otherwise, convert the original name to
 911  * upper-case and return it as the alternative name.
 912  */
 913 void
 914 smb_query_shortname(smb_node_t *node, smb_queryinfo_t *qinfo)
 915 {
 916         char *namep;
 917 
 918         if (SMB_IS_STREAM(node))
 919                 namep = node->n_unode->od_name;
 920         else
 921                 namep = node->od_name;
 922 
 923         if (smb_needs_mangled(namep)) {
 924                 smb_mangle(namep, qinfo->qi_attr.sa_vattr.va_nodeid,
 925                     qinfo->qi_shortname, SMB_SHORTNAMELEN);
 926         } else {
 927                 (void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN);
 928                 (void) smb_strupr(qinfo->qi_shortname);
 929         }
 930 }
 931 
 932 /*
 933  * smb_query_pipeinfo
 934  *
 935  * Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE
 936  * (This should become an smb_opipe function.)
 937  */
 938 static int
 939 smb_query_pipeinfo(smb_request_t *sr, smb_opipe_t *opipe, uint16_t infolev,
 940     smb_queryinfo_t *qinfo)
 941 {
 942         char *namep = opipe->p_name;
 943 
 944         (void) bzero(qinfo, sizeof (smb_queryinfo_t));
 945         qinfo->qi_node = NULL;
 946         qinfo->qi_attr.sa_vattr.va_nlink = 1;
 947         qinfo->qi_delete_on_close = 1;
 948         qinfo->qi_isdir = 0;
 949 
 950         if ((infolev == SMB_INFO_STANDARD) ||
 951             (infolev == SMB_INFO_QUERY_EA_SIZE) ||
 952             (infolev == SMB_QUERY_INFORMATION2)) {
 953                 qinfo->qi_attr.sa_dosattr = 0;
 954         } else {
 955                 qinfo->qi_attr.sa_dosattr = FILE_ATTRIBUTE_NORMAL;
 956         }
 957 
 958         /* If the leading \ is missing from the pipe name, add it. */
 959         if (*namep != '\\')
 960                 (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep);
 961         else
 962                 (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN);
 963 
 964         qinfo->qi_namelen=
 965             smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
 966 
 967         return (0);
 968 }
 969 
 970 /*
 971  * smb_query_pipe_valid_infolev
 972  *
 973  * If the infolev is not valid for a message pipe, the error
 974  * information is set in sr and B_FALSE is returned.
 975  * Otherwise, returns B_TRUE.
 976  */
 977 static boolean_t
 978 smb_query_pipe_valid_infolev(smb_request_t *sr, uint16_t infolev)
 979 {
 980         switch (infolev) {
 981         case SMB_INFO_QUERY_ALL_EAS:
 982                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 983                     ERRDOS, ERROR_ACCESS_DENIED);
 984                 return (B_FALSE);
 985 
 986         case SMB_QUERY_FILE_ALT_NAME_INFO:
 987         case SMB_FILE_ALT_NAME_INFORMATION:
 988         case SMB_QUERY_FILE_STREAM_INFO:
 989         case SMB_FILE_STREAM_INFORMATION:
 990         case SMB_QUERY_FILE_COMPRESSION_INFO:
 991         case SMB_FILE_COMPRESSION_INFORMATION:
 992         case SMB_FILE_NETWORK_OPEN_INFORMATION:
 993         case SMB_FILE_ATTR_TAG_INFORMATION:
 994                 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
 995                     ERRDOS, ERROR_INVALID_PARAMETER);
 996                 return (B_FALSE);
 997         }
 998 
 999         return (B_TRUE);
1000 }