Initial commit to Gerrit
[profile/ivi/quota.git] / rquota_server.c
1 /*
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
8  *          group quota files.
9  *
10  *          This part does the lookup of the info.
11  *
12  * Version: $Id: rquota_server.c,v 1.22 2010/01/05 16:04:57 jkar8572 Exp $
13  *
14  * Author:  Marco van Wieringen <mvw@planets.elm.net>
15  *
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.
20  */
21
22 #include "config.h"
23
24 #include <rpc/rpc.h>
25 #include <arpa/inet.h>
26 #include <paths.h>
27 #include <stdio.h>
28 #include <syslog.h>
29 #include <time.h>
30
31 #include "mntopt.h"
32 #include "quotaops.h"
33 #include "bylabel.h"
34 #include "rquota.h"
35 #include "quotaio.h"
36 #include "quotasys.h"
37 #include "dqblk_rpc.h"
38 #include "common.h"
39
40 #define STDIN_FILENO    0
41
42 #define TYPE_EXTENDED   0x01
43 #define ACTIVE          0x02
44
45 #define FACILITY        LOG_LOCAL7
46
47 #ifndef MAXPATHNAMELEN
48 #define MAXPATHNAMELEN BUFSIZ
49 #endif
50
51 #define NETTYPE AF_INET
52
53 /* Options from rquota_svc.c */
54 #define FL_AUTOFS 4
55 extern int flags;
56
57 extern char nfs_pseudoroot[PATH_MAX];
58
59 /*
60  * Global unix authentication credentials.
61  */
62 extern struct authunix_parms *unix_cred;
63
64 int in_group(gid_t * gids, u_int len, gid_t gid)
65 {
66         gid_t *gidsp = gids + len;
67
68         while (gidsp > gids)
69                 if (*(--gids) == gid)
70                         return 1;
71
72         return 0;
73 }
74
75 static inline void servnet2utildqblk(struct util_dqblk *u, sq_dqblk * n)
76 {
77         time_t now;
78
79         time(&now);
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;
86         if (n->rq_btimeleft)
87                 u->dqb_btime = n->rq_btimeleft + now;
88         else
89                 u->dqb_btime = 0;
90         if (n->rq_ftimeleft)
91                 u->dqb_itime = n->rq_ftimeleft + now;
92         else
93                 u->dqb_itime = 0;
94 }
95
96 static inline void servutil2netdqblk(struct rquota *n, struct util_dqblk *u)
97 {
98         time_t now;
99
100         time(&now);
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;
107         if (u->dqb_btime)
108                 n->rq_btimeleft = u->dqb_btime - now;
109         else
110                 n->rq_btimeleft = 0;
111         if (u->dqb_itime)
112                 n->rq_ftimeleft = u->dqb_itime - now;
113         else
114                 n->rq_ftimeleft = 0;
115 }
116
117 setquota_rslt *setquotainfo(int lflags, caddr_t * argp, struct svc_req *rqstp)
118 {
119         static setquota_rslt result;
120
121 #if defined(RPC_SETQUOTA)
122         union {
123                 setquota_args *args;
124                 ext_setquota_args *ext_args;
125         } arguments;
126         struct util_dqblk dqblk;
127         struct dquot *dquot;
128         struct mntent *mnt;
129         char pathname[PATH_MAX] = {0};
130         char *pathp = pathname;
131         int id, qcmd, type;
132         struct quota_handle *handles[2] = { NULL, NULL };
133
134         /*
135          * First check authentication.
136          */
137         if (lflags & TYPE_EXTENDED) {
138                 arguments.ext_args = (ext_setquota_args *) argp;
139
140                 id = arguments.ext_args->sqa_id;
141                 if (unix_cred->aup_uid != 0) {
142                         result.status = Q_EPERM;
143                         return (&result);
144                 }
145
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);
152         }
153         else {
154                 arguments.args = (setquota_args *) argp;
155
156                 id = arguments.args->sqa_id;
157                 if (unix_cred->aup_uid != 0) {
158                         result.status = Q_EPERM;
159                         return (&result);
160                 }
161
162                 qcmd = arguments.args->sqa_qcmd;
163                 type = USRQUOTA;
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);
168         }
169
170         result.status = Q_NOQUOTA;
171         result.setquota_rslt_u.sqr_rquota.rq_bsize = RPC_DQBLK_SIZE;
172
173         if (init_mounts_scan(1, &pathp, MS_QUIET | MS_NO_MNTPOINT | MS_NFS_ALL | ((flags & FL_AUTOFS) ? 0 : MS_NO_AUTOFS)) < 0)
174                 goto out;
175         if (!(mnt = get_next_mount())) {
176                 end_mounts_scan();
177                 goto out;
178         }
179         if (!(handles[0] = init_io(mnt, type, -1, 0))) {
180                 end_mounts_scan();
181                 goto out;
182         }
183         end_mounts_scan();
184         if (!(dquot = handles[0]->qh_ops->read_dquot(handles[0], id)))
185                 goto out;
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;
193         }
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;
197         }
198         if (handles[0]->qh_ops->commit_dquot(dquot, COMMIT_LIMITS) == -1) {
199                 free(dquot);
200                 goto out;
201         }
202         free(dquot);
203         result.status = Q_OK;
204 out:
205         dispose_handle_list(handles);
206 #else
207         result.status = Q_EPERM;
208 #endif
209         return (&result);
210 }
211
212 getquota_rslt *getquotainfo(int lflags, caddr_t * argp, struct svc_req * rqstp)
213 {
214         static getquota_rslt result;
215         union {
216                 getquota_args *args;
217                 ext_getquota_args *ext_args;
218         } arguments;
219         struct dquot *dquot = NULL;
220         struct mntent *mnt;
221         char pathname[PATH_MAX] = {0};
222         char *pathp = pathname;
223         int id, type;
224         struct quota_handle *handles[2] = { NULL, NULL };
225
226         /*
227          * First check authentication.
228          */
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);
236
237                 if (type == USRQUOTA && unix_cred->aup_uid && unix_cred->aup_uid != id) {
238                         result.status = Q_EPERM;
239                         return (&result);
240                 }
241
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;
245                         return (&result);
246                 }
247         }
248         else {
249                 arguments.args = (getquota_args *) argp;
250                 id = arguments.args->gqa_uid;
251                 type = USRQUOTA;
252                 if (arguments.ext_args->gqa_pathp[0] != '/')
253                         sstrncpy(pathname, nfs_pseudoroot, PATH_MAX);
254                 sstrncat(pathname, arguments.args->gqa_pathp, PATH_MAX);
255
256                 if (unix_cred->aup_uid && unix_cred->aup_uid != id) {
257                         result.status = Q_EPERM;
258                         return (&result);
259                 }
260         }
261
262         result.status = Q_NOQUOTA;
263         result.getquota_rslt_u.gqr_rquota.rq_bsize = RPC_DQBLK_SIZE;
264
265         if (init_mounts_scan(1, &pathp, MS_QUIET | MS_NO_MNTPOINT | MS_NFS_ALL | ((flags & FL_AUTOFS) ? 0 : MS_NO_AUTOFS)) < 0)
266                 goto out;
267         if (!(mnt = get_next_mount())) {
268                 end_mounts_scan();
269                 goto out;
270         }
271         if (!(handles[0] = init_io(mnt, type, -1, IOI_READONLY))) {
272                 end_mounts_scan();
273                 goto out;
274         }
275         end_mounts_scan();
276         if (!(lflags & ACTIVE) || QIO_ENABLED(handles[0]))
277                 dquot = handles[0]->qh_ops->read_dquot(handles[0], id);
278         if (dquot) {
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);
283                 free(dquot);
284         }
285 out:
286         dispose_handle_list(handles);
287         return (&result);
288 }
289
290 /*
291  * Map RPC-entrypoints to local function names.
292  */
293 getquota_rslt *rquotaproc_getquota_1_svc(getquota_args * argp, struct svc_req * rqstp)
294 {
295         return (getquotainfo(0, (caddr_t *) argp, rqstp));
296 }
297
298 getquota_rslt *rquotaproc_getactivequota_1_svc(getquota_args * argp, struct svc_req * rqstp)
299 {
300         return (getquotainfo(ACTIVE, (caddr_t *) argp, rqstp));
301 }
302
303 getquota_rslt *rquotaproc_getquota_2_svc(ext_getquota_args * argp, struct svc_req * rqstp)
304 {
305         return (getquotainfo(TYPE_EXTENDED, (caddr_t *) argp, rqstp));
306 }
307
308 getquota_rslt *rquotaproc_getactivequota_2_svc(ext_getquota_args * argp, struct svc_req * rqstp)
309 {
310         return (getquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *) argp, rqstp));
311 }
312
313 setquota_rslt *rquotaproc_setquota_1_svc(setquota_args * argp, struct svc_req * rqstp)
314 {
315         return (setquotainfo(0, (caddr_t *) argp, rqstp));
316 }
317
318 setquota_rslt *rquotaproc_setactivequota_1_svc(setquota_args * argp, struct svc_req * rqstp)
319 {
320         return (setquotainfo(ACTIVE, (caddr_t *) argp, rqstp));
321 }
322
323 setquota_rslt *rquotaproc_setquota_2_svc(ext_setquota_args * argp, struct svc_req * rqstp)
324 {
325         return (setquotainfo(TYPE_EXTENDED, (caddr_t *) argp, rqstp));
326 }
327
328 setquota_rslt *rquotaproc_setactivequota_2_svc(ext_setquota_args * argp, struct svc_req * rqstp)
329 {
330         return (setquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *) argp, rqstp));
331 }