Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : System QUOTA function wrappers for NFS
4 : Copyright (C) Michael Adam 2010
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 :
21 : #include "includes.h"
22 :
23 : #undef DBGC_CLASS
24 : #define DBGC_CLASS DBGC_QUOTA
25 :
26 : #ifndef HAVE_SYS_QUOTAS
27 : #ifdef HAVE_NFS_QUOTAS
28 : #undef HAVE_NFS_QUOTAS
29 : #endif
30 : #endif
31 :
32 : #ifdef HAVE_NFS_QUOTAS
33 :
34 : /*
35 : * nfs quota support
36 : * This is based on the FreeBSD / SUNOS5 section of quotas.c
37 : */
38 :
39 : /* <rpc/xdr.h> uses TRUE and FALSE */
40 : #ifdef TRUE
41 : #undef TRUE
42 : #endif
43 :
44 : #ifdef FALSE
45 : #undef FALSE
46 : #endif
47 :
48 : #include <rpc/rpc.h>
49 : #include <rpc/types.h>
50 : #include <rpc/xdr.h>
51 : #include <rpcsvc/rquota.h>
52 : #ifdef HAVE_RPC_NETTYPE_H
53 : #include <rpc/nettype.h>
54 : #endif
55 :
56 : #ifndef RQ_PATHLEN
57 : #define RQ_PATHLEN 1024
58 : #endif
59 :
60 : #ifdef HAVE_GETQUOTA_RSLT_GETQUOTA_RSLT_U
61 : #define GQR_RQUOTA getquota_rslt_u.gqr_rquota
62 : #define GQR_STATUS status
63 : #else
64 : #define GQR_RQUOTA gqr_rquota
65 : #define GQR_STATUS gqr_status
66 : #endif
67 :
68 0 : static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
69 : {
70 0 : if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
71 0 : return(0);
72 0 : if (!xdr_int(xdrsp, &args->gqa_uid))
73 0 : return(0);
74 0 : return (1);
75 : }
76 :
77 0 : static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
78 : {
79 0 : int quotastat;
80 :
81 0 : if (!xdr_int(xdrsp, "astat)) {
82 0 : DEBUG(6,("nfs_quotas: Status bad or zero\n"));
83 0 : return 0;
84 : }
85 0 : gqr->GQR_STATUS = quotastat;
86 :
87 0 : if (!xdr_int(xdrsp, &gqr->GQR_RQUOTA.rq_bsize)) {
88 0 : DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
89 0 : return 0;
90 : }
91 0 : if (!xdr_bool(xdrsp, &gqr->GQR_RQUOTA.rq_active)) {
92 0 : DEBUG(6,("nfs_quotas: Active bad or zero\n"));
93 0 : return 0;
94 : }
95 0 : if (!xdr_int(xdrsp, (int *)&gqr->GQR_RQUOTA.rq_bhardlimit)) {
96 0 : DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
97 0 : return 0;
98 : }
99 0 : if (!xdr_int(xdrsp, (int *)&gqr->GQR_RQUOTA.rq_bsoftlimit)) {
100 0 : DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
101 0 : return 0;
102 : }
103 0 : if (!xdr_int(xdrsp, (int *)&gqr->GQR_RQUOTA.rq_curblocks)) {
104 0 : DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
105 0 : return 0;
106 : }
107 0 : return (1);
108 : }
109 :
110 :
111 0 : int sys_get_nfs_quota(const char *path, const char *bdev,
112 : enum SMB_QUOTA_TYPE qtype,
113 : unid_t id, SMB_DISK_QUOTA *dp)
114 : {
115 0 : CLIENT *clnt = NULL;
116 0 : struct getquota_rslt gq_rslt;
117 0 : struct getquota_args gq_args;
118 0 : const char *mnttype;
119 0 : char *cutstr, *host, *testpath;
120 0 : int len;
121 0 : static struct timeval timeout = {2,0};
122 0 : enum clnt_stat clnt_stat;
123 :
124 0 : int ret = -1;
125 0 : uint32_t qflags = 0;
126 :
127 0 : if (!path || !bdev || !dp) {
128 0 : smb_panic("sys_get_nfs_quota: called with NULL pointer");
129 : }
130 :
131 0 : DEBUG(10, ("sys_get_nfs_quota: path[%s] bdev[%s] qtype[%d]\n",
132 : path, bdev, qtype));
133 :
134 0 : ZERO_STRUCT(*dp);
135 :
136 0 : dp->qtype = qtype;
137 :
138 0 : if (qtype != SMB_USER_QUOTA_TYPE) {
139 0 : DEBUG(3, ("sys_get_nfs_quota: got unsupported quota type '%d', "
140 : "only supported type is '%d' (SMB_USER_QUOTA_TYPE)\n",
141 : qtype, SMB_USER_QUOTA_TYPE));
142 0 : errno = ENOSYS;
143 0 : return -1;
144 : }
145 :
146 0 : mnttype = bdev;
147 0 : len = strcspn(mnttype, ":");
148 0 : cutstr = (char *) SMB_MALLOC(len+1);
149 0 : if (cutstr == NULL) {
150 0 : errno = ENOMEM;
151 0 : return -1;
152 : }
153 :
154 0 : memset(cutstr, '\0', len+1);
155 0 : host = strncat(cutstr, mnttype, sizeof(char) * len);
156 0 : testpath = strchr_m(mnttype, ':');
157 0 : if (testpath == NULL) {
158 0 : errno = EINVAL;
159 0 : goto out;
160 : }
161 0 : testpath++;
162 0 : gq_args.gqa_pathp = testpath;
163 0 : gq_args.gqa_uid = id.uid;
164 :
165 0 : DEBUG(10, ("sys_get_nfs_quotas: Asking for quota of path '%s' on "
166 : "host '%s', rpcprog '%i', rpcvers '%i', network '%s'\n",
167 : host, testpath+1, (int)RQUOTAPROG, (int)RQUOTAVERS, "udp"));
168 :
169 0 : clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp");
170 0 : if (clnt == NULL) {
171 0 : ret = -1;
172 0 : goto out;
173 : }
174 :
175 0 : clnt->cl_auth = authunix_create_default();
176 0 : if (clnt->cl_auth == NULL) {
177 0 : DEBUG(3, ("sys_get_nfs_quotas: authunix_create_default "
178 : "failed\n"));
179 0 : ret = -1;
180 0 : goto out;
181 : }
182 :
183 0 : clnt_stat = clnt_call(clnt,
184 : RQUOTAPROC_GETQUOTA,
185 : (const xdrproc_t) my_xdr_getquota_args,
186 : (caddr_t)&gq_args,
187 : (const xdrproc_t) my_xdr_getquota_rslt,
188 : (caddr_t)&gq_rslt,
189 : timeout);
190 :
191 0 : if (clnt_stat != RPC_SUCCESS) {
192 0 : if (errno == ECONNREFUSED) {
193 : /* If we cannot connect with rpc.quotad, it may
194 : * simply be because there's no quota on the remote
195 : * system
196 : */
197 0 : DBG_INFO("clnt_call failed with ECONNREFUSED - "
198 : "assuming no quotas on server\n");
199 0 : ret = 0;
200 : } else {
201 0 : int save_errno = errno;
202 0 : DBG_NOTICE("clnt_call failed - %s\n", strerror(errno));
203 0 : errno = save_errno;
204 0 : ret = -1;
205 : }
206 0 : goto out;
207 : }
208 :
209 0 : DEBUG(10, ("sys_get_nfs_quotas: getquota_rslt:\n"
210 : "status : '%i'\n"
211 : "bsize : '%i'\n"
212 : "active : '%s'\n"
213 : "bhardlimit : '%u'\n"
214 : "bsoftlimit : '%u'\n"
215 : "curblocks : '%u'\n"
216 : "fhardlimit : '%u'\n"
217 : "fsoftlimit : '%u'\n"
218 : "curfiles : '%u'\n"
219 : "btimeleft : '%u'\n"
220 : "ftimeleft : '%u'\n",
221 : gq_rslt.GQR_STATUS,
222 : gq_rslt.GQR_RQUOTA.rq_bsize,
223 : gq_rslt.GQR_RQUOTA.rq_active?"yes":"no",
224 : gq_rslt.GQR_RQUOTA.rq_bhardlimit,
225 : gq_rslt.GQR_RQUOTA.rq_bsoftlimit,
226 : gq_rslt.GQR_RQUOTA.rq_curblocks,
227 : gq_rslt.GQR_RQUOTA.rq_fhardlimit,
228 : gq_rslt.GQR_RQUOTA.rq_fsoftlimit,
229 : gq_rslt.GQR_RQUOTA.rq_curfiles,
230 : gq_rslt.GQR_RQUOTA.rq_btimeleft,
231 : gq_rslt.GQR_RQUOTA.rq_ftimeleft));
232 :
233 : /*
234 : * gqr.status returns
235 : * 1 if quotas exist,
236 : * 2 if there is no quota set, and
237 : * 3 if no permission to get the quota.
238 : */
239 :
240 0 : switch (gq_rslt.GQR_STATUS) {
241 0 : case 1:
242 0 : DEBUG(10, ("sys_get_nfs_quotas: Good quota data\n"));
243 0 : dp->bsize = (uint64_t)gq_rslt.GQR_RQUOTA.rq_bsize;
244 0 : dp->softlimit = gq_rslt.GQR_RQUOTA.rq_bsoftlimit;
245 0 : dp->hardlimit = gq_rslt.GQR_RQUOTA.rq_bhardlimit;
246 0 : dp->curblocks = gq_rslt.GQR_RQUOTA.rq_curblocks;
247 0 : dp->isoftlimit = gq_rslt.GQR_RQUOTA.rq_fsoftlimit;
248 0 : dp->ihardlimit = gq_rslt.GQR_RQUOTA.rq_fhardlimit;
249 0 : dp->curinodes = gq_rslt.GQR_RQUOTA.rq_curfiles;
250 0 : break;
251 :
252 0 : case 2:
253 0 : DEBUG(5, ("sys_get_nfs_quotas: No quota set\n"));
254 0 : SMB_QUOTAS_SET_NO_LIMIT(dp);
255 0 : break;
256 :
257 0 : case 3:
258 0 : DEBUG(3, ("sys_get_nfs_quotas: no permission to get quota\n"));
259 0 : errno = EPERM;
260 0 : ret = -1;
261 0 : goto out;
262 :
263 0 : default:
264 0 : DEBUG(5, ("sys_get_nfs_quotas: Unknown remote quota status "
265 : "code '%i'\n", gq_rslt.GQR_STATUS));
266 0 : ret = -1;
267 0 : goto out;
268 0 : break;
269 : }
270 :
271 0 : dp->qflags = qflags;
272 :
273 0 : ret = 0;
274 :
275 0 : out:
276 0 : if (clnt) {
277 0 : if (clnt->cl_auth) {
278 0 : auth_destroy(clnt->cl_auth);
279 : }
280 0 : clnt_destroy(clnt);
281 : }
282 :
283 0 : SAFE_FREE(cutstr);
284 :
285 0 : DEBUG(10, ("sys_get_nfs_quotas: finished\n" ));
286 0 : return ret;
287 : }
288 :
289 0 : int sys_set_nfs_quota(const char *path, const char *bdev,
290 : enum SMB_QUOTA_TYPE qtype,
291 : unid_t id, SMB_DISK_QUOTA *dp)
292 : {
293 0 : DEBUG(1, ("sys_set_nfs_quota : not supported\n"));
294 0 : errno = ENOSYS;
295 0 : return -1;
296 : }
297 :
298 : #else /* HAVE_NFS_QUOTAS */
299 :
300 : void dummy_sysquotas_nfs(void);
301 : void dummy_sysquotas_nfs(void) {}
302 :
303 : #endif /* HAVE_NFS_QUOTAS */
|