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