1/*
2 *
3 * parts of this are lifted from the bsd quota program and are
4 * therefore under the following copyright:
5 *
6 * Copyright (c) 1980, 1990, 1993
7 *      The Regents of the University of California.  All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Robert Elz at The University of Melbourne.
11 *
12 * Ported for AIX (jfs) by Joerg Schumacher (J.Schumacher@tu-bs.de) at the
13 * Technische Universitaet Braunschweig, FRG
14 */
15
16#ifdef HAVE_CONFIG_H
17#include "config.h"
18#endif /* HAVE_CONFIG_H */
19
20#if !defined(NO_QUOTA_SUPPORT) && !defined(HAVE_LIBQUOTA)
21#include <stdio.h>
22#include <string.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <sys/param.h> /* for DEV_BSIZE */
26#include <sys/time.h>  /* <rpc/rpc.h> on ultrix doesn't include this */
27#ifdef HAVE_NETDB_H
28#include <netdb.h>
29#endif /* HAVE_NETDB_H */
30#include <netinet/in.h>
31#ifndef PORTMAP
32#define PORTMAP 1
33#endif
34#include <rpc/rpc.h>
35#include <rpc/pmap_prot.h>
36#include <rpcsvc/rquota.h>
37
38
39#include <atalk/afp.h>
40#include <atalk/logger.h>
41
42#include "unix.h"
43
44/* lifted (with modifications) from the bsd quota program */
45static int
46callaurpc(struct vol *vol,
47    u_long prognum, u_long versnum, u_long procnum,
48    xdrproc_t inproc, char *in,
49    xdrproc_t outproc, char *out)
50{
51    enum clnt_stat clnt_stat;
52    struct timeval tottimeout;
53
54    if (!vol->v_nfsclient) {
55        struct hostent *hp;
56        struct sockaddr_in server_addr;
57        struct timeval timeout;
58        int socket = RPC_ANYSOCK;
59
60        if ((hp = gethostbyname(vol->v_gvs)) == NULL)
61            return ((int) RPC_UNKNOWNHOST);
62        timeout.tv_usec = 0;
63        timeout.tv_sec = 6;
64        memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
65        server_addr.sin_family = AF_INET;
66        server_addr.sin_port =  0;
67
68        if ((vol->v_nfsclient = (void *)
69                                clntudp_create(&server_addr, prognum, versnum,
70                                               timeout, &socket)) == NULL)
71            return ((int) rpc_createerr.cf_stat);
72
73        ((CLIENT *) vol->v_nfsclient)->cl_auth = authunix_create_default();
74    }
75
76    tottimeout.tv_sec = 10;
77    tottimeout.tv_usec = 0;
78    clnt_stat = clnt_call((CLIENT *) vol->v_nfsclient, procnum,
79                          inproc, in, outproc, out, tottimeout);
80    return ((int) clnt_stat);
81}
82
83
84/* sunos 4 machines structure things a little differently. */
85#ifdef USE_OLD_RQUOTA
86#define GQR_STATUS gqr_status
87#define GQR_RQUOTA gqr_rquota
88#else /* USE_OLD_RQUOTA */
89#define GQR_STATUS status
90#define GQR_RQUOTA getquota_rslt_u.gqr_rquota
91#endif /* USE_OLD_RQUOTA */
92
93int getnfsquota(struct vol *vol, const int uid, const uint32_t bsize,
94                struct dqblk *dqp)
95{
96
97    struct getquota_args gq_args;
98    struct getquota_rslt gq_rslt;
99    struct timeval tv;
100    char *hostpath;
101
102    /* figure out the host and path */
103    if ((hostpath = strchr(vol->v_gvs, ':')) == NULL) {
104        LOG(log_error, logtype_afpd, "can't find hostname for %s", vol->v_gvs);
105        return AFPERR_PARAM;
106    }
107
108    if (*(hostpath + 1) != '/')
109        return AFPERR_PARAM;
110
111    /* separate host from hostpath */
112    *hostpath = '\0';
113
114    gq_args.gqa_pathp = hostpath + 1;
115    gq_args.gqa_uid = uid;
116
117    if(callaurpc(vol, RQUOTAPROG, RQUOTAVERS, RQUOTAPROC_GETQUOTA,
118                 (xdrproc_t) xdr_getquota_args, (char *) &gq_args,
119                 (xdrproc_t) xdr_getquota_rslt, (char *) &gq_rslt) != 0) {
120        LOG(log_info, logtype_afpd, "nfsquota: can't retrieve nfs quota information. \
121            make sure that rpc.rquotad is running on %s.", vol->v_gvs);
122        *hostpath = ':';
123        return AFPERR_PARAM;
124    }
125
126    switch (gq_rslt.GQR_STATUS) {
127    case Q_NOQUOTA:
128        break;
129
130    case Q_EPERM:
131        LOG(log_error, logtype_afpd, "nfsquota: quota permission error, host: %s",
132            vol->v_gvs);
133        break;
134
135    case Q_OK: /* we only copy the bits that we need. */
136        gettimeofday(&tv, NULL);
137
138#if defined(__svr4__) || defined(TRU64)
139        /* why doesn't using bsize work? */
140#define NFS_BSIZE gq_rslt.GQR_RQUOTA.rq_bsize / DEV_BSIZE
141#else /* __svr4__ || TRU64 */
142        /* NOTE: linux' rquotad program doesn't currently report the
143        * correct rq_bsize. */
144	/* NOTE: This is integer division and can introduce rounding errors */
145#define NFS_BSIZE gq_rslt.GQR_RQUOTA.rq_bsize / bsize
146#endif /* __svr4__  || TRU64 */
147
148        dqp->dqb_bhardlimit =
149            gq_rslt.GQR_RQUOTA.rq_bhardlimit*NFS_BSIZE;
150        dqp->dqb_bsoftlimit =
151            gq_rslt.GQR_RQUOTA.rq_bsoftlimit*NFS_BSIZE;
152        dqp->dqb_curblocks =
153            gq_rslt.GQR_RQUOTA.rq_curblocks*NFS_BSIZE;
154
155#ifdef ultrix
156        dqp->dqb_bwarn = gq_rslt.GQR_RQUOTA.rq_btimeleft;
157#else /* ultrix */
158        dqp->dqb_btimelimit =
159            tv.tv_sec + gq_rslt.GQR_RQUOTA.rq_btimeleft;
160#endif /* ultrix */
161
162        *hostpath = ':';
163        return AFP_OK;
164        break;
165
166    default:
167        LOG(log_info, logtype_afpd, "bad rpc result, host: %s", vol->v_gvs);
168        break;
169    }
170
171    *hostpath = ':';
172    return AFPERR_PARAM;
173}
174#endif /* ! NO_QUOTA_SUPPORT && !HAVE_LIBQUOTA */
175