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
smb_pre_query_information_disk(smb_request_t * sr)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
smb_post_query_information_disk(smb_request_t * sr)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
smb_com_query_information_disk(smb_request_t * sr)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
smb_com_trans2_query_fs_information(smb_request_t * sr,smb_xa_t * xa)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
smb_fssize(smb_request_t * sr,smb_fssize_t * fssize)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
smb_com_trans2_set_fs_information(smb_request_t * sr,smb_xa_t * xa)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
smb_trans2_set_fs_ctrl_info(smb_request_t * sr,smb_xa_t * xa)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