1*a90cf9f2SGordon Ross /*
2*a90cf9f2SGordon Ross  * CDDL HEADER START
3*a90cf9f2SGordon Ross  *
4*a90cf9f2SGordon Ross  * The contents of this file are subject to the terms of the
5*a90cf9f2SGordon Ross  * Common Development and Distribution License (the "License").
6*a90cf9f2SGordon Ross  * You may not use this file except in compliance with the License.
7*a90cf9f2SGordon Ross  *
8*a90cf9f2SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*a90cf9f2SGordon Ross  * or http://www.opensolaris.org/os/licensing.
10*a90cf9f2SGordon Ross  * See the License for the specific language governing permissions
11*a90cf9f2SGordon Ross  * and limitations under the License.
12*a90cf9f2SGordon Ross  *
13*a90cf9f2SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14*a90cf9f2SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*a90cf9f2SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16*a90cf9f2SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17*a90cf9f2SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18*a90cf9f2SGordon Ross  *
19*a90cf9f2SGordon Ross  * CDDL HEADER END
20*a90cf9f2SGordon Ross  */
21*a90cf9f2SGordon Ross 
22*a90cf9f2SGordon Ross /*
23*a90cf9f2SGordon Ross  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*a90cf9f2SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
25*a90cf9f2SGordon Ross  */
26*a90cf9f2SGordon Ross 
27*a90cf9f2SGordon Ross #include <smbsrv/smb_kproto.h>
28*a90cf9f2SGordon Ross #include <smbsrv/smb_fsops.h>
29*a90cf9f2SGordon Ross #include <smbsrv/smb_share.h>
30*a90cf9f2SGordon Ross #include <smbsrv/string.h>
31*a90cf9f2SGordon Ross #include <sys/fs/zfs.h>
32*a90cf9f2SGordon Ross #include <smbsrv/smb_xdr.h>
33*a90cf9f2SGordon Ross #include <smbsrv/smb_door.h>
34*a90cf9f2SGordon Ross #include <smbsrv/smb_idmap.h>
35*a90cf9f2SGordon Ross 
36*a90cf9f2SGordon Ross /*
37*a90cf9f2SGordon Ross  * A user/group quota entry passed over the wire consists of:
38*a90cf9f2SGordon Ross  * - next offset (uint32_t)
39*a90cf9f2SGordon Ross  * - length of SID (uint32_t)
40*a90cf9f2SGordon Ross  * - last modified time (uint64_t)
41*a90cf9f2SGordon Ross  * - quota used (uint64_t)
42*a90cf9f2SGordon Ross  * - quota limit (uint64_t)
43*a90cf9f2SGordon Ross  * - quota threahold (uint64_t)
44*a90cf9f2SGordon Ross  * - variable length sid - max = 32 bytes
45*a90cf9f2SGordon Ross  * SMB_QUOTA_SIZE_NO_SID is the size of the above, excluding the sid.
46*a90cf9f2SGordon Ross  */
47*a90cf9f2SGordon Ross #define	SMB_QUOTA_SIZE_NO_SID \
48*a90cf9f2SGordon Ross 	((2 * sizeof (uint32_t)) + (4 * sizeof (uint64_t)))
49*a90cf9f2SGordon Ross #define	SMB_QUOTA_EST_SIZE (SMB_QUOTA_SIZE_NO_SID + SMB_EST_SID_SIZE)
50*a90cf9f2SGordon Ross #define	SMB_QUOTA_MAX_SIZE (SMB_QUOTA_SIZE_NO_SID + SMB_MAX_SID_SIZE)
51*a90cf9f2SGordon Ross 
52*a90cf9f2SGordon Ross 
53*a90cf9f2SGordon Ross /*
54*a90cf9f2SGordon Ross  * smb_quota_init_sids
55*a90cf9f2SGordon Ross  *
56*a90cf9f2SGordon Ross  * If the query is of type SMB_QUOTA_QUERY_SIDLIST or
57*a90cf9f2SGordon Ross  * SMB_QUOTA_QUERY_STARTSID decode the list of sids from
58*a90cf9f2SGordon Ross  * the client request into request->qq_sid_list.
59*a90cf9f2SGordon Ross  * Otherwise (type SMB_QUOTA_QUERY_ALL) find the resume sid
60*a90cf9f2SGordon Ross  * and insert it into request->qq_sid_list, or reset the
61*a90cf9f2SGordon Ross  * resume sid to NULL if request->qq_restart.
62*a90cf9f2SGordon Ross  *
63*a90cf9f2SGordon Ross  * Returns: NT_STATUS codes
64*a90cf9f2SGordon Ross  */
65*a90cf9f2SGordon Ross uint32_t
smb_quota_init_sids(mbuf_chain_t * mbc,smb_quota_query_t * request,smb_ofile_t * ofile)66*a90cf9f2SGordon Ross smb_quota_init_sids(mbuf_chain_t *mbc, smb_quota_query_t *request,
67*a90cf9f2SGordon Ross     smb_ofile_t *ofile)
68*a90cf9f2SGordon Ross {
69*a90cf9f2SGordon Ross 	smb_quota_sid_t *sid;
70*a90cf9f2SGordon Ross 	list_t *sid_list;
71*a90cf9f2SGordon Ross 	uint32_t status = NT_STATUS_SUCCESS;
72*a90cf9f2SGordon Ross 
73*a90cf9f2SGordon Ross 	sid_list = &request->qq_sid_list;
74*a90cf9f2SGordon Ross 	list_create(sid_list, sizeof (smb_quota_sid_t),
75*a90cf9f2SGordon Ross 	    offsetof(smb_quota_sid_t, qs_list_node));
76*a90cf9f2SGordon Ross 
77*a90cf9f2SGordon Ross 	switch (request->qq_query_op) {
78*a90cf9f2SGordon Ross 	case SMB_QUOTA_QUERY_SIDLIST:
79*a90cf9f2SGordon Ross 	case SMB_QUOTA_QUERY_STARTSID:
80*a90cf9f2SGordon Ross 		status = smb_quota_decode_sids(mbc, sid_list);
81*a90cf9f2SGordon Ross 		break;
82*a90cf9f2SGordon Ross 	case SMB_QUOTA_QUERY_ALL:
83*a90cf9f2SGordon Ross 		if (request->qq_restart)
84*a90cf9f2SGordon Ross 			smb_ofile_set_quota_resume(ofile, NULL);
85*a90cf9f2SGordon Ross 		else {
86*a90cf9f2SGordon Ross 			sid = kmem_zalloc(sizeof (smb_quota_sid_t), KM_SLEEP);
87*a90cf9f2SGordon Ross 			list_insert_tail(sid_list, sid);
88*a90cf9f2SGordon Ross 			smb_ofile_get_quota_resume(ofile, sid->qs_sidstr,
89*a90cf9f2SGordon Ross 			    SMB_SID_STRSZ);
90*a90cf9f2SGordon Ross 			if (*sid->qs_sidstr == '\0')
91*a90cf9f2SGordon Ross 				status = NT_STATUS_INVALID_PARAMETER;
92*a90cf9f2SGordon Ross 		}
93*a90cf9f2SGordon Ross 		break;
94*a90cf9f2SGordon Ross 	default:
95*a90cf9f2SGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
96*a90cf9f2SGordon Ross 		break;
97*a90cf9f2SGordon Ross 	}
98*a90cf9f2SGordon Ross 
99*a90cf9f2SGordon Ross 	return (status);
100*a90cf9f2SGordon Ross }
101*a90cf9f2SGordon Ross 
102*a90cf9f2SGordon Ross /*
103*a90cf9f2SGordon Ross  * smb_quota_free_sids
104*a90cf9f2SGordon Ross  */
105*a90cf9f2SGordon Ross void
smb_quota_free_sids(smb_quota_query_t * request)106*a90cf9f2SGordon Ross smb_quota_free_sids(smb_quota_query_t *request)
107*a90cf9f2SGordon Ross {
108*a90cf9f2SGordon Ross 	list_t *sid_list;
109*a90cf9f2SGordon Ross 	smb_quota_sid_t *sid;
110*a90cf9f2SGordon Ross 
111*a90cf9f2SGordon Ross 	sid_list = &request->qq_sid_list;
112*a90cf9f2SGordon Ross 
113*a90cf9f2SGordon Ross 	while ((sid = list_head(sid_list)) != NULL) {
114*a90cf9f2SGordon Ross 		list_remove(sid_list, sid);
115*a90cf9f2SGordon Ross 		kmem_free(sid, sizeof (smb_quota_sid_t));
116*a90cf9f2SGordon Ross 	}
117*a90cf9f2SGordon Ross 
118*a90cf9f2SGordon Ross 	list_destroy(sid_list);
119*a90cf9f2SGordon Ross }
120*a90cf9f2SGordon Ross 
121*a90cf9f2SGordon Ross /*
122*a90cf9f2SGordon Ross  * smb_quota_decode_sids
123*a90cf9f2SGordon Ross  *
124*a90cf9f2SGordon Ross  * Decode the SIDs from the data block and stores them in string form in list.
125*a90cf9f2SGordon Ross  * Eaxh sid entry comprises:
126*a90cf9f2SGordon Ross  *	next_offset (4 bytes) - offset of next entry
127*a90cf9f2SGordon Ross  *	sid length (4 bytes)
128*a90cf9f2SGordon Ross  *	sid (variable length = sidlen)
129*a90cf9f2SGordon Ross  * The last entry will have a next_offset value of 0.
130*a90cf9f2SGordon Ross  *
131*a90cf9f2SGordon Ross  * Returns NT_STATUS codes.
132*a90cf9f2SGordon Ross  */
133*a90cf9f2SGordon Ross uint32_t
smb_quota_decode_sids(mbuf_chain_t * mbc,list_t * list)134*a90cf9f2SGordon Ross smb_quota_decode_sids(mbuf_chain_t *mbc, list_t *list)
135*a90cf9f2SGordon Ross {
136*a90cf9f2SGordon Ross 	uint32_t	offset, mb_offset, sid_offset, bytes_left;
137*a90cf9f2SGordon Ross 	uint32_t	next_offset, sidlen;
138*a90cf9f2SGordon Ross 	smb_sid_t	*sid;
139*a90cf9f2SGordon Ross 	smb_quota_sid_t	*qsid;
140*a90cf9f2SGordon Ross 	uint32_t status = NT_STATUS_SUCCESS;
141*a90cf9f2SGordon Ross 	struct mbuf_chain sidbuf;
142*a90cf9f2SGordon Ross 	int rc;
143*a90cf9f2SGordon Ross 
144*a90cf9f2SGordon Ross 	offset = 0;
145*a90cf9f2SGordon Ross 	do {
146*a90cf9f2SGordon Ross 		mb_offset = offset + mbc->chain_offset;
147*a90cf9f2SGordon Ross 		bytes_left = mbc->max_bytes - mb_offset;
148*a90cf9f2SGordon Ross 		rc = MBC_SHADOW_CHAIN(&sidbuf, mbc,
149*a90cf9f2SGordon Ross 		    mb_offset, bytes_left);
150*a90cf9f2SGordon Ross 		if (rc != 0) {
151*a90cf9f2SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
152*a90cf9f2SGordon Ross 			break;
153*a90cf9f2SGordon Ross 		}
154*a90cf9f2SGordon Ross 
155*a90cf9f2SGordon Ross 		if (smb_mbc_decodef(&sidbuf, "ll", &next_offset, &sidlen)) {
156*a90cf9f2SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
157*a90cf9f2SGordon Ross 			break;
158*a90cf9f2SGordon Ross 		}
159*a90cf9f2SGordon Ross 
160*a90cf9f2SGordon Ross 		sid_offset = offset + (2 * sizeof (uint32_t));
161*a90cf9f2SGordon Ross 		sid = smb_decode_sid(mbc, sid_offset);
162*a90cf9f2SGordon Ross 		if (sid == NULL) {
163*a90cf9f2SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
164*a90cf9f2SGordon Ross 			break;
165*a90cf9f2SGordon Ross 		}
166*a90cf9f2SGordon Ross 
167*a90cf9f2SGordon Ross 		qsid = kmem_zalloc(sizeof (smb_quota_sid_t), KM_SLEEP);
168*a90cf9f2SGordon Ross 		smb_sid_tostr(sid, qsid->qs_sidstr);
169*a90cf9f2SGordon Ross 		smb_sid_free(sid);
170*a90cf9f2SGordon Ross 		sid = NULL;
171*a90cf9f2SGordon Ross 
172*a90cf9f2SGordon Ross 		list_insert_tail(list, qsid);
173*a90cf9f2SGordon Ross 		offset += next_offset;
174*a90cf9f2SGordon Ross 	} while ((next_offset != 0) && (bytes_left > 0));
175*a90cf9f2SGordon Ross 
176*a90cf9f2SGordon Ross 	return (status);
177*a90cf9f2SGordon Ross }
178*a90cf9f2SGordon Ross 
179*a90cf9f2SGordon Ross /*
180*a90cf9f2SGordon Ross  * smb_quota_max_quota
181*a90cf9f2SGordon Ross  *
182*a90cf9f2SGordon Ross  * If the query is if type SMB_QUOTA_QUERY_SIDLIST a quota entry
183*a90cf9f2SGordon Ross  * is returned for each sid in the sidlist. request->qr_max_quota
184*a90cf9f2SGordon Ross  * is set to 0 and is unused.
185*a90cf9f2SGordon Ross  * Otherwise (for SMB_QUOTA_QUERY_STARTSID and SMB_QUOTA_QUERY_ALL)
186*a90cf9f2SGordon Ross  * max_quota is the maximum number of quota entries requested from
187*a90cf9f2SGordon Ross  * the file system (via door call smb_quota_query()).
188*a90cf9f2SGordon Ross  * If single is set max_quota is set to 1. If single is not set
189*a90cf9f2SGordon Ross  * max quota is calculated as the number of quotas of size
190*a90cf9f2SGordon Ross  * SMB_QUOTA_EST_SIZE that would fit in the response buffer.
191*a90cf9f2SGordon Ross  */
192*a90cf9f2SGordon Ross void
smb_quota_max_quota(mbuf_chain_t * mbc,smb_quota_query_t * request)193*a90cf9f2SGordon Ross smb_quota_max_quota(mbuf_chain_t *mbc, smb_quota_query_t *request)
194*a90cf9f2SGordon Ross {
195*a90cf9f2SGordon Ross 	if (request->qq_query_op == SMB_QUOTA_QUERY_SIDLIST)
196*a90cf9f2SGordon Ross 		request->qq_max_quota = 0;
197*a90cf9f2SGordon Ross 	else if (request->qq_single)
198*a90cf9f2SGordon Ross 		request->qq_max_quota = 1;
199*a90cf9f2SGordon Ross 	else
200*a90cf9f2SGordon Ross 		request->qq_max_quota = (mbc->max_bytes / SMB_QUOTA_EST_SIZE);
201*a90cf9f2SGordon Ross }
202*a90cf9f2SGordon Ross 
203*a90cf9f2SGordon Ross /*
204*a90cf9f2SGordon Ross  * smb_quota_decode_quotas
205*a90cf9f2SGordon Ross  *
206*a90cf9f2SGordon Ross  * Decode the quota entries into a list_t of smb_quota_t.
207*a90cf9f2SGordon Ross  * SMB_QUOTA_SIZE_NO_SID is the size of a quota entry,
208*a90cf9f2SGordon Ross  * excluding the sid.
209*a90cf9f2SGordon Ross  * The last entry will have a next_offset value of 0.
210*a90cf9f2SGordon Ross  *
211*a90cf9f2SGordon Ross  * Returns NT_STATUS codes.
212*a90cf9f2SGordon Ross  */
213*a90cf9f2SGordon Ross uint32_t
smb_quota_decode_quotas(mbuf_chain_t * mbc,list_t * list)214*a90cf9f2SGordon Ross smb_quota_decode_quotas(mbuf_chain_t *mbc, list_t *list)
215*a90cf9f2SGordon Ross {
216*a90cf9f2SGordon Ross 	uint32_t	offset, mb_offset, sid_offset, bytes_left;
217*a90cf9f2SGordon Ross 	uint32_t	next_offset, sidlen;
218*a90cf9f2SGordon Ross 	uint64_t	mtime;
219*a90cf9f2SGordon Ross 	smb_sid_t	*sid;
220*a90cf9f2SGordon Ross 	smb_quota_t	*quota;
221*a90cf9f2SGordon Ross 	uint32_t	status = NT_STATUS_SUCCESS;
222*a90cf9f2SGordon Ross 	struct mbuf_chain quotabuf;
223*a90cf9f2SGordon Ross 	int rc;
224*a90cf9f2SGordon Ross 
225*a90cf9f2SGordon Ross 	offset = 0;
226*a90cf9f2SGordon Ross 	do {
227*a90cf9f2SGordon Ross 		mb_offset = offset + mbc->chain_offset;
228*a90cf9f2SGordon Ross 		bytes_left = mbc->max_bytes - mb_offset;
229*a90cf9f2SGordon Ross 		rc = MBC_SHADOW_CHAIN(&quotabuf, mbc,
230*a90cf9f2SGordon Ross 		    mb_offset, bytes_left);
231*a90cf9f2SGordon Ross 		if (rc != 0) {
232*a90cf9f2SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
233*a90cf9f2SGordon Ross 			break;
234*a90cf9f2SGordon Ross 		}
235*a90cf9f2SGordon Ross 
236*a90cf9f2SGordon Ross 		quota = kmem_zalloc(sizeof (smb_quota_t), KM_SLEEP);
237*a90cf9f2SGordon Ross 
238*a90cf9f2SGordon Ross 		if (smb_mbc_decodef(&quotabuf, "llqqqq",
239*a90cf9f2SGordon Ross 		    &next_offset, &sidlen, &mtime,
240*a90cf9f2SGordon Ross 		    &quota->q_used, &quota->q_thresh, &quota->q_limit)) {
241*a90cf9f2SGordon Ross 			kmem_free(quota, sizeof (smb_quota_t));
242*a90cf9f2SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
243*a90cf9f2SGordon Ross 			break;
244*a90cf9f2SGordon Ross 		}
245*a90cf9f2SGordon Ross 
246*a90cf9f2SGordon Ross 		sid_offset = offset + SMB_QUOTA_SIZE_NO_SID;
247*a90cf9f2SGordon Ross 		sid = smb_decode_sid(mbc, sid_offset);
248*a90cf9f2SGordon Ross 		if (sid == NULL) {
249*a90cf9f2SGordon Ross 			kmem_free(quota, sizeof (smb_quota_t));
250*a90cf9f2SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
251*a90cf9f2SGordon Ross 			break;
252*a90cf9f2SGordon Ross 		}
253*a90cf9f2SGordon Ross 
254*a90cf9f2SGordon Ross 		bzero(quota->q_sidstr, SMB_SID_STRSZ);
255*a90cf9f2SGordon Ross 		smb_sid_tostr(sid, quota->q_sidstr);
256*a90cf9f2SGordon Ross 		smb_sid_free(sid);
257*a90cf9f2SGordon Ross 		sid = NULL;
258*a90cf9f2SGordon Ross 
259*a90cf9f2SGordon Ross 		list_insert_tail(list, quota);
260*a90cf9f2SGordon Ross 		offset += next_offset;
261*a90cf9f2SGordon Ross 	} while ((next_offset != 0) && (bytes_left > 0));
262*a90cf9f2SGordon Ross 
263*a90cf9f2SGordon Ross 	return (status);
264*a90cf9f2SGordon Ross }
265*a90cf9f2SGordon Ross 
266*a90cf9f2SGordon Ross /*
267*a90cf9f2SGordon Ross  * smb_quota_free_quotas
268*a90cf9f2SGordon Ross  */
269*a90cf9f2SGordon Ross void
smb_quota_free_quotas(list_t * list)270*a90cf9f2SGordon Ross smb_quota_free_quotas(list_t *list)
271*a90cf9f2SGordon Ross {
272*a90cf9f2SGordon Ross 	smb_quota_t *quota;
273*a90cf9f2SGordon Ross 
274*a90cf9f2SGordon Ross 	while ((quota = list_head(list)) != NULL) {
275*a90cf9f2SGordon Ross 		list_remove(list, quota);
276*a90cf9f2SGordon Ross 		kmem_free(quota, sizeof (smb_quota_t));
277*a90cf9f2SGordon Ross 	}
278*a90cf9f2SGordon Ross 
279*a90cf9f2SGordon Ross 	list_destroy(list);
280*a90cf9f2SGordon Ross }
281*a90cf9f2SGordon Ross 
282*a90cf9f2SGordon Ross /*
283*a90cf9f2SGordon Ross  * smb_quota_encode_quotas
284*a90cf9f2SGordon Ross  *
285*a90cf9f2SGordon Ross  * Encode the quota entries from a list_t of smb_quota_t.
286*a90cf9f2SGordon Ross  * SMB_QUOTA_SIZE_NO_SID is the size of a quota entry,
287*a90cf9f2SGordon Ross  * excluding the sid.
288*a90cf9f2SGordon Ross  * The last entry will have a next_offset value of 0.
289*a90cf9f2SGordon Ross  * Sets the last encoded SID as the resume sid.
290*a90cf9f2SGordon Ross  */
291*a90cf9f2SGordon Ross uint32_t
smb_quota_encode_quotas(mbuf_chain_t * mbc,smb_quota_query_t * request,smb_quota_response_t * reply,smb_ofile_t * ofile)292*a90cf9f2SGordon Ross smb_quota_encode_quotas(mbuf_chain_t *mbc, smb_quota_query_t *request,
293*a90cf9f2SGordon Ross     smb_quota_response_t *reply, smb_ofile_t *ofile)
294*a90cf9f2SGordon Ross {
295*a90cf9f2SGordon Ross 	uint32_t next_offset, sid_offset;
296*a90cf9f2SGordon Ross 	uint64_t mtime = 0;
297*a90cf9f2SGordon Ross 	uint32_t sidlen, pad;
298*a90cf9f2SGordon Ross 	smb_sid_t *sid;
299*a90cf9f2SGordon Ross 	char *sidstr = NULL, *resume = NULL;
300*a90cf9f2SGordon Ross 	smb_quota_t *quota, *next_quota;
301*a90cf9f2SGordon Ross 	list_t *list = &reply->qr_quota_list;
302*a90cf9f2SGordon Ross 
303*a90cf9f2SGordon Ross 	int rc;
304*a90cf9f2SGordon Ross 	uint32_t status = NT_STATUS_SUCCESS;
305*a90cf9f2SGordon Ross 
306*a90cf9f2SGordon Ross 	quota = list_head(list);
307*a90cf9f2SGordon Ross 	while (quota) {
308*a90cf9f2SGordon Ross 		next_quota = list_next(list, quota);
309*a90cf9f2SGordon Ross 		sidstr = quota->q_sidstr;
310*a90cf9f2SGordon Ross 		if ((sid = smb_sid_fromstr(sidstr)) == NULL) {
311*a90cf9f2SGordon Ross 			quota = next_quota;
312*a90cf9f2SGordon Ross 			continue;
313*a90cf9f2SGordon Ross 		}
314*a90cf9f2SGordon Ross 
315*a90cf9f2SGordon Ross 		sidlen = smb_sid_len(sid);
316*a90cf9f2SGordon Ross 		sid_offset = SMB_QUOTA_SIZE_NO_SID;
317*a90cf9f2SGordon Ross 		next_offset = sid_offset + sidlen;
318*a90cf9f2SGordon Ross 		pad = smb_pad_align(next_offset, 8);
319*a90cf9f2SGordon Ross 		next_offset += pad;
320*a90cf9f2SGordon Ross 
321*a90cf9f2SGordon Ross 		if (!MBC_ROOM_FOR(mbc, next_offset)) {
322*a90cf9f2SGordon Ross 			smb_sid_free(sid);
323*a90cf9f2SGordon Ross 			break;
324*a90cf9f2SGordon Ross 		}
325*a90cf9f2SGordon Ross 		if (!MBC_ROOM_FOR(mbc,
326*a90cf9f2SGordon Ross 		    next_offset + SMB_QUOTA_MAX_SIZE)) {
327*a90cf9f2SGordon Ross 			next_quota = NULL;
328*a90cf9f2SGordon Ross 		}
329*a90cf9f2SGordon Ross 
330*a90cf9f2SGordon Ross 		rc = smb_mbc_encodef(mbc, "llqqqq",
331*a90cf9f2SGordon Ross 		    next_quota ? next_offset : 0, sidlen, mtime,
332*a90cf9f2SGordon Ross 		    quota->q_used, quota->q_thresh, quota->q_limit);
333*a90cf9f2SGordon Ross 		if (rc == 0) {
334*a90cf9f2SGordon Ross 			smb_encode_sid(mbc, sid);
335*a90cf9f2SGordon Ross 			rc = smb_mbc_encodef(mbc, "#.", pad);
336*a90cf9f2SGordon Ross 		}
337*a90cf9f2SGordon Ross 
338*a90cf9f2SGordon Ross 		smb_sid_free(sid);
339*a90cf9f2SGordon Ross 
340*a90cf9f2SGordon Ross 		if (rc != 0) {
341*a90cf9f2SGordon Ross 			status = NT_STATUS_INTERNAL_ERROR;
342*a90cf9f2SGordon Ross 			break;
343*a90cf9f2SGordon Ross 		}
344*a90cf9f2SGordon Ross 
345*a90cf9f2SGordon Ross 		resume = sidstr;
346*a90cf9f2SGordon Ross 		quota = next_quota;
347*a90cf9f2SGordon Ross 	}
348*a90cf9f2SGordon Ross 
349*a90cf9f2SGordon Ross 	if ((status == NT_STATUS_SUCCESS) &&
350*a90cf9f2SGordon Ross 	    ((request->qq_query_op == SMB_QUOTA_QUERY_STARTSID) ||
351*a90cf9f2SGordon Ross 	    (request->qq_query_op == SMB_QUOTA_QUERY_ALL))) {
352*a90cf9f2SGordon Ross 		smb_ofile_set_quota_resume(ofile, resume);
353*a90cf9f2SGordon Ross 	}
354*a90cf9f2SGordon Ross 
355*a90cf9f2SGordon Ross 	return (status);
356*a90cf9f2SGordon Ross }
357*a90cf9f2SGordon Ross 
358*a90cf9f2SGordon Ross /*
359*a90cf9f2SGordon Ross  * smb_quota_query_user_quota
360*a90cf9f2SGordon Ross  *
361*a90cf9f2SGordon Ross  * Get user quota information for a single user (uid)
362*a90cf9f2SGordon Ross  * for the current file system.
363*a90cf9f2SGordon Ross  * Find the user's sid, insert it in the sidlist of a
364*a90cf9f2SGordon Ross  * smb_quota_query_t request and invoke the door call
365*a90cf9f2SGordon Ross  * smb_quota_query() to obtain the quota information.
366*a90cf9f2SGordon Ross  *
367*a90cf9f2SGordon Ross  * Returns: NT_STATUS codes.
368*a90cf9f2SGordon Ross  */
369*a90cf9f2SGordon Ross uint32_t
smb_quota_query_user_quota(smb_request_t * sr,uid_t uid,smb_quota_t * quota)370*a90cf9f2SGordon Ross smb_quota_query_user_quota(smb_request_t *sr, uid_t uid, smb_quota_t *quota)
371*a90cf9f2SGordon Ross {
372*a90cf9f2SGordon Ross 	smb_sid_t *sid;
373*a90cf9f2SGordon Ross 	smb_quota_sid_t qsid;
374*a90cf9f2SGordon Ross 	smb_quota_query_t request;
375*a90cf9f2SGordon Ross 	smb_quota_response_t reply;
376*a90cf9f2SGordon Ross 	list_t *sid_list;
377*a90cf9f2SGordon Ross 	smb_quota_t *q;
378*a90cf9f2SGordon Ross 	smb_node_t *tnode;
379*a90cf9f2SGordon Ross 	uint32_t status = NT_STATUS_SUCCESS;
380*a90cf9f2SGordon Ross 
381*a90cf9f2SGordon Ross 	if (smb_idmap_getsid(uid, SMB_IDMAP_USER, &sid) != IDMAP_SUCCESS)
382*a90cf9f2SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
383*a90cf9f2SGordon Ross 
384*a90cf9f2SGordon Ross 	smb_sid_tostr(sid, qsid.qs_sidstr);
385*a90cf9f2SGordon Ross 	smb_sid_free(sid);
386*a90cf9f2SGordon Ross 
387*a90cf9f2SGordon Ross 	bzero(&request, sizeof (smb_quota_query_t));
388*a90cf9f2SGordon Ross 	bzero(&reply, sizeof (smb_quota_response_t));
389*a90cf9f2SGordon Ross 
390*a90cf9f2SGordon Ross 	tnode = sr->tid_tree->t_snode;
391*a90cf9f2SGordon Ross 	request.qq_root_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
392*a90cf9f2SGordon Ross 	if (smb_node_getmntpath(tnode, request.qq_root_path, MAXPATHLEN) != 0) {
393*a90cf9f2SGordon Ross 		kmem_free(request.qq_root_path, MAXPATHLEN);
394*a90cf9f2SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
395*a90cf9f2SGordon Ross 	}
396*a90cf9f2SGordon Ross 
397*a90cf9f2SGordon Ross 	sid_list = &request.qq_sid_list;
398*a90cf9f2SGordon Ross 	list_create(sid_list, sizeof (smb_quota_sid_t),
399*a90cf9f2SGordon Ross 	    offsetof(smb_quota_sid_t, qs_list_node));
400*a90cf9f2SGordon Ross 	list_insert_tail(sid_list, &qsid);
401*a90cf9f2SGordon Ross 
402*a90cf9f2SGordon Ross 	request.qq_query_op = SMB_QUOTA_QUERY_SIDLIST;
403*a90cf9f2SGordon Ross 	request.qq_single = B_TRUE;
404*a90cf9f2SGordon Ross 
405*a90cf9f2SGordon Ross 	if (smb_quota_query(sr->sr_server, &request, &reply) != 0) {
406*a90cf9f2SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
407*a90cf9f2SGordon Ross 	} else {
408*a90cf9f2SGordon Ross 		if (reply.qr_status != NT_STATUS_SUCCESS) {
409*a90cf9f2SGordon Ross 			status = reply.qr_status;
410*a90cf9f2SGordon Ross 		} else {
411*a90cf9f2SGordon Ross 			q = list_head(&reply.qr_quota_list);
412*a90cf9f2SGordon Ross 			if ((q == NULL) ||
413*a90cf9f2SGordon Ross 			    (strcmp(qsid.qs_sidstr, q->q_sidstr) != 0)) {
414*a90cf9f2SGordon Ross 				/* should never happen */
415*a90cf9f2SGordon Ross 				status = NT_STATUS_INTERNAL_ERROR;
416*a90cf9f2SGordon Ross 			} else {
417*a90cf9f2SGordon Ross 				bcopy(q, quota, sizeof (smb_quota_t));
418*a90cf9f2SGordon Ross 			}
419*a90cf9f2SGordon Ross 		}
420*a90cf9f2SGordon Ross 		xdr_free(smb_quota_response_xdr, (char *)&reply);
421*a90cf9f2SGordon Ross 	}
422*a90cf9f2SGordon Ross 
423*a90cf9f2SGordon Ross 	kmem_free(request.qq_root_path, MAXPATHLEN);
424*a90cf9f2SGordon Ross 	list_remove(sid_list, &qsid);
425*a90cf9f2SGordon Ross 	list_destroy(sid_list);
426*a90cf9f2SGordon Ross 
427*a90cf9f2SGordon Ross 	return (status);
428*a90cf9f2SGordon Ross }
429*a90cf9f2SGordon Ross 
430*a90cf9f2SGordon Ross /*
431*a90cf9f2SGordon Ross  * smb_quota_query
432*a90cf9f2SGordon Ross  *
433*a90cf9f2SGordon Ross  * Door call to query quotas for the provided filesystem path.
434*a90cf9f2SGordon Ross  * Returns: -1 - door call (or encode/decode) failure.
435*a90cf9f2SGordon Ross  *	     0 - success. Status set in reply.
436*a90cf9f2SGordon Ross  */
437*a90cf9f2SGordon Ross int
smb_quota_query(smb_server_t * sv,smb_quota_query_t * request,smb_quota_response_t * reply)438*a90cf9f2SGordon Ross smb_quota_query(smb_server_t *sv, smb_quota_query_t *request,
439*a90cf9f2SGordon Ross     smb_quota_response_t *reply)
440*a90cf9f2SGordon Ross {
441*a90cf9f2SGordon Ross 	int	rc;
442*a90cf9f2SGordon Ross 
443*a90cf9f2SGordon Ross 	rc = smb_kdoor_upcall(sv, SMB_DR_QUOTA_QUERY,
444*a90cf9f2SGordon Ross 	    request, smb_quota_query_xdr, reply, smb_quota_response_xdr);
445*a90cf9f2SGordon Ross 
446*a90cf9f2SGordon Ross 	return (rc);
447*a90cf9f2SGordon Ross }
448*a90cf9f2SGordon Ross 
449*a90cf9f2SGordon Ross /*
450*a90cf9f2SGordon Ross  * smb_quota_set
451*a90cf9f2SGordon Ross  *
452*a90cf9f2SGordon Ross  * Door call to set quotas for the provided filesystem path.
453*a90cf9f2SGordon Ross  * Returns: -1 - door call (or encode/decode) failure.
454*a90cf9f2SGordon Ross  *	     0 - success. Status set in reply.
455*a90cf9f2SGordon Ross  */
456*a90cf9f2SGordon Ross int
smb_quota_set(smb_server_t * sv,smb_quota_set_t * request,uint32_t * reply)457*a90cf9f2SGordon Ross smb_quota_set(smb_server_t *sv, smb_quota_set_t *request, uint32_t *reply)
458*a90cf9f2SGordon Ross {
459*a90cf9f2SGordon Ross 	int	rc;
460*a90cf9f2SGordon Ross 
461*a90cf9f2SGordon Ross 	rc = smb_kdoor_upcall(sv, SMB_DR_QUOTA_SET,
462*a90cf9f2SGordon Ross 	    request, smb_quota_set_xdr, reply, xdr_uint32_t);
463*a90cf9f2SGordon Ross 
464*a90cf9f2SGordon Ross 	return (rc);
465*a90cf9f2SGordon Ross }
466