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 2019 Nexenta by DDN, Inc. All rights reserved.
24 */
25
26 /*
27 * Dispatch function for SMB2_QUERY_INFO
28 *
29 * [MS-FSCC 2.5] If a file system does not implement ...
30 * an Information Classs, NT_STATUS_INVALID_PARAMETER...
31 */
32
33 #include <smbsrv/smb2_kproto.h>
34 #include <smbsrv/smb_fsops.h>
35 #include <smbsrv/ntifs.h>
36
37 uint32_t smb2_qfs_volume(smb_request_t *);
38 uint32_t smb2_qfs_size(smb_request_t *);
39 uint32_t smb2_qfs_device(smb_request_t *);
40 uint32_t smb2_qfs_attr(smb_request_t *);
41 uint32_t smb2_qfs_control(smb_request_t *);
42 uint32_t smb2_qfs_fullsize(smb_request_t *);
43 uint32_t smb2_qfs_obj_id(smb_request_t *);
44 uint32_t smb2_qfs_sectorsize(smb_request_t *);
45
46 uint32_t
smb2_qinfo_fs(smb_request_t * sr,smb_queryinfo_t * qi)47 smb2_qinfo_fs(smb_request_t *sr, smb_queryinfo_t *qi)
48 {
49 uint32_t status;
50
51 switch (qi->qi_InfoClass) {
52
53 /* pg 153 */
54 case FileFsVolumeInformation: /* 1 */
55 status = smb2_qfs_volume(sr);
56 break;
57 case FileFsSizeInformation: /* 3 */
58 status = smb2_qfs_size(sr);
59 break;
60 case FileFsDeviceInformation: /* 4 */
61 status = smb2_qfs_device(sr);
62 break;
63 case FileFsAttributeInformation: /* 5 */
64 status = smb2_qfs_attr(sr);
65 break;
66 case FileFsControlInformation: /* 6 */
67 status = smb2_qfs_control(sr);
68 break;
69 case FileFsFullSizeInformation: /* 7 */
70 status = smb2_qfs_fullsize(sr);
71 break;
72 case FileFsObjectIdInformation: /* 8 */
73 status = smb2_qfs_obj_id(sr);
74 break;
75 case FileFsDriverPathInformation: /* 9 */
76 case FileFsVolumeFlagsInformation: /* A */
77 status = NT_STATUS_INVALID_INFO_CLASS;
78 break;
79 case FileFsSectorSizeInformation: /* B */
80 status = smb2_qfs_sectorsize(sr);
81 break;
82 default: /* there are some infoclasses we don't yet handle */
83 status = NT_STATUS_INVALID_INFO_CLASS;
84 #ifdef DEBUG
85 cmn_err(CE_NOTE, "unknown InfoClass 0x%x", qi->qi_InfoClass);
86 #endif
87 break;
88 }
89
90 return (status);
91 }
92
93 /*
94 * FileFsVolumeInformation
95 */
96 uint32_t
smb2_qfs_volume(smb_request_t * sr)97 smb2_qfs_volume(smb_request_t *sr)
98 {
99 smb_tree_t *tree = sr->tid_tree;
100 smb_node_t *snode;
101 fsid_t fsid;
102 uint32_t LabelLength;
103 int rc;
104
105 if (!STYPE_ISDSK(tree->t_res_type))
106 return (NT_STATUS_INVALID_PARAMETER);
107
108 snode = tree->t_snode;
109 fsid = SMB_NODE_FSID(snode);
110
111 LabelLength = smb_wcequiv_strlen(tree->t_volume);
112
113 /*
114 * NT has the "supports objects" flag set to 1.
115 */
116 rc = smb_mbc_encodef(
117 &sr->raw_data, "Tllb.U",
118 &tree->t_create_time, /* (T) */
119 fsid.val[0], /* serial no. (l) */
120 LabelLength, /* (l) */
121 0, /* Supports objects (b) */
122 /* reserved (.) */
123 tree->t_volume); /* (U) */
124 if (rc != 0)
125 return (NT_STATUS_BUFFER_OVERFLOW);
126
127 return (0);
128 }
129
130 /*
131 * FileFsSizeInformation
132 */
133 uint32_t
smb2_qfs_size(smb_request_t * sr)134 smb2_qfs_size(smb_request_t *sr)
135 {
136 smb_fssize_t fssize;
137 smb_tree_t *tree = sr->tid_tree;
138 int rc;
139
140 if (!STYPE_ISDSK(tree->t_res_type))
141 return (NT_STATUS_INVALID_PARAMETER);
142
143 rc = smb_fssize(sr, &fssize);
144 if (rc)
145 return (smb_errno2status(rc));
146
147 rc = smb_mbc_encodef(
148 &sr->raw_data, "qqll",
149 fssize.fs_caller_units,
150 fssize.fs_caller_avail,
151 fssize.fs_sectors_per_unit,
152 fssize.fs_bytes_per_sector);
153 if (rc != 0)
154 return (NT_STATUS_BUFFER_OVERFLOW);
155
156 return (0);
157 }
158
159 /*
160 * FileFsFullSizeInformation
161 */
162 uint32_t
smb2_qfs_fullsize(smb_request_t * sr)163 smb2_qfs_fullsize(smb_request_t *sr)
164 {
165 smb_fssize_t fssize;
166 smb_tree_t *tree = sr->tid_tree;
167 int rc;
168
169 if (!STYPE_ISDSK(tree->t_res_type))
170 return (NT_STATUS_INVALID_PARAMETER);
171
172 rc = smb_fssize(sr, &fssize);
173 if (rc)
174 return (smb_errno2status(rc));
175
176 rc = smb_mbc_encodef(
177 &sr->raw_data, "qqqll",
178 fssize.fs_caller_units,
179 fssize.fs_caller_avail,
180 fssize.fs_volume_avail,
181 fssize.fs_sectors_per_unit,
182 fssize.fs_bytes_per_sector);
183 if (rc != 0)
184 return (NT_STATUS_BUFFER_OVERFLOW);
185
186 return (0);
187 }
188
189 /*
190 * FileFsDeviceInformation
191 */
192 uint32_t
smb2_qfs_device(smb_request_t * sr)193 smb2_qfs_device(smb_request_t *sr)
194 {
195 smb_tree_t *tree = sr->tid_tree;
196 uint32_t DeviceType;
197 uint32_t Characteristics;
198 int rc;
199
200 if (!STYPE_ISDSK(tree->t_res_type))
201 return (NT_STATUS_INVALID_PARAMETER);
202
203 DeviceType = FILE_DEVICE_DISK;
204 Characteristics = FILE_DEVICE_IS_MOUNTED;
205
206 rc = smb_mbc_encodef(
207 &sr->raw_data, "ll",
208 DeviceType,
209 Characteristics);
210 if (rc != 0)
211 return (NT_STATUS_BUFFER_OVERFLOW);
212
213 return (0);
214 }
215
216 /*
217 * FileFsAttributeInformation
218 */
219 uint32_t
smb2_qfs_attr(smb_request_t * sr)220 smb2_qfs_attr(smb_request_t *sr)
221 {
222 smb_tree_t *tree = sr->tid_tree;
223 char *fsname;
224 uint32_t namelen;
225 uint32_t FsAttr;
226 int rc;
227
228 /* This call is OK on all tree types. */
229 switch (tree->t_res_type & STYPE_MASK) {
230 case STYPE_IPC:
231 fsname = "PIPE";
232 break;
233 case STYPE_DISKTREE:
234 fsname = "NTFS"; /* A lie, but compatible... */
235 break;
236 case STYPE_PRINTQ:
237 case STYPE_DEVICE:
238 default: /* gcc -Wuninitialized */
239 return (NT_STATUS_INVALID_PARAMETER);
240 }
241 namelen = smb_wcequiv_strlen(fsname);
242
243 /*
244 * Todo: Store the FsAttributes in the tree object,
245 * then just return that directly here.
246 */
247 FsAttr = FILE_CASE_PRESERVED_NAMES;
248 if (tree->t_flags & SMB_TREE_UNICODE_ON_DISK)
249 FsAttr |= FILE_UNICODE_ON_DISK;
250 if (tree->t_flags & SMB_TREE_SUPPORTS_ACLS)
251 FsAttr |= FILE_PERSISTENT_ACLS;
252 if ((tree->t_flags & SMB_TREE_CASEINSENSITIVE) == 0)
253 FsAttr |= FILE_CASE_SENSITIVE_SEARCH;
254 if (tree->t_flags & SMB_TREE_STREAMS)
255 FsAttr |= FILE_NAMED_STREAMS;
256 if (tree->t_flags & SMB_TREE_QUOTA)
257 FsAttr |= FILE_VOLUME_QUOTAS;
258 if (tree->t_flags & SMB_TREE_SPARSE)
259 FsAttr |= FILE_SUPPORTS_SPARSE_FILES;
260
261 rc = smb_mbc_encodef(
262 &sr->raw_data, "lllU",
263 FsAttr,
264 MAXNAMELEN-1,
265 namelen,
266 fsname);
267 if (rc != 0)
268 return (NT_STATUS_BUFFER_OVERFLOW);
269
270 return (0);
271 }
272
273 /*
274 * FileFsControlInformation
275 */
276 uint32_t
smb2_qfs_control(smb_request_t * sr)277 smb2_qfs_control(smb_request_t *sr)
278 {
279 smb_tree_t *tree = sr->tid_tree;
280 int rc;
281
282 if (!STYPE_ISDSK(tree->t_res_type))
283 return (NT_STATUS_INVALID_PARAMETER);
284 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) {
285 /*
286 * Strange error per. [MS-FSCC 2.5.2]
287 * which means quotas not supported.
288 */
289 return (NT_STATUS_VOLUME_NOT_UPGRADED);
290 }
291
292 rc = smb_mbc_encodef(
293 &sr->raw_data, "qqqqqll",
294 0, /* free space start filtering - MUST be 0 */
295 0, /* free space threshold - MUST be 0 */
296 0, /* free space stop filtering - MUST be 0 */
297 SMB_QUOTA_UNLIMITED, /* default quota threshold */
298 SMB_QUOTA_UNLIMITED, /* default quota limit */
299 FILE_VC_QUOTA_ENFORCE, /* fs control flag */
300 0); /* pad bytes */
301 if (rc != 0)
302 return (NT_STATUS_BUFFER_OVERFLOW);
303
304 return (0);
305 }
306
307 /*
308 * FileFsObjectIdInformation
309 */
310 /* ARGSUSED */
311 uint32_t
smb2_qfs_obj_id(smb_request_t * sr)312 smb2_qfs_obj_id(smb_request_t *sr)
313 {
314 return (NT_STATUS_INVALID_PARAMETER);
315 }
316
317 /*
318 * Not sure yet where these should go.
319 * Flags in FileFsSectorSizeInformation
320 */
321
322 #define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001
323 // When set, this flag indicates that the first physical sector of the device
324 // is aligned with the first logical sector. When not set, the first physical
325 // sector of the device is misaligned with the first logical sector.
326
327 #define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002
328 // When set, this flag indicates that the partition is aligned to physical
329 // sector boundaries on the storage device.
330
331 #define SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004
332 // When set, the device reports that it does not incur a seek penalty (this
333 // typically indicates that the device does not have rotating media, such as
334 // flash-based disks).
335
336 #define SSINFO_FLAGS_TRIM_ENABLED 0x00000008
337 // When set, the device supports TRIM operations, either T13 (ATA) TRIM or
338 // T10 (SCSI/SAS) UNMAP.
339
340 #define SSINFO_OFFSET_UNKNOWN 0xffffffff
341 // For "Alignment" fields below
342
343 /*
344 * We have to lie to Windows Hyper-V about our logical record size,
345 * because with larger sizes it fails setting up a virtual disk.
346 */
347 int smb2_max_logical_sector_size = 4096;
348
349 /*
350 * FileFsSectorSizeInformation
351 *
352 * Returns a FILE_FS_SECTOR_SIZE_INFORMATION
353 * See: [MS-FSCC] 2.5.8 FileFsSizeInformation
354 *
355 * LogicalBytesPerSector (4 bytes): ... number of bytes in a logical sector
356 * for the device backing the volume. This field is the unit of logical
357 * addressing for the device and is not the unit of atomic write.
358 * PhysicalBytesPerSectorForAtomicity (4 bytes): ... number of bytes in a
359 * physical sector for the device backing the volume. This is the reported
360 * physical sector size of the device and is the unit of atomic write.
361 * PhysicalBytesPerSectorForPerformance (4 bytes): ... number of bytes in a
362 * physical sector for the device backing the volume. This is the reported
363 * physical sector size of the device and is the unit of performance.
364 * FileSystemEffectivePhysicalBytesPerSectorForAtomicity (4 bytes): unit, in
365 * bytes, that the file system on the volume will use for internal operations
366 * that require alignment and atomicity.
367 * Flags (4 bytes): See ...
368 * ByteOffsetForSectorAlignment (4 bytes): ... logical sector offset within the
369 * first physical sector where the first logical sector is placed, in bytes.
370 * If this value is set to SSINFO_OFFSET_UNKNOWN (0xffffffff), there was
371 * insufficient information to compute this field.
372 * ByteOffsetForPartitionAlignment (4 bytes): ... byte offset from the first
373 * physical sector where the first partition is placed. If this value is
374 * set to SSINFO_OFFSET_UNKNOWN (0xffffffff), there was either insufficient
375 * information or an error was encountered in computing this field.
376 */
377 uint32_t
smb2_qfs_sectorsize(smb_request_t * sr)378 smb2_qfs_sectorsize(smb_request_t *sr)
379 {
380 smb_fssize_t fssize;
381 smb_tree_t *tree = sr->tid_tree;
382 uint32_t lbps, pbps;
383 uint32_t flags, unk;
384 int rc;
385
386 if (!STYPE_ISDSK(tree->t_res_type))
387 return (NT_STATUS_INVALID_PARAMETER);
388
389 rc = smb_fssize(sr, &fssize);
390 if (rc)
391 return (smb_errno2status(rc));
392
393 // PhysicalBytesPerSector
394 pbps = fssize.fs_bytes_per_sector;
395
396 // LogicalBytesPerSector
397 lbps = fssize.fs_sectors_per_unit * pbps;
398 if (lbps > smb2_max_logical_sector_size)
399 lbps = smb2_max_logical_sector_size;
400
401 // Flags
402 // We include "no seek penalty" because our files are
403 // always ZFS-backed, which can reorder things on disk.
404 // Leaving out SSINFO_FLAGS_TRIM_ENABLED for now.
405 flags = SSINFO_FLAGS_ALIGNED_DEVICE |
406 SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE |
407 SSINFO_FLAGS_NO_SEEK_PENALTY;
408
409 // ByteOffsetForSectorAlignment
410 // ByteOffsetForPartitionAlignment
411 // Just say "unknown" for these two.
412 unk = SSINFO_OFFSET_UNKNOWN;
413
414 rc = smb_mbc_encodef(
415 &sr->raw_data,
416 "lllllll",
417 lbps, // LogicalBytesPerSector
418 pbps, // PhysicalBytesPerSectorForAtomicity
419 lbps, // PhysicalBytesPerSectorForPerformance
420 pbps, // FileSystemEffectivePhysicalBytesPerSectorForAtomicity
421 flags,
422 unk, unk);
423
424 if (rc != 0)
425 return (NT_STATUS_BUFFER_OVERFLOW);
426
427 return (0);
428 }
429