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