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  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 #include <smbsrv/smb_kproto.h>
  27 #include <smbsrv/smb_fsops.h>
  28 #include <smbsrv/smbinfo.h>
  29 
  30 static int smb_trans2_set_fs_ctrl_info(smb_request_t *, smb_xa_t *);
  31 
  32 /*
  33  * smb_com_query_information_disk
  34  *
  35  * The SMB_COM_QUERY_INFORMATION_DISK command is used to determine the
  36  * capacity and remaining free space on the drive hosting the directory
  37  * structure indicated by Tid in the SMB header.
  38  *
  39  * The blocking/allocation units used in this response may be independent
  40  * of the actual physical or logical blocking/allocation algorithm(s) used
  41  * internally by the server.  However, they must accurately reflect the
  42  * amount of space on the server.
  43  *
  44  * This SMB only returns 16 bits of information for each field, which may
  45  * not be large enough for some disk systems.  In particular TotalUnits is
  46  * commonly > 64K.  Fortunately, it turns out the all the client cares
  47  * about is the total disk size, in bytes, and the free space, in bytes.
  48  * So,  it is reasonable for a server to adjust the relative values of
  49  * BlocksPerUnit and BlockSize to accommodate.  If after all adjustment,
  50  * the numbers are still too high, the largest possible values for
  51  * TotalUnit or FreeUnits (i.e. 0xFFFF) should be returned.
  52  */
  53 
  54 smb_sdrc_t
  55 smb_pre_query_information_disk(smb_request_t *sr)
  56 {
  57         DTRACE_SMB_1(op__QueryInformationDisk__start, smb_request_t *, sr);
  58         return (SDRC_SUCCESS);
  59 }
  60 
  61 void
  62 smb_post_query_information_disk(smb_request_t *sr)
  63 {
  64         DTRACE_SMB_1(op__QueryInformationDisk__done, smb_request_t *, sr);
  65 }
  66 
  67 smb_sdrc_t
  68 smb_com_query_information_disk(smb_request_t *sr)
  69 {
  70         int                     rc;
  71         fsblkcnt64_t            total_blocks, free_blocks;
  72         unsigned long           block_size, unit_size;
  73         unsigned short          blocks_per_unit, bytes_per_block;
  74         unsigned short          total_units, free_units;
  75         smb_fssize_t            fssize;
  76 
  77         if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
  78                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
  79                 return (SDRC_ERROR);
  80         }
  81 
  82         if (smb_fssize(sr, &fssize) != 0)
  83                 return (SDRC_ERROR);
  84 
  85         unit_size = fssize.fs_sectors_per_unit;
  86         block_size = fssize.fs_bytes_per_sector;
  87         total_blocks = fssize.fs_caller_units;
  88         free_blocks = fssize.fs_caller_avail;
  89 
  90         /*
  91          * It seems that DOS clients cannot handle block sizes
  92          * bigger than 512 KB. So we have to set the block size at
  93          * most to 512
  94          */
  95         while (block_size > 512) {
  96                 block_size >>= 1;
  97                 unit_size <<= 1;
  98         }
  99 
 100         /* adjust blocks and sizes until they fit into a word */
 101         while (total_blocks >= 0xFFFF) {
 102                 total_blocks >>= 1;
 103                 free_blocks >>= 1;
 104                 if ((unit_size <<= 1) > 0xFFFF) {
 105                         unit_size >>= 1;
 106                         total_blocks = 0xFFFF;
 107                         free_blocks <<= 1;
 108                         break;
 109                 }
 110         }
 111 
 112         total_units = (total_blocks >= 0xFFFF) ?
 113             0xFFFF : (unsigned short)total_blocks;
 114         free_units = (free_blocks >= 0xFFFF) ?
 115             0xFFFF : (unsigned short)free_blocks;
 116         bytes_per_block = (unsigned short)block_size;
 117         blocks_per_unit = (unsigned short)unit_size;
 118 
 119         rc = smbsr_encode_result(sr, 5, 0, "bwwww2.w",
 120             5,
 121             total_units,        /* total_units */
 122             blocks_per_unit,    /* blocks_per_unit */
 123             bytes_per_block,    /* blocksize */
 124             free_units,         /* free_units */
 125             0);                 /* bcc */
 126 
 127         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 128 }
 129 
 130 /*
 131  * smb_com_trans2_query_fs_information
 132  *
 133  * This transaction requests information about the filesystem.
 134  * The following information levels are supported:
 135  *
 136  *  InformationLevel                    Value
 137  *  ==================================  ======
 138  *  SMB_INFO_ALLOCATION                 1
 139  *  SMB_INFO_VOLUME                     2
 140  *  SMB_QUERY_FS_VOLUME_INFO            0x102
 141  *  SMB_QUERY_FS_SIZE_INFO              0x103
 142  *  SMB_QUERY_FS_DEVICE_INFO            0x104
 143  *  SMB_QUERY_FS_ATTRIBUTE_INFO         0x105
 144  *  SMB_FILE_FS_VOLUME_INFORMATION      1001
 145  *  SMB_FILE_FS_SIZE_INFORMATION        1003
 146  *  SMB_FILE_FS_DEVICE_INFORMATION      1004
 147  *  SMB_FILE_FS_ATTRIBUTE_INFORMATION   1005
 148  *  SMB_FILE_FS_CONTROL_INFORMATION     1006
 149  *  SMB_FILE_FS_FULLSIZE_INFORMATION    1007
 150  *
 151  * The fsid provides a system-wide unique file system ID.
 152  * fsid.val[0] is the 32-bit dev for the file system of the share root
 153  * smb_node.
 154  * fsid.val[1] is the file system type.
 155  */
 156 smb_sdrc_t
 157 smb_com_trans2_query_fs_information(smb_request_t *sr, smb_xa_t *xa)
 158 {
 159         uint32_t                flags;
 160         char                    *encode_str, *tmpbuf;
 161         uint64_t                max_int;
 162         uint16_t                infolev;
 163         int                     rc, length, buflen;
 164         smb_tree_t              *tree;
 165         smb_node_t              *snode;
 166         char                    *fsname = "NTFS";
 167         fsid_t                  fsid;
 168         smb_fssize_t            fssize;
 169         smb_msgbuf_t            mb;
 170 
 171         tree = sr->tid_tree;
 172 
 173         if (!STYPE_ISDSK(tree->t_res_type)) {
 174                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 175                     ERRDOS, ERROR_ACCESS_DENIED);
 176                 return (SDRC_ERROR);
 177         }
 178 
 179         if (smb_mbc_decodef(&xa->req_param_mb, "w", &infolev) != 0)
 180                 return (SDRC_ERROR);
 181 
 182         snode = tree->t_snode;
 183         fsid = SMB_NODE_FSID(snode);
 184 
 185         switch (infolev) {
 186         case SMB_INFO_ALLOCATION:
 187                 if (smb_fssize(sr, &fssize) != 0)
 188                         return (SDRC_ERROR);
 189 
 190                 max_int = (uint64_t)UINT_MAX;
 191                 if (fssize.fs_caller_units > max_int)
 192                         fssize.fs_caller_units = max_int;
 193                 if (fssize.fs_caller_avail > max_int)
 194                         fssize.fs_caller_avail = max_int;
 195 
 196                 (void) smb_mbc_encodef(&xa->rep_data_mb, "llllw",
 197                     0,
 198                     fssize.fs_sectors_per_unit,
 199                     fssize.fs_caller_units,
 200                     fssize.fs_caller_avail,
 201                     fssize.fs_bytes_per_sector);
 202                 break;
 203 
 204         case SMB_INFO_VOLUME:
 205                 /*
 206                  * In this response, the unicode volume label is NOT
 207                  * expected to be aligned. Encode ('U') into a temporary
 208                  * buffer, then encode buffer as a byte stream ('#c').
 209                  */
 210                 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) ||
 211                     (sr->session->native_os == NATIVE_OS_WIN95)) {
 212                         length = smb_wcequiv_strlen(tree->t_volume);
 213                         buflen = length + sizeof (smb_wchar_t);
 214                         tmpbuf = smb_srm_zalloc(sr, buflen);
 215                         smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen,
 216                             SMB_MSGBUF_UNICODE);
 217                         rc = smb_msgbuf_encode(&mb, "U", tree->t_volume);
 218                         if (rc >= 0) {
 219                                 rc = smb_mbc_encodef(&xa->rep_data_mb,
 220                                     "%lb#c", sr, fsid.val[0],
 221                                     length, length, tmpbuf);
 222                         }
 223                         smb_msgbuf_term(&mb);
 224                 } else {
 225                         length = strlen(tree->t_volume);
 226                         rc = smb_mbc_encodef(&xa->rep_data_mb, "%lbs", sr,
 227                             fsid.val[0], length, tree->t_volume);
 228                 }
 229 
 230                 if (rc < 0)
 231                         return (SDRC_ERROR);
 232                 break;
 233 
 234         case SMB_QUERY_FS_VOLUME_INFO:
 235         case SMB_FILE_FS_VOLUME_INFORMATION:
 236                 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) ||
 237                     (sr->session->native_os == NATIVE_OS_WIN95)) {
 238                         length = smb_wcequiv_strlen(tree->t_volume);
 239                         encode_str = "%qllb.U";
 240                 } else {
 241                         length = strlen(tree->t_volume);
 242                         encode_str = "%qllb.s";
 243                 }
 244 
 245                 /*
 246                  * NT has the "supports objects" flag set to 1.
 247                  */
 248                 (void) smb_mbc_encodef(&xa->rep_data_mb, encode_str, sr,
 249                     0ll,                        /* Volume creation time */
 250                     fsid.val[0],                /* Volume serial number */
 251                     length,                     /* label length */
 252                     0,                          /* Supports objects */
 253                     tree->t_volume);
 254                 break;
 255 
 256         case SMB_QUERY_FS_SIZE_INFO:
 257         case SMB_FILE_FS_SIZE_INFORMATION:
 258                 if (smb_fssize(sr, &fssize) != 0)
 259                         return (SDRC_ERROR);
 260 
 261                 (void) smb_mbc_encodef(&xa->rep_data_mb, "qqll",
 262                     fssize.fs_caller_units,
 263                     fssize.fs_caller_avail,
 264                     fssize.fs_sectors_per_unit,
 265                     fssize.fs_bytes_per_sector);
 266                 break;
 267 
 268         case SMB_QUERY_FS_DEVICE_INFO:
 269         case SMB_FILE_FS_DEVICE_INFORMATION:
 270                 (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
 271                     FILE_DEVICE_FILE_SYSTEM,
 272                     FILE_DEVICE_IS_MOUNTED);
 273                 break;
 274 
 275         case SMB_QUERY_FS_ATTRIBUTE_INFO:
 276         case SMB_FILE_FS_ATTRIBUTE_INFORMATION:
 277                 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) ||
 278                     (sr->session->native_os == NATIVE_OS_WINNT) ||
 279                     (sr->session->native_os == NATIVE_OS_WIN2000) ||
 280                     (sr->session->native_os == NATIVE_OS_WIN95) ||
 281                     (sr->session->native_os == NATIVE_OS_MACOS)) {
 282                         length = smb_wcequiv_strlen(fsname);
 283                         encode_str = "%lllU";
 284                         sr->smb_flg2 |= SMB_FLAGS2_UNICODE;
 285                 } else {
 286                         length = strlen(fsname);
 287                         encode_str = "%llls";
 288                 }
 289 
 290                 flags = FILE_CASE_PRESERVED_NAMES;
 291 
 292                 if (tree->t_flags & SMB_TREE_UNICODE_ON_DISK)
 293                         flags |= FILE_UNICODE_ON_DISK;
 294 
 295                 if (tree->t_flags & SMB_TREE_SUPPORTS_ACLS)
 296                         flags |= FILE_PERSISTENT_ACLS;
 297 
 298                 if ((tree->t_flags & SMB_TREE_CASEINSENSITIVE) == 0)
 299                         flags |= FILE_CASE_SENSITIVE_SEARCH;
 300 
 301                 if (tree->t_flags & SMB_TREE_STREAMS)
 302                         flags |= FILE_NAMED_STREAMS;
 303 
 304                 if (tree->t_flags & SMB_TREE_QUOTA)
 305                         flags |= FILE_VOLUME_QUOTAS;
 306 
 307                 if (tree->t_flags & SMB_TREE_SPARSE)
 308                         flags |= FILE_SUPPORTS_SPARSE_FILES;
 309 
 310                 (void) smb_mbc_encodef(&xa->rep_data_mb, encode_str, sr,
 311                     flags,
 312                     MAXNAMELEN, /* max name */
 313                     length,     /* label length */
 314                     fsname);
 315                 break;
 316 
 317         case SMB_FILE_FS_CONTROL_INFORMATION:
 318                 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) {
 319                         smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
 320                             ERRDOS, ERROR_NOT_SUPPORTED);
 321                         return (SDRC_ERROR);
 322                 }
 323 
 324                 (void) smb_mbc_encodef(&xa->rep_data_mb, "qqqqqll",
 325                     0,          /* free space start filtering - MUST be 0 */
 326                     0,          /* free space threshold - MUST be 0 */
 327                     0,          /* free space stop filtering - MUST be 0 */
 328                     SMB_QUOTA_UNLIMITED,        /* default quota threshold */
 329                     SMB_QUOTA_UNLIMITED,        /* default quota limit */
 330                     FILE_VC_QUOTA_ENFORCE,      /* fs control flag */
 331                     0);                         /* pad bytes */
 332                 break;
 333 
 334         case SMB_FILE_FS_FULLSIZE_INFORMATION:
 335                 if (smb_fssize(sr, &fssize) != 0)
 336                         return (SDRC_ERROR);
 337 
 338                 (void) smb_mbc_encodef(&xa->rep_data_mb, "qqqll",
 339                     fssize.fs_caller_units,
 340                     fssize.fs_caller_avail,
 341                     fssize.fs_volume_avail,
 342                     fssize.fs_sectors_per_unit,
 343                     fssize.fs_bytes_per_sector);
 344                 break;
 345 
 346         case SMB_FILE_FS_LABEL_INFORMATION:
 347         case SMB_FILE_FS_OBJECTID_INFORMATION:
 348         case SMB_FILE_FS_DRIVERPATH_INFORMATION:
 349                 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
 350                     ERRDOS, ERROR_NOT_SUPPORTED);
 351                 return (SDRC_ERROR);
 352 
 353         default:
 354                 smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
 355                     ERRDOS, ERROR_INVALID_LEVEL);
 356                 return (SDRC_ERROR);
 357         }
 358 
 359         return (SDRC_SUCCESS);
 360 }
 361 
 362 /*
 363  * smb_fssize
 364  *
 365  * File system size information, for the volume and for the user
 366  * initiating the request.
 367  *
 368  * If there's no quota entry for the user initiating the request,
 369  * caller_units and caller_avail are the total and available units
 370  * for the volume (volume_units, volume_avail).
 371  * If there is a quota entry for the user initiating the request,
 372  * and it is not SMB_QUOTA_UNLIMITED, calculate caller_units and
 373  * caller_avail as follows:
 374  *   caller_units = quota limit / bytes_per_unit
 375  *   caller_avail = remaining quota / bytes_per_unit
 376  *
 377  * A quota limit of SMB_QUOTA_UNLIMITED means that the user's quota
 378  * is specfied as unlimited. A quota limit of 0 means there is no
 379  * quota specified for the user.
 380  *
 381  * Returns: 0 (success) or an errno value
 382  */
 383 int
 384 smb_fssize(smb_request_t *sr, smb_fssize_t *fssize)
 385 {
 386         smb_node_t *node;
 387         struct statvfs64 df;
 388         uid_t uid;
 389         smb_quota_t quota;
 390         int spu;        /* sectors per unit */
 391         int rc;
 392 
 393         bzero(fssize, sizeof (smb_fssize_t));
 394         node = sr->tid_tree->t_snode;
 395         if ((rc = smb_fsop_statfs(sr->user_cr, node, &df)) != 0)
 396                 return (rc);
 397 
 398         if (df.f_frsize < DEV_BSIZE)
 399                 df.f_frsize = DEV_BSIZE;
 400         if (df.f_bsize < df.f_frsize)
 401                 df.f_bsize = df.f_frsize;
 402         spu = df.f_bsize / df.f_frsize;
 403 
 404         fssize->fs_bytes_per_sector = (uint16_t)df.f_frsize;
 405         fssize->fs_sectors_per_unit = spu;
 406 
 407         if (df.f_bavail > df.f_blocks)
 408                 df.f_bavail = 0;
 409 
 410         fssize->fs_volume_units = df.f_blocks / spu;
 411         fssize->fs_volume_avail = df.f_bavail / spu;
 412         fssize->fs_caller_units = df.f_blocks / spu;
 413         fssize->fs_caller_avail = df.f_bavail / spu;
 414 
 415         if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA))
 416                 return (0);
 417 
 418         uid = crgetuid(sr->uid_user->u_cred);
 419         if (smb_quota_query_user_quota(sr, uid, "a) != NT_STATUS_SUCCESS)
 420                 return (0);
 421 
 422         if ((quota.q_limit != SMB_QUOTA_UNLIMITED) && (quota.q_limit != 0)) {
 423                 fssize->fs_caller_units = quota.q_limit / df.f_bsize;
 424                 if (quota.q_limit <= quota.q_used)
 425                         fssize->fs_caller_avail = 0;
 426                 else
 427                         fssize->fs_caller_avail =
 428                             (quota.q_limit - quota.q_used) / df.f_bsize;
 429         }
 430 
 431         return (0);
 432 }
 433 
 434 /*
 435  * smb_com_trans2_set_fs_information
 436  *
 437  * This transaction sets filesystem information.
 438  * The following information levels are supported:
 439  *
 440  *  InformationLevel                    Value
 441  *  ==================================  ======
 442  *  SMB_FILE_FS_CONTROL_INFORMATION     1006
 443  */
 444 smb_sdrc_t
 445 smb_com_trans2_set_fs_information(smb_request_t *sr, smb_xa_t *xa)
 446 {
 447         smb_tree_t              *tree;
 448         uint16_t                infolev;
 449 
 450         tree = sr->tid_tree;
 451         if (!STYPE_ISDSK(tree->t_res_type)) {
 452                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 453                     ERRDOS, ERROR_ACCESS_DENIED);
 454                 return (SDRC_ERROR);
 455         }
 456 
 457         if (smb_mbc_decodef(&xa->req_param_mb, "ww",
 458             &sr->smb_fid, &infolev) != 0)
 459                 return (SDRC_ERROR);
 460 
 461         switch (infolev) {
 462         case SMB_FILE_FS_CONTROL_INFORMATION:
 463                 if (smb_trans2_set_fs_ctrl_info(sr, xa) != 0)
 464                         return (SDRC_ERROR);
 465                 break;
 466 
 467         case SMB_FILE_FS_VOLUME_INFORMATION:
 468         case SMB_FILE_FS_LABEL_INFORMATION:
 469         case SMB_FILE_FS_SIZE_INFORMATION:
 470         case SMB_FILE_FS_DEVICE_INFORMATION:
 471         case SMB_FILE_FS_ATTRIBUTE_INFORMATION:
 472         case SMB_FILE_FS_FULLSIZE_INFORMATION:
 473         case SMB_FILE_FS_OBJECTID_INFORMATION:
 474         case SMB_FILE_FS_DRIVERPATH_INFORMATION:
 475                 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
 476                     ERRDOS, ERROR_NOT_SUPPORTED);
 477                 return (SDRC_ERROR);
 478 
 479         default:
 480                 smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
 481                     ERRDOS, ERROR_INVALID_LEVEL);
 482                 return (SDRC_ERROR);
 483         }
 484 
 485         return (SDRC_SUCCESS);
 486 }
 487 
 488 /*
 489  * smb_trans2_set_fs_ctrl_info
 490  *
 491  * Only users with Admin privileges (i.e. of the BUILTIN/Administrators
 492  * group) will be allowed to set quotas.
 493  *
 494  * Currently QUOTAS are always ENFORCED and the default values
 495  * are always SMB_QUOTA_UNLIMITED (none). Any attempt to set
 496  * values other than these will result in NT_STATUS_NOT_SUPPORTED.
 497  */
 498 static int
 499 smb_trans2_set_fs_ctrl_info(smb_request_t *sr, smb_xa_t *xa)
 500 {
 501         int rc;
 502         uint64_t fstart, fthresh, fstop, qthresh, qlimit;
 503         uint32_t qctrl, qpad;
 504 
 505         if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) {
 506                 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
 507                     ERRDOS, ERROR_NOT_SUPPORTED);
 508                 return (-1);
 509         }
 510 
 511         if (!smb_user_is_admin(sr->uid_user)) {
 512                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 513                     ERRDOS, ERROR_ACCESS_DENIED);
 514                 return (-1);
 515         }
 516 
 517         rc = smb_mbc_decodef(&xa->req_data_mb, "qqqqqll", &fstart,
 518             &fthresh, &fstop, &qthresh, &qlimit, &qctrl, &qpad);
 519 
 520         if ((rc != 0) || (fstart != 0) || (fthresh != 0) || (fstop != 0)) {
 521                 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
 522                     ERRDOS, ERROR_INVALID_PARAMETER);
 523                 return (-1);
 524         }
 525 
 526         /* Only support ENFORCED quotas with UNLIMITED default */
 527         if ((qctrl != FILE_VC_QUOTA_ENFORCE) ||
 528             (qlimit != SMB_QUOTA_UNLIMITED) ||
 529             (qthresh != SMB_QUOTA_UNLIMITED)) {
 530                 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
 531                     ERRDOS, ERROR_NOT_SUPPORTED);
 532                 return (-1);
 533         }
 534 
 535         return (0);
 536 }