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