1 /*
2  * Copyright (c) 1980, 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Robert Elz at The University of Melbourne.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * Ported for AIX (jfs) by Joerg Schumacher (J.Schumacher@tu-bs.de) at the
33  * Technische Universitaet Braunschweig, FRG
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif /* HAVE_CONFIG_H */
39 
40 #if !defined(NO_QUOTA_SUPPORT) && !defined(HAVE_LIBQUOTA)
41 #include <stdio.h>
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/param.h> /* for DEV_BSIZE */
46 #include <sys/time.h>  /* <rpc/rpc.h> on ultrix doesn't include this */
47 #ifdef HAVE_NETDB_H
48 #include <netdb.h>
49 #endif /* HAVE_NETDB_H */
50 #include <netinet/in.h>
51 #ifndef PORTMAP
52 #define PORTMAP 1
53 #endif
54 #include <rpc/rpc.h>
55 #include <rpc/pmap_prot.h>
56 #include <rpcsvc/rquota.h>
57 
58 
59 #include <atalk/afp.h>
60 #include <atalk/logger.h>
61 
62 #include "unix.h"
63 
64 /* lifted (with modifications) from the bsd quota program */
65 static int
callaurpc(struct vol * vol,u_long prognum,u_long versnum,u_long procnum,xdrproc_t inproc,char * in,xdrproc_t outproc,char * out)66 callaurpc(struct vol *vol,
67     u_long prognum, u_long versnum, u_long procnum,
68     xdrproc_t inproc, char *in,
69     xdrproc_t outproc, char *out)
70 {
71     enum clnt_stat clnt_stat;
72     struct timeval tottimeout;
73 
74     if (!vol->v_nfsclient) {
75         struct hostent *hp;
76         struct sockaddr_in server_addr;
77         struct timeval timeout;
78         int socket = RPC_ANYSOCK;
79 
80         if ((hp = gethostbyname(vol->v_gvs)) == NULL)
81             return ((int) RPC_UNKNOWNHOST);
82         timeout.tv_usec = 0;
83         timeout.tv_sec = 6;
84         memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
85         server_addr.sin_family = AF_INET;
86         server_addr.sin_port =  0;
87 
88         if ((vol->v_nfsclient = (void *)
89                                 clntudp_create(&server_addr, prognum, versnum,
90                                                timeout, &socket)) == NULL)
91             return ((int) rpc_createerr.cf_stat);
92 
93         ((CLIENT *) vol->v_nfsclient)->cl_auth = authunix_create_default();
94     }
95 
96     tottimeout.tv_sec = 10;
97     tottimeout.tv_usec = 0;
98     clnt_stat = clnt_call((CLIENT *) vol->v_nfsclient, procnum,
99                           inproc, in, outproc, out, tottimeout);
100     return ((int) clnt_stat);
101 }
102 
103 
104 /* sunos 4 machines structure things a little differently. */
105 #ifdef USE_OLD_RQUOTA
106 #define GQR_STATUS gqr_status
107 #define GQR_RQUOTA gqr_rquota
108 #else /* USE_OLD_RQUOTA */
109 #define GQR_STATUS status
110 #define GQR_RQUOTA getquota_rslt_u.gqr_rquota
111 #endif /* USE_OLD_RQUOTA */
112 
getnfsquota(struct vol * vol,const int uid,const uint32_t bsize,struct dqblk * dqp)113 int getnfsquota(struct vol *vol, const int uid, const uint32_t bsize,
114                 struct dqblk *dqp)
115 {
116 
117     struct getquota_args gq_args;
118     struct getquota_rslt gq_rslt;
119     struct timeval tv;
120     char *hostpath;
121 
122     /* figure out the host and path */
123     if ((hostpath = strchr(vol->v_gvs, ':')) == NULL) {
124         LOG(log_error, logtype_afpd, "can't find hostname for %s", vol->v_gvs);
125         return AFPERR_PARAM;
126     }
127 
128     if (*(hostpath + 1) != '/')
129         return AFPERR_PARAM;
130 
131     /* separate host from hostpath */
132     *hostpath = '\0';
133 
134     gq_args.gqa_pathp = hostpath + 1;
135     gq_args.gqa_uid = uid;
136 
137     if(callaurpc(vol, RQUOTAPROG, RQUOTAVERS, RQUOTAPROC_GETQUOTA,
138                  (xdrproc_t) xdr_getquota_args, (char *) &gq_args,
139                  (xdrproc_t) xdr_getquota_rslt, (char *) &gq_rslt) != 0) {
140         LOG(log_info, logtype_afpd, "nfsquota: can't retrieve nfs quota information. \
141             make sure that rpc.rquotad is running on %s.", vol->v_gvs);
142         *hostpath = ':';
143         return AFPERR_PARAM;
144     }
145 
146     switch (gq_rslt.GQR_STATUS) {
147     case Q_NOQUOTA:
148         break;
149 
150     case Q_EPERM:
151         LOG(log_error, logtype_afpd, "nfsquota: quota permission error, host: %s",
152             vol->v_gvs);
153         break;
154 
155     case Q_OK: /* we only copy the bits that we need. */
156         gettimeofday(&tv, NULL);
157 
158 #if defined(__svr4__) || defined(TRU64)
159         /* why doesn't using bsize work? */
160 #define NFS_BSIZE gq_rslt.GQR_RQUOTA.rq_bsize / DEV_BSIZE
161 #else /* __svr4__ || TRU64 */
162         /* NOTE: linux' rquotad program doesn't currently report the
163         * correct rq_bsize. */
164 	/* NOTE: This is integer division and can introduce rounding errors */
165 #define NFS_BSIZE gq_rslt.GQR_RQUOTA.rq_bsize / bsize
166 #endif /* __svr4__  || TRU64 */
167 
168         dqp->dqb_bhardlimit =
169             gq_rslt.GQR_RQUOTA.rq_bhardlimit*NFS_BSIZE;
170         dqp->dqb_bsoftlimit =
171             gq_rslt.GQR_RQUOTA.rq_bsoftlimit*NFS_BSIZE;
172         dqp->dqb_curblocks =
173             gq_rslt.GQR_RQUOTA.rq_curblocks*NFS_BSIZE;
174 
175 #ifdef ultrix
176         dqp->dqb_bwarn = gq_rslt.GQR_RQUOTA.rq_btimeleft;
177 #else /* ultrix */
178         dqp->dqb_btimelimit =
179             tv.tv_sec + gq_rslt.GQR_RQUOTA.rq_btimeleft;
180 #endif /* ultrix */
181 
182         *hostpath = ':';
183         return AFP_OK;
184         break;
185 
186     default:
187         LOG(log_info, logtype_afpd, "bad rpc result, host: %s", vol->v_gvs);
188         break;
189     }
190 
191     *hostpath = ':';
192     return AFPERR_PARAM;
193 }
194 #endif /* ! NO_QUOTA_SUPPORT && !HAVE_LIBQUOTA */
195