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