summaryrefslogtreecommitdiff
path: root/rquota_server.c
diff options
context:
space:
mode:
authorYang Lin <lin.a.yang@intel.com>2012-05-30 19:43:21 +0800
committerYang Lin <lin.a.yang@intel.com>2012-05-30 19:43:21 +0800
commit8c82de96cd23e4823a2d29eb2de2295c0866b0c9 (patch)
tree4c255e87442eb17f710f1674e13303ff56be0c7a /rquota_server.c
downloadquota-8c82de96cd23e4823a2d29eb2de2295c0866b0c9.tar.gz
quota-8c82de96cd23e4823a2d29eb2de2295c0866b0c9.tar.bz2
quota-8c82de96cd23e4823a2d29eb2de2295c0866b0c9.zip
Initial commit to Gerrittizen/20120530.11.0_branch1.0
Diffstat (limited to 'rquota_server.c')
-rw-r--r--rquota_server.c331
1 files changed, 331 insertions, 0 deletions
diff --git a/rquota_server.c b/rquota_server.c
new file mode 100644
index 0000000..cb3c44d
--- /dev/null
+++ b/rquota_server.c
@@ -0,0 +1,331 @@
+/*
+ * QUOTA An implementation of the diskquota system for the LINUX
+ * operating system. QUOTA is implemented using the BSD systemcall
+ * interface as the means of communication with the user level.
+ * Should work for all filesystems because of integration into the
+ * VFS layer of the operating system.
+ * This is based on the Melbourne quota system wich uses both user and
+ * group quota files.
+ *
+ * This part does the lookup of the info.
+ *
+ * Version: $Id: rquota_server.c,v 1.22 2010/01/05 16:04:57 jkar8572 Exp $
+ *
+ * Author: Marco van Wieringen <mvw@planets.elm.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "config.h"
+
+#include <rpc/rpc.h>
+#include <arpa/inet.h>
+#include <paths.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <time.h>
+
+#include "mntopt.h"
+#include "quotaops.h"
+#include "bylabel.h"
+#include "rquota.h"
+#include "quotaio.h"
+#include "quotasys.h"
+#include "dqblk_rpc.h"
+#include "common.h"
+
+#define STDIN_FILENO 0
+
+#define TYPE_EXTENDED 0x01
+#define ACTIVE 0x02
+
+#define FACILITY LOG_LOCAL7
+
+#ifndef MAXPATHNAMELEN
+#define MAXPATHNAMELEN BUFSIZ
+#endif
+
+#define NETTYPE AF_INET
+
+/* Options from rquota_svc.c */
+#define FL_AUTOFS 4
+extern int flags;
+
+extern char nfs_pseudoroot[PATH_MAX];
+
+/*
+ * Global unix authentication credentials.
+ */
+extern struct authunix_parms *unix_cred;
+
+int in_group(gid_t * gids, u_int len, gid_t gid)
+{
+ gid_t *gidsp = gids + len;
+
+ while (gidsp > gids)
+ if (*(--gids) == gid)
+ return 1;
+
+ return 0;
+}
+
+static inline void servnet2utildqblk(struct util_dqblk *u, sq_dqblk * n)
+{
+ time_t now;
+
+ time(&now);
+ u->dqb_bhardlimit = n->rq_bhardlimit;
+ u->dqb_bsoftlimit = n->rq_bsoftlimit;
+ u->dqb_ihardlimit = n->rq_fhardlimit;
+ u->dqb_isoftlimit = n->rq_fsoftlimit;
+ u->dqb_curspace = ((qsize_t)n->rq_curblocks) << RPC_DQBLK_SIZE_BITS;
+ u->dqb_curinodes = n->rq_curfiles;
+ if (n->rq_btimeleft)
+ u->dqb_btime = n->rq_btimeleft + now;
+ else
+ u->dqb_btime = 0;
+ if (n->rq_ftimeleft)
+ u->dqb_itime = n->rq_ftimeleft + now;
+ else
+ u->dqb_itime = 0;
+}
+
+static inline void servutil2netdqblk(struct rquota *n, struct util_dqblk *u)
+{
+ time_t now;
+
+ time(&now);
+ n->rq_bhardlimit = (u->dqb_bhardlimit << QUOTABLOCK_BITS) >> RPC_DQBLK_SIZE_BITS;
+ n->rq_bsoftlimit = (u->dqb_bsoftlimit << QUOTABLOCK_BITS) >> RPC_DQBLK_SIZE_BITS;
+ n->rq_fhardlimit = u->dqb_ihardlimit;
+ n->rq_fsoftlimit = u->dqb_isoftlimit;
+ n->rq_curblocks = (u->dqb_curspace + RPC_DQBLK_SIZE - 1) >> RPC_DQBLK_SIZE_BITS;
+ n->rq_curfiles = u->dqb_curinodes;
+ if (u->dqb_btime)
+ n->rq_btimeleft = u->dqb_btime - now;
+ else
+ n->rq_btimeleft = 0;
+ if (u->dqb_itime)
+ n->rq_ftimeleft = u->dqb_itime - now;
+ else
+ n->rq_ftimeleft = 0;
+}
+
+setquota_rslt *setquotainfo(int lflags, caddr_t * argp, struct svc_req *rqstp)
+{
+ static setquota_rslt result;
+
+#if defined(RPC_SETQUOTA)
+ union {
+ setquota_args *args;
+ ext_setquota_args *ext_args;
+ } arguments;
+ struct util_dqblk dqblk;
+ struct dquot *dquot;
+ struct mntent *mnt;
+ char pathname[PATH_MAX] = {0};
+ char *pathp = pathname;
+ int id, qcmd, type;
+ struct quota_handle *handles[2] = { NULL, NULL };
+
+ /*
+ * First check authentication.
+ */
+ if (lflags & TYPE_EXTENDED) {
+ arguments.ext_args = (ext_setquota_args *) argp;
+
+ id = arguments.ext_args->sqa_id;
+ if (unix_cred->aup_uid != 0) {
+ result.status = Q_EPERM;
+ return (&result);
+ }
+
+ qcmd = arguments.ext_args->sqa_qcmd;
+ type = arguments.ext_args->sqa_type;
+ if (arguments.ext_args->sqa_pathp[0] != '/')
+ sstrncpy(pathname, nfs_pseudoroot, PATH_MAX);
+ sstrncat(pathname, arguments.ext_args->sqa_pathp, PATH_MAX);
+ servnet2utildqblk(&dqblk, &arguments.ext_args->sqa_dqblk);
+ }
+ else {
+ arguments.args = (setquota_args *) argp;
+
+ id = arguments.args->sqa_id;
+ if (unix_cred->aup_uid != 0) {
+ result.status = Q_EPERM;
+ return (&result);
+ }
+
+ qcmd = arguments.args->sqa_qcmd;
+ type = USRQUOTA;
+ if (arguments.args->sqa_pathp[0] != '/')
+ sstrncpy(pathname, nfs_pseudoroot, PATH_MAX);
+ sstrncat(pathname, arguments.args->sqa_pathp, PATH_MAX);
+ servnet2utildqblk(&dqblk, &arguments.args->sqa_dqblk);
+ }
+
+ result.status = Q_NOQUOTA;
+ result.setquota_rslt_u.sqr_rquota.rq_bsize = RPC_DQBLK_SIZE;
+
+ if (init_mounts_scan(1, &pathp, MS_QUIET | MS_NO_MNTPOINT | MS_NFS_ALL | ((flags & FL_AUTOFS) ? 0 : MS_NO_AUTOFS)) < 0)
+ goto out;
+ if (!(mnt = get_next_mount())) {
+ end_mounts_scan();
+ goto out;
+ }
+ if (!(handles[0] = init_io(mnt, type, -1, 0))) {
+ end_mounts_scan();
+ goto out;
+ }
+ end_mounts_scan();
+ if (!(dquot = handles[0]->qh_ops->read_dquot(handles[0], id)))
+ goto out;
+ if (qcmd == QCMD(Q_RPC_SETQLIM, type) || qcmd == QCMD(Q_RPC_SETQUOTA, type)) {
+ dquot->dq_dqb.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
+ dquot->dq_dqb.dqb_bhardlimit = dqblk.dqb_bhardlimit;
+ dquot->dq_dqb.dqb_isoftlimit = dqblk.dqb_isoftlimit;
+ dquot->dq_dqb.dqb_ihardlimit = dqblk.dqb_ihardlimit;
+ dquot->dq_dqb.dqb_btime = dqblk.dqb_btime;
+ dquot->dq_dqb.dqb_itime = dqblk.dqb_itime;
+ }
+ if (qcmd == QCMD(Q_RPC_SETUSE, type) || qcmd == QCMD(Q_RPC_SETQUOTA, type)) {
+ dquot->dq_dqb.dqb_curspace = dqblk.dqb_curspace;
+ dquot->dq_dqb.dqb_curinodes = dqblk.dqb_curinodes;
+ }
+ if (handles[0]->qh_ops->commit_dquot(dquot, COMMIT_LIMITS) == -1) {
+ free(dquot);
+ goto out;
+ }
+ free(dquot);
+ result.status = Q_OK;
+out:
+ dispose_handle_list(handles);
+#else
+ result.status = Q_EPERM;
+#endif
+ return (&result);
+}
+
+getquota_rslt *getquotainfo(int lflags, caddr_t * argp, struct svc_req * rqstp)
+{
+ static getquota_rslt result;
+ union {
+ getquota_args *args;
+ ext_getquota_args *ext_args;
+ } arguments;
+ struct dquot *dquot = NULL;
+ struct mntent *mnt;
+ char pathname[PATH_MAX] = {0};
+ char *pathp = pathname;
+ int id, type;
+ struct quota_handle *handles[2] = { NULL, NULL };
+
+ /*
+ * First check authentication.
+ */
+ if (lflags & TYPE_EXTENDED) {
+ arguments.ext_args = (ext_getquota_args *) argp;
+ id = arguments.ext_args->gqa_id;
+ type = arguments.ext_args->gqa_type;
+ if (arguments.ext_args->gqa_pathp[0] != '/')
+ sstrncpy(pathname, nfs_pseudoroot, PATH_MAX);
+ sstrncat(pathname, arguments.ext_args->gqa_pathp, PATH_MAX);
+
+ if (type == USRQUOTA && unix_cred->aup_uid && unix_cred->aup_uid != id) {
+ result.status = Q_EPERM;
+ return (&result);
+ }
+
+ if (type == GRPQUOTA && unix_cred->aup_uid && unix_cred->aup_gid != id &&
+ !in_group((gid_t *) unix_cred->aup_gids, unix_cred->aup_len, id)) {
+ result.status = Q_EPERM;
+ return (&result);
+ }
+ }
+ else {
+ arguments.args = (getquota_args *) argp;
+ id = arguments.args->gqa_uid;
+ type = USRQUOTA;
+ if (arguments.ext_args->gqa_pathp[0] != '/')
+ sstrncpy(pathname, nfs_pseudoroot, PATH_MAX);
+ sstrncat(pathname, arguments.args->gqa_pathp, PATH_MAX);
+
+ if (unix_cred->aup_uid && unix_cred->aup_uid != id) {
+ result.status = Q_EPERM;
+ return (&result);
+ }
+ }
+
+ result.status = Q_NOQUOTA;
+ result.getquota_rslt_u.gqr_rquota.rq_bsize = RPC_DQBLK_SIZE;
+
+ if (init_mounts_scan(1, &pathp, MS_QUIET | MS_NO_MNTPOINT | MS_NFS_ALL | ((flags & FL_AUTOFS) ? 0 : MS_NO_AUTOFS)) < 0)
+ goto out;
+ if (!(mnt = get_next_mount())) {
+ end_mounts_scan();
+ goto out;
+ }
+ if (!(handles[0] = init_io(mnt, type, -1, IOI_READONLY))) {
+ end_mounts_scan();
+ goto out;
+ }
+ end_mounts_scan();
+ if (!(lflags & ACTIVE) || QIO_ENABLED(handles[0]))
+ dquot = handles[0]->qh_ops->read_dquot(handles[0], id);
+ if (dquot) {
+ result.status = Q_OK;
+ result.getquota_rslt_u.gqr_rquota.rq_active =
+ QIO_ENABLED(handles[0]) ? TRUE : FALSE;
+ servutil2netdqblk(&result.getquota_rslt_u.gqr_rquota, &dquot->dq_dqb);
+ free(dquot);
+ }
+out:
+ dispose_handle_list(handles);
+ return (&result);
+}
+
+/*
+ * Map RPC-entrypoints to local function names.
+ */
+getquota_rslt *rquotaproc_getquota_1_svc(getquota_args * argp, struct svc_req * rqstp)
+{
+ return (getquotainfo(0, (caddr_t *) argp, rqstp));
+}
+
+getquota_rslt *rquotaproc_getactivequota_1_svc(getquota_args * argp, struct svc_req * rqstp)
+{
+ return (getquotainfo(ACTIVE, (caddr_t *) argp, rqstp));
+}
+
+getquota_rslt *rquotaproc_getquota_2_svc(ext_getquota_args * argp, struct svc_req * rqstp)
+{
+ return (getquotainfo(TYPE_EXTENDED, (caddr_t *) argp, rqstp));
+}
+
+getquota_rslt *rquotaproc_getactivequota_2_svc(ext_getquota_args * argp, struct svc_req * rqstp)
+{
+ return (getquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *) argp, rqstp));
+}
+
+setquota_rslt *rquotaproc_setquota_1_svc(setquota_args * argp, struct svc_req * rqstp)
+{
+ return (setquotainfo(0, (caddr_t *) argp, rqstp));
+}
+
+setquota_rslt *rquotaproc_setactivequota_1_svc(setquota_args * argp, struct svc_req * rqstp)
+{
+ return (setquotainfo(ACTIVE, (caddr_t *) argp, rqstp));
+}
+
+setquota_rslt *rquotaproc_setquota_2_svc(ext_setquota_args * argp, struct svc_req * rqstp)
+{
+ return (setquotainfo(TYPE_EXTENDED, (caddr_t *) argp, rqstp));
+}
+
+setquota_rslt *rquotaproc_setactivequota_2_svc(ext_setquota_args * argp, struct svc_req * rqstp)
+{
+ return (setquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *) argp, rqstp));
+}