summaryrefslogtreecommitdiffstats
path: root/libexec/rpc.rquotad
diff options
context:
space:
mode:
authorgraichen <graichen@FreeBSD.org>1996-01-05 08:47:12 +0000
committergraichen <graichen@FreeBSD.org>1996-01-05 08:47:12 +0000
commit4f5719b08f9e2aa8ee228443fc01f1a124c28b33 (patch)
tree6f64caae37d03a4cac9e8d2d37d3d282d3162171 /libexec/rpc.rquotad
parent2e79ca4db7e3218540c5337cd282d56ea73ebd22 (diff)
downloadFreeBSD-src-4f5719b08f9e2aa8ee228443fc01f1a124c28b33.zip
FreeBSD-src-4f5719b08f9e2aa8ee228443fc01f1a124c28b33.tar.gz
Obtained from: NetBSD
Imported rpc.rquotad from NetBSD - currently only used by the quota-command to display quota's over nfs
Diffstat (limited to 'libexec/rpc.rquotad')
-rw-r--r--libexec/rpc.rquotad/Makefile10
-rw-r--r--libexec/rpc.rquotad/rpc.rquotad.858
-rw-r--r--libexec/rpc.rquotad/rquotad.c331
3 files changed, 399 insertions, 0 deletions
diff --git a/libexec/rpc.rquotad/Makefile b/libexec/rpc.rquotad/Makefile
new file mode 100644
index 0000000..7618d98
--- /dev/null
+++ b/libexec/rpc.rquotad/Makefile
@@ -0,0 +1,10 @@
+# $Id: Makefile,v 1.3 1995/04/12 00:47:27 jtc Exp $
+
+PROG = rpc.rquotad
+SRCS = rquotad.c
+MAN8 = rpc.rquotad.8
+
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
+.include <bsd.prog.mk>
diff --git a/libexec/rpc.rquotad/rpc.rquotad.8 b/libexec/rpc.rquotad/rpc.rquotad.8
new file mode 100644
index 0000000..b378cc3
--- /dev/null
+++ b/libexec/rpc.rquotad/rpc.rquotad.8
@@ -0,0 +1,58 @@
+.\"
+.\" Copyright (c) 1994 Theo de Raadt
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Theo de Raadt.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: rpc.rquotad.8,v 1.2 1995/04/12 00:47:32 jtc Exp $
+.\"
+.Dd June 22, 1994
+.Dt RPC.RQUOTAD 8
+.Os BSD 4.3
+.Sh NAME
+.Nm rpc.rquotad
+.Nd remote quota server
+.Sh SYNOPSIS
+.Nm /usr/libexec/rpc.rquotad
+.Sh DESCRIPTION
+.Nm rpc.rquotad
+is a
+.Xr rpc 3
+server which returns quotas for a user of a local filesystem
+which is NFS-mounted onto a remote machine.
+.Xr quota 1
+uses the results to display user quotas for remote filesystems.
+.Nm rpc.rquotad
+is normally invoked by
+.Xr inetd 8 .
+.Pp
+.Nm rpc.rquotad
+uses an RPC protocol defined in
+.Pa /usr/include/rpcsvc/rquota.x .
+.Sh BUGS
+BSD 4.4 and NetBSD support group quotas but the rquota protocol does not.
+.Sh SEE ALSO
+.Xr quota 1
diff --git a/libexec/rpc.rquotad/rquotad.c b/libexec/rpc.rquotad/rquotad.c
new file mode 100644
index 0000000..33fa420
--- /dev/null
+++ b/libexec/rpc.rquotad/rquotad.c
@@ -0,0 +1,331 @@
+/*
+ * by Manuel Bouyer (bouyer@ensta.fr)
+ *
+ * There is no copyright, you can use it as you want.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <signal.h>
+
+#include <stdio.h>
+#include <fstab.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+
+#include <syslog.h>
+#include <varargs.h>
+
+#include <ufs/ufs/quota.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpcsvc/rquota.h>
+#include <arpa/inet.h>
+
+void rquota_service __P((struct svc_req *request, SVCXPRT *transp));
+void sendquota __P((struct svc_req *request, SVCXPRT *transp));
+void printerr_reply __P((SVCXPRT *transp));
+void initfs __P((void));
+int getfsquota __P((long id, char *path, struct dqblk *dqblk));
+int hasquota __P((struct fstab *fs, char **qfnamep));
+
+/*
+ * structure containing informations about ufs filesystems
+ * initialised by initfs()
+ */
+struct fs_stat {
+ struct fs_stat *fs_next; /* next element */
+ char *fs_file; /* mount point of the filesystem */
+ char *qfpathname; /* pathname of the quota file */
+ dev_t st_dev; /* device of the filesystem */
+} fs_stat;
+struct fs_stat *fs_begin = NULL;
+
+int from_inetd = 1;
+
+void
+cleanup()
+{
+ (void) pmap_unset(RQUOTAPROG, RQUOTAVERS);
+ exit(0);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SVCXPRT *transp;
+ int sock = 0;
+ int proto = 0;
+ struct sockaddr_in from;
+ int fromlen;
+
+ fromlen = sizeof(from);
+ if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ from_inetd = 0;
+ sock = RPC_ANYSOCK;
+ proto = IPPROTO_UDP;
+ }
+
+ if (!from_inetd) {
+ daemon(0, 0);
+
+ (void) pmap_unset(RQUOTAPROG, RQUOTAVERS);
+
+ (void) signal(SIGINT, cleanup);
+ (void) signal(SIGTERM, cleanup);
+ (void) signal(SIGHUP, cleanup);
+ }
+
+ openlog("rpc.rquotad", LOG_CONS|LOG_PID, LOG_DAEMON);
+
+ /* create and register the service */
+ transp = svcudp_create(sock);
+ if (transp == NULL) {
+ syslog(LOG_ERR, "couldn't create udp service.");
+ exit(1);
+ }
+ if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquota_service, proto)) {
+ syslog(LOG_ERR, "unable to register (RQUOTAPROG, RQUOTAVERS, %s).", proto?"udp":"(inetd)");
+ exit(1);
+ }
+
+ initfs(); /* init the fs_stat list */
+ svc_run();
+ syslog(LOG_ERR, "svc_run returned");
+ exit(1);
+}
+
+void
+rquota_service(request, transp)
+ struct svc_req *request;
+ SVCXPRT *transp;
+{
+ switch (request->rq_proc) {
+ case NULLPROC:
+ (void)svc_sendreply(transp, xdr_void, (char *)NULL);
+ break;
+
+ case RQUOTAPROC_GETQUOTA:
+ case RQUOTAPROC_GETACTIVEQUOTA:
+ sendquota(request, transp);
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ break;
+ }
+ if (from_inetd)
+ exit(0);
+}
+
+/* read quota for the specified id, and send it */
+void
+sendquota(request, transp)
+ struct svc_req *request;
+ SVCXPRT *transp;
+{
+ struct getquota_args getq_args;
+ struct getquota_rslt getq_rslt;
+ struct dqblk dqblk;
+ struct timeval timev;
+
+ bzero((char *)&getq_args, sizeof(getq_args));
+ if (!svc_getargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
+ svcerr_decode(transp);
+ return;
+ }
+ if (request->rq_cred.oa_flavor != AUTH_UNIX) {
+ /* bad auth */
+ getq_rslt.status = Q_EPERM;
+ } else if (!getfsquota(getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
+ /* failed, return noquota */
+ getq_rslt.status = Q_NOQUOTA;
+ } else {
+ gettimeofday(&timev, NULL);
+ getq_rslt.status = Q_OK;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = DEV_BSIZE;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
+ dqblk.dqb_bhardlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
+ dqblk.dqb_bsoftlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
+ dqblk.dqb_curblocks;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
+ dqblk.dqb_ihardlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
+ dqblk.dqb_isoftlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
+ dqblk.dqb_curinodes;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
+ dqblk.dqb_btime - timev.tv_sec;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
+ dqblk.dqb_itime - timev.tv_sec;
+ }
+ if (!svc_sendreply(transp, xdr_getquota_rslt, (char *)&getq_rslt)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
+ syslog(LOG_ERR, "unable to free arguments");
+ exit(1);
+ }
+}
+
+void
+printerr_reply(transp) /* when a reply to a request failed */
+ SVCXPRT *transp;
+{
+ char *name;
+ struct sockaddr_in *caller;
+ int save_errno;
+
+ save_errno = errno;
+
+ caller = svc_getcaller(transp);
+ name = (char *)inet_ntoa(caller->sin_addr);
+ errno = save_errno;
+ if (errno == 0)
+ syslog(LOG_ERR, "couldn't send reply to %s", name);
+ else
+ syslog(LOG_ERR, "couldn't send reply to %s: %m", name);
+}
+
+/* initialise the fs_tab list from entries in /etc/fstab */
+void
+initfs()
+{
+ struct fs_stat *fs_current = NULL;
+ struct fs_stat *fs_next = NULL;
+ char *qfpathname;
+ struct fstab *fs;
+ struct stat st;
+
+ setfsent();
+ while ((fs = getfsent())) {
+ if (strcmp(fs->fs_vfstype, "ufs"))
+ continue;
+ if (!hasquota(fs, &qfpathname))
+ continue;
+
+ fs_current = (struct fs_stat *) malloc(sizeof(struct fs_stat));
+ fs_current->fs_next = fs_next; /* next element */
+
+ fs_current->fs_file = malloc(sizeof(char) * (strlen(fs->fs_file) + 1));
+ strcpy(fs_current->fs_file, fs->fs_file);
+
+ fs_current->qfpathname = malloc(sizeof(char) * (strlen(qfpathname) + 1));
+ strcpy(fs_current->qfpathname, qfpathname);
+
+ stat(qfpathname, &st);
+ fs_current->st_dev = st.st_dev;
+
+ fs_next = fs_current;
+ }
+ endfsent();
+ fs_begin = fs_current;
+}
+
+/*
+ * gets the quotas for id, filesystem path.
+ * Return 0 if fail, 1 otherwise
+ */
+int
+getfsquota(id, path, dqblk)
+ long id;
+ char *path;
+ struct dqblk *dqblk;
+{
+ struct stat st_path;
+ struct fs_stat *fs;
+ int qcmd, fd, ret = 0;
+
+ if (stat(path, &st_path) < 0)
+ return (0);
+
+ qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
+
+ for (fs = fs_begin; fs != NULL; fs = fs->fs_next) {
+ /* where the devise is the same as path */
+ if (fs->st_dev != st_path.st_dev)
+ continue;
+
+ /* find the specified filesystem. get and return quota */
+ if (quotactl(fs->fs_file, qcmd, id, dqblk) == 0)
+ return (1);
+
+ if ((fd = open(fs->qfpathname, O_RDONLY)) < 0) {
+ syslog(LOG_ERR, "open error: %s: %m", fs->qfpathname);
+ return (0);
+ }
+ if (lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET) == (off_t)-1) {
+ close(fd);
+ return (1);
+ }
+ switch (read(fd, dqblk, sizeof(struct dqblk))) {
+ case 0:
+ /*
+ * Convert implicit 0 quota (EOF)
+ * into an explicit one (zero'ed dqblk)
+ */
+ bzero((caddr_t) dqblk, sizeof(struct dqblk));
+ ret = 1;
+ break;
+ case sizeof(struct dqblk): /* OK */
+ ret = 1;
+ break;
+ default: /* ERROR */
+ syslog(LOG_ERR, "read error: %s: %m", fs->qfpathname);
+ close(fd);
+ return (0);
+ }
+ close(fd);
+ }
+ return (ret);
+}
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ * Comes from quota.c, NetBSD 0.9
+ */
+int
+hasquota(fs, qfnamep)
+ struct fstab *fs;
+ char **qfnamep;
+{
+ static char initname, usrname[100];
+ static char buf[BUFSIZ];
+ char *opt, *cp;
+ char *qfextension[] = INITQFNAMES;
+
+ if (!initname) {
+ sprintf(usrname, "%s%s", qfextension[USRQUOTA], QUOTAFILENAME);
+ initname = 1;
+ }
+ strcpy(buf, fs->fs_mntops);
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if ((cp = index(opt, '=')))
+ *cp++ = '\0';
+ if (strcmp(opt, usrname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp) {
+ *qfnamep = cp;
+ return (1);
+ }
+ sprintf(buf, "%s/%s.%s", fs->fs_file, QUOTAFILENAME, qfextension[USRQUOTA]);
+ *qfnamep = buf;
+ return (1);
+}
OpenPOWER on IntegriCloud