2 * QUOTA An implementation of the diskquota system for the LINUX
3 * operating system. QUOTA is implemented using the BSD systemcall
4 * interface as the means of communication with the user level.
5 * Should work for all filesystems because of integration into the
6 * VFS layer of the operating system.
7 * This is based on the Melbourne quota system wich uses both user and
10 * This part does the lookup of the info.
12 * Version: $Id: rquota_server.c,v 1.22 2010/01/05 16:04:57 jkar8572 Exp $
14 * Author: Marco van Wieringen <mvw@planets.elm.net>
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version
19 * 2 of the License, or (at your option) any later version.
25 #include <arpa/inet.h>
37 #include "dqblk_rpc.h"
40 #define STDIN_FILENO 0
42 #define TYPE_EXTENDED 0x01
45 #define FACILITY LOG_LOCAL7
47 #ifndef MAXPATHNAMELEN
48 #define MAXPATHNAMELEN BUFSIZ
51 #define NETTYPE AF_INET
53 /* Options from rquota_svc.c */
57 extern char nfs_pseudoroot[PATH_MAX];
60 * Global unix authentication credentials.
62 extern struct authunix_parms *unix_cred;
64 int in_group(gid_t * gids, u_int len, gid_t gid)
66 gid_t *gidsp = gids + len;
75 static inline void servnet2utildqblk(struct util_dqblk *u, sq_dqblk * n)
80 u->dqb_bhardlimit = n->rq_bhardlimit;
81 u->dqb_bsoftlimit = n->rq_bsoftlimit;
82 u->dqb_ihardlimit = n->rq_fhardlimit;
83 u->dqb_isoftlimit = n->rq_fsoftlimit;
84 u->dqb_curspace = ((qsize_t)n->rq_curblocks) << RPC_DQBLK_SIZE_BITS;
85 u->dqb_curinodes = n->rq_curfiles;
87 u->dqb_btime = n->rq_btimeleft + now;
91 u->dqb_itime = n->rq_ftimeleft + now;
96 static inline void servutil2netdqblk(struct rquota *n, struct util_dqblk *u)
101 n->rq_bhardlimit = (u->dqb_bhardlimit << QUOTABLOCK_BITS) >> RPC_DQBLK_SIZE_BITS;
102 n->rq_bsoftlimit = (u->dqb_bsoftlimit << QUOTABLOCK_BITS) >> RPC_DQBLK_SIZE_BITS;
103 n->rq_fhardlimit = u->dqb_ihardlimit;
104 n->rq_fsoftlimit = u->dqb_isoftlimit;
105 n->rq_curblocks = (u->dqb_curspace + RPC_DQBLK_SIZE - 1) >> RPC_DQBLK_SIZE_BITS;
106 n->rq_curfiles = u->dqb_curinodes;
108 n->rq_btimeleft = u->dqb_btime - now;
112 n->rq_ftimeleft = u->dqb_itime - now;
117 setquota_rslt *setquotainfo(int lflags, caddr_t * argp, struct svc_req *rqstp)
119 static setquota_rslt result;
121 #if defined(RPC_SETQUOTA)
124 ext_setquota_args *ext_args;
126 struct util_dqblk dqblk;
129 char pathname[PATH_MAX] = {0};
130 char *pathp = pathname;
132 struct quota_handle *handles[2] = { NULL, NULL };
135 * First check authentication.
137 if (lflags & TYPE_EXTENDED) {
138 arguments.ext_args = (ext_setquota_args *) argp;
140 id = arguments.ext_args->sqa_id;
141 if (unix_cred->aup_uid != 0) {
142 result.status = Q_EPERM;
146 qcmd = arguments.ext_args->sqa_qcmd;
147 type = arguments.ext_args->sqa_type;
148 if (arguments.ext_args->sqa_pathp[0] != '/')
149 sstrncpy(pathname, nfs_pseudoroot, PATH_MAX);
150 sstrncat(pathname, arguments.ext_args->sqa_pathp, PATH_MAX);
151 servnet2utildqblk(&dqblk, &arguments.ext_args->sqa_dqblk);
154 arguments.args = (setquota_args *) argp;
156 id = arguments.args->sqa_id;
157 if (unix_cred->aup_uid != 0) {
158 result.status = Q_EPERM;
162 qcmd = arguments.args->sqa_qcmd;
164 if (arguments.args->sqa_pathp[0] != '/')
165 sstrncpy(pathname, nfs_pseudoroot, PATH_MAX);
166 sstrncat(pathname, arguments.args->sqa_pathp, PATH_MAX);
167 servnet2utildqblk(&dqblk, &arguments.args->sqa_dqblk);
170 result.status = Q_NOQUOTA;
171 result.setquota_rslt_u.sqr_rquota.rq_bsize = RPC_DQBLK_SIZE;
173 if (init_mounts_scan(1, &pathp, MS_QUIET | MS_NO_MNTPOINT | MS_NFS_ALL | ((flags & FL_AUTOFS) ? 0 : MS_NO_AUTOFS)) < 0)
175 if (!(mnt = get_next_mount())) {
179 if (!(handles[0] = init_io(mnt, type, -1, 0))) {
184 if (!(dquot = handles[0]->qh_ops->read_dquot(handles[0], id)))
186 if (qcmd == QCMD(Q_RPC_SETQLIM, type) || qcmd == QCMD(Q_RPC_SETQUOTA, type)) {
187 dquot->dq_dqb.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
188 dquot->dq_dqb.dqb_bhardlimit = dqblk.dqb_bhardlimit;
189 dquot->dq_dqb.dqb_isoftlimit = dqblk.dqb_isoftlimit;
190 dquot->dq_dqb.dqb_ihardlimit = dqblk.dqb_ihardlimit;
191 dquot->dq_dqb.dqb_btime = dqblk.dqb_btime;
192 dquot->dq_dqb.dqb_itime = dqblk.dqb_itime;
194 if (qcmd == QCMD(Q_RPC_SETUSE, type) || qcmd == QCMD(Q_RPC_SETQUOTA, type)) {
195 dquot->dq_dqb.dqb_curspace = dqblk.dqb_curspace;
196 dquot->dq_dqb.dqb_curinodes = dqblk.dqb_curinodes;
198 if (handles[0]->qh_ops->commit_dquot(dquot, COMMIT_LIMITS) == -1) {
203 result.status = Q_OK;
205 dispose_handle_list(handles);
207 result.status = Q_EPERM;
212 getquota_rslt *getquotainfo(int lflags, caddr_t * argp, struct svc_req * rqstp)
214 static getquota_rslt result;
217 ext_getquota_args *ext_args;
219 struct dquot *dquot = NULL;
221 char pathname[PATH_MAX] = {0};
222 char *pathp = pathname;
224 struct quota_handle *handles[2] = { NULL, NULL };
227 * First check authentication.
229 if (lflags & TYPE_EXTENDED) {
230 arguments.ext_args = (ext_getquota_args *) argp;
231 id = arguments.ext_args->gqa_id;
232 type = arguments.ext_args->gqa_type;
233 if (arguments.ext_args->gqa_pathp[0] != '/')
234 sstrncpy(pathname, nfs_pseudoroot, PATH_MAX);
235 sstrncat(pathname, arguments.ext_args->gqa_pathp, PATH_MAX);
237 if (type == USRQUOTA && unix_cred->aup_uid && unix_cred->aup_uid != id) {
238 result.status = Q_EPERM;
242 if (type == GRPQUOTA && unix_cred->aup_uid && unix_cred->aup_gid != id &&
243 !in_group((gid_t *) unix_cred->aup_gids, unix_cred->aup_len, id)) {
244 result.status = Q_EPERM;
249 arguments.args = (getquota_args *) argp;
250 id = arguments.args->gqa_uid;
252 if (arguments.ext_args->gqa_pathp[0] != '/')
253 sstrncpy(pathname, nfs_pseudoroot, PATH_MAX);
254 sstrncat(pathname, arguments.args->gqa_pathp, PATH_MAX);
256 if (unix_cred->aup_uid && unix_cred->aup_uid != id) {
257 result.status = Q_EPERM;
262 result.status = Q_NOQUOTA;
263 result.getquota_rslt_u.gqr_rquota.rq_bsize = RPC_DQBLK_SIZE;
265 if (init_mounts_scan(1, &pathp, MS_QUIET | MS_NO_MNTPOINT | MS_NFS_ALL | ((flags & FL_AUTOFS) ? 0 : MS_NO_AUTOFS)) < 0)
267 if (!(mnt = get_next_mount())) {
271 if (!(handles[0] = init_io(mnt, type, -1, IOI_READONLY))) {
276 if (!(lflags & ACTIVE) || QIO_ENABLED(handles[0]))
277 dquot = handles[0]->qh_ops->read_dquot(handles[0], id);
279 result.status = Q_OK;
280 result.getquota_rslt_u.gqr_rquota.rq_active =
281 QIO_ENABLED(handles[0]) ? TRUE : FALSE;
282 servutil2netdqblk(&result.getquota_rslt_u.gqr_rquota, &dquot->dq_dqb);
286 dispose_handle_list(handles);
291 * Map RPC-entrypoints to local function names.
293 getquota_rslt *rquotaproc_getquota_1_svc(getquota_args * argp, struct svc_req * rqstp)
295 return (getquotainfo(0, (caddr_t *) argp, rqstp));
298 getquota_rslt *rquotaproc_getactivequota_1_svc(getquota_args * argp, struct svc_req * rqstp)
300 return (getquotainfo(ACTIVE, (caddr_t *) argp, rqstp));
303 getquota_rslt *rquotaproc_getquota_2_svc(ext_getquota_args * argp, struct svc_req * rqstp)
305 return (getquotainfo(TYPE_EXTENDED, (caddr_t *) argp, rqstp));
308 getquota_rslt *rquotaproc_getactivequota_2_svc(ext_getquota_args * argp, struct svc_req * rqstp)
310 return (getquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *) argp, rqstp));
313 setquota_rslt *rquotaproc_setquota_1_svc(setquota_args * argp, struct svc_req * rqstp)
315 return (setquotainfo(0, (caddr_t *) argp, rqstp));
318 setquota_rslt *rquotaproc_setactivequota_1_svc(setquota_args * argp, struct svc_req * rqstp)
320 return (setquotainfo(ACTIVE, (caddr_t *) argp, rqstp));
323 setquota_rslt *rquotaproc_setquota_2_svc(ext_setquota_args * argp, struct svc_req * rqstp)
325 return (setquotainfo(TYPE_EXTENDED, (caddr_t *) argp, rqstp));
328 setquota_rslt *rquotaproc_setactivequota_2_svc(ext_setquota_args * argp, struct svc_req * rqstp)
330 return (setquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *) argp, rqstp));