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