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