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