32e5cba04bfb86240d65b9494e860a11ae0f906b
[nfs-utils.git] / utils / rquotad / 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 2.9 1996/11/17 16:59:46 mvw Exp mvw $
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 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #define _LINUX_QUOTA_VERSION 1
26
27 #include <rpc/rpc.h>
28 #include "rquota.h"
29 #include <sys/file.h>
30 #include <sys/stat.h>
31 #include <sys/param.h>
32 #include <sys/quota.h>
33 #include <sys/mount.h>
34 #include <dirent.h>
35 #include <paths.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include "mntent.h"
40 #include "xmalloc.h"
41
42 #define TYPE_EXTENDED   0x01
43 #define ACTIVE          0x02
44
45 #ifndef MNTTYPE_AUTOFS
46 #define MNTTYPE_AUTOFS  "autofs"
47 #endif
48
49 #ifndef BLOCK_SIZE
50 #define BLOCK_SIZE 1024
51 #endif
52
53 /*
54  * Global unix authentication credentials.
55  */
56 extern struct authunix_parms *unix_cred;
57
58 int in_group (gid_t *gids, u_int len, gid_t gid)
59 {
60    int cnt = 0;
61
62    while (cnt < len) {
63       if (gids[cnt] == gid)
64          return 1;
65       cnt++;
66    }
67    return 0;
68 }
69
70 getquota_rslt *getquotainfo(int flags, caddr_t *argp, struct svc_req *rqstp)
71 {
72    static getquota_rslt result;
73    union {
74       getquota_args *args;
75       ext_getquota_args *ext_args;
76    } arguments;
77    FILE *fp;
78    struct dqblk dq_dqb;
79    struct mntent *mnt;
80    char *pathname, *qfpathname;
81    int fd, err, id, type;
82    struct stat stm, stn;
83    struct rquota *rquota;
84
85    /*
86     * First check authentication.
87     */
88    if (flags & TYPE_EXTENDED) {
89       arguments.ext_args = (ext_getquota_args *)argp;
90       id = arguments.ext_args->gqa_id;
91       type = arguments.ext_args->gqa_type;
92       pathname = arguments.ext_args->gqa_pathp;
93
94       if (type == USRQUOTA && unix_cred->aup_uid && unix_cred->aup_uid != id) {
95          result.status = Q_EPERM;
96          return(&result);
97       }
98
99       if (type == GRPQUOTA && unix_cred->aup_uid && unix_cred->aup_gid != id &&
100           !in_group((gid_t *)unix_cred->aup_gids, unix_cred->aup_len, id)) {
101          result.status = Q_EPERM;
102          return(&result);
103       }
104    } else {
105       arguments.args = (getquota_args *)argp;
106       id = arguments.args->gqa_uid;
107       type = USRQUOTA;
108       pathname = arguments.args->gqa_pathp;
109
110       if (unix_cred->aup_uid && unix_cred->aup_uid != id) {
111          result.status = Q_EPERM;
112          return(&result);
113       }
114    }
115
116    fp = setmntent(MNTTAB, "r");
117    while ((mnt = getmntent(fp)) != (struct mntent *)0) {
118       if (stat(mnt->mnt_dir, &stm) == -1)
119           continue;
120
121       if (stat(pathname, &stn) == -1)
122           break;
123       else if (stm.st_dev != stn.st_dev)
124           continue;
125
126       if (mnt->mnt_fsname [0] != '/'
127           || strcasecmp (mnt->mnt_type, MNTTYPE_NFS) == 0
128           || strcasecmp (mnt->mnt_type, MNTTYPE_AUTOFS) == 0
129           || strcasecmp (mnt->mnt_type, MNTTYPE_SWAP) == 0
130           || strcasecmp (mnt->mnt_type, MNTTYPE_IGNORE) == 0)
131          break;
132
133       /* All blocks reported are in BLOCK_SIZE. */
134       result.getquota_rslt_u.gqr_rquota.rq_bsize = BLOCK_SIZE;
135
136       if (hasquota(mnt, type, &qfpathname)) {
137          if ((err = quotactl(QCMD(Q_GETQUOTA, type), mnt->mnt_fsname,
138                              id, (caddr_t)&dq_dqb)) == -1
139              && !(flags & ACTIVE)) {
140             if ((fd = open(qfpathname, O_RDONLY)) < 0)
141             {
142                free(qfpathname);
143                continue;
144             }
145             free(qfpathname);
146             lseek(fd, (long) dqoff(id), L_SET);
147             switch (read(fd, &dq_dqb, sizeof(struct dqblk))) {
148                case 0:/* EOF */
149                   /*
150                    * Convert implicit 0 quota (EOF) into an
151                    * explicit one (zero'ed dqblk)
152                    */
153                   memset((caddr_t)&dq_dqb, 0, sizeof(struct dqblk));
154                   break;
155                case sizeof(struct dqblk):   /* OK */
156                   break;
157                default:   /* ERROR */
158                   close(fd);
159                   continue;
160             }
161             close(fd);
162          }
163          endmntent(fp);
164
165          if (err && (flags & ACTIVE)) {
166             result.status = Q_NOQUOTA;   
167             return(&result);
168          }
169
170          result.status = Q_OK;   
171          result.getquota_rslt_u.gqr_rquota.rq_active = (err == 0) ? TRUE : FALSE;
172          /*
173           * Make a copy of the info into the last part of the remote quota
174           * struct might not be exactly the same on all architectures...
175           */
176
177          rquota = &result.getquota_rslt_u.gqr_rquota;
178          rquota->rq_bhardlimit = dq_dqb.dqb_bhardlimit;
179          rquota->rq_bsoftlimit = dq_dqb.dqb_bsoftlimit;;
180          rquota->rq_curblocks = dq_dqb.dqb_curblocks;
181          rquota->rq_fhardlimit = dq_dqb.dqb_ihardlimit;
182          rquota->rq_fsoftlimit = dq_dqb.dqb_isoftlimit;
183          rquota->rq_curfiles = dq_dqb.dqb_curinodes;
184          rquota->rq_btimeleft = dq_dqb.dqb_btime;
185          rquota->rq_ftimeleft = dq_dqb.dqb_itime;
186
187          return(&result);
188       }
189    }
190    endmntent(fp);
191
192    result.status = Q_NOQUOTA;   
193    return(&result);
194 }
195
196 getquota_rslt *rquotaproc_getquota_1(getquota_args *argp, struct svc_req *rqstp)
197 {
198    return(getquotainfo(0, (caddr_t *)argp, rqstp));
199 }
200
201 getquota_rslt *rquotaproc_getactivequota_1(getquota_args *argp, struct svc_req *rqstp)
202 {
203    return(getquotainfo(ACTIVE, (caddr_t *)argp, rqstp));
204 }
205
206 getquota_rslt *rquotaproc_getquota_2(ext_getquota_args *argp, struct svc_req *rqstp)
207 {
208    return(getquotainfo(TYPE_EXTENDED, (caddr_t *)argp, rqstp));
209 }
210
211 getquota_rslt *rquotaproc_getactivequota_2(ext_getquota_args *argp, struct svc_req *rqstp)
212 {
213    return(getquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *)argp, rqstp));
214 }