from bouyer@ensta.fr; cleaned by me

This commit is contained in:
deraadt 1994-06-24 07:42:26 +00:00
parent 32a94e53c4
commit 8b6e0e0481
3 changed files with 389 additions and 0 deletions

View File

@ -0,0 +1,9 @@
# $Id: Makefile,v 1.1 1994/06/24 07:42:26 deraadt Exp $
PROG = rpc.rquotad
SRCS = rquotad.c
DPADD= ${LIBRPCSVC}
LDADD= -lrpcsvc
.include <bsd.prog.mk>

View File

@ -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.1 1994/06/24 07:42:29 deraadt 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

View File

@ -0,0 +1,322 @@
/*
* 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/signal.h>
#include <stdio.h>
#include <fstab.h>
#include <ctype.h>
#include <stdlib.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 <rpcsvc/rquota.h>
void rquota_svc __P((struct svc_req *request, SVCXPRT *transport));
void exit_svc __P((int signo));
void sendquota __P((struct svc_req *request, SVCXPRT *transport));
void printerr_reply __P((SVCXPRT *transport));
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
main(argc, argv)
int argc;
char *argv[];
{
SVCXPRT *transport;
int sock = 0;
int proto = 0;
int from_inetd = 1;
struct sockaddr_in from;
int fromlen;
openlog("rquotad", LOG_PID, LOG_DAEMON);
if (getsockname(0, (struct sockaddr *) & from, &fromlen) < 0) {
from_inetd = 0;
sock = RPC_ANYSOCK;
proto = IPPROTO_UDP;
}
if (!from_inetd) {
daemon(0, 0);
pmap_unset(RQUOTAPROG, RQUOTAVERS);
signal(SIGINT, exit_svc); /* trap some signals */
signal(SIGQUIT, exit_svc); /* to unregister the service */
signal(SIGTERM, exit_svc); /* before exiting */
}
/* create and register the service */
if ((transport = svcudp_create(sock)) == NULL) {
syslog(LOG_ERR, "couldn't create UDP transport");
exit(1);
}
if (svc_register(transport, RQUOTAPROG, RQUOTAVERS,
rquota_svc, proto) == 0) {
syslog(LOG_ERR, "couldn't register service");
exit(1);
}
initfs(); /* init the fs_stat list */
svc_run();
syslog(LOG_ERR, "svc_run has returned !");
exit(1); /* svc_run don't return */
}
/* rquota service */
void
rquota_svc(request, transport)
struct svc_req *request;
SVCXPRT *transport;
{
switch (request->rq_proc) {
case NULLPROC:
errno = 0;
if (svc_sendreply(transport, xdr_void, 0) == 0)
printerr_reply(transport);
break;
case RQUOTAPROC_GETQUOTA:
case RQUOTAPROC_GETACTIVEQUOTA:
sendquota(request, transport);
break;
default:
svcerr_noproc(transport);
break;
}
return;
}
/* read quota for the specified id, and send it */
void
sendquota(request, transport)
struct svc_req *request;
SVCXPRT *transport;
{
struct getquota_args getq_args;
struct getquota_rslt getq_rslt;
struct dqblk dqblk;
struct timeval timev;
getq_args.gqa_pathp = NULL; /* allocated by svc_getargs */
if (svc_getargs(transport, xdr_getquota_args, &getq_args) == 0) {
svcerr_decode(transport);
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) == 0) {
getq_rslt.status = Q_NOQUOTA; /* failed, return 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(transport, xdr_getquota_rslt, (char *)&getq_rslt) == 0)
printerr_reply(transport);
return;
}
void
exit_svc(signo) /* signal trapped */
int signo;
{
syslog(LOG_ERR, "exiting on signal %d", signo);
pmap_unset(RQUOTAPROG, RQUOTAVERS);
exit(0);
}
void
printerr_reply(transport) /* when a reply to a request failed */
SVCXPRT *transport;
{
char *name;
struct sockaddr_in *caller;
int save_errno;
save_errno = errno;
caller = svc_getcaller(transport);
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);
return;
}
/* 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;
char *qfextension[] = INITQFNAMES;
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;
char *qfextension[] = INITQFNAMES;
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, "couldn't read %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);
}