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