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 */
37typedef 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
60static int smb_fssize(smb_request_t *, smb_fssize_t *);
61static 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
85smb_sdrc_t
86smb_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
92void
93smb_post_query_information_disk(smb_request_t *sr)
94{
95	DTRACE_SMB_1(op__QueryInformationDisk__done, smb_request_t *, sr);
96}
97
98smb_sdrc_t
99smb_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 */
187smb_sdrc_t
188smb_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 */
415static int
416smb_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, &quota) != 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 */
472smb_sdrc_t
473smb_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 */
526static int
527smb_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