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 2017 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
30static 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
54smb_sdrc_t
55smb_pre_query_information_disk(smb_request_t *sr)
56{
57	DTRACE_SMB_START(op__QueryInformationDisk, smb_request_t *, sr);
58	return (SDRC_SUCCESS);
59}
60
61void
62smb_post_query_information_disk(smb_request_t *sr)
63{
64	DTRACE_SMB_DONE(op__QueryInformationDisk, smb_request_t *, sr);
65}
66
67smb_sdrc_t
68smb_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 */
156smb_sdrc_t
157smb_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 */
383int
384smb_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, &quota) != 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 */
444smb_sdrc_t
445smb_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 */
498static int
499smb_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