diff options
author | Yang Lin <lin.a.yang@intel.com> | 2012-05-30 19:43:21 +0800 |
---|---|---|
committer | Yang Lin <lin.a.yang@intel.com> | 2012-05-30 19:43:21 +0800 |
commit | 8c82de96cd23e4823a2d29eb2de2295c0866b0c9 (patch) | |
tree | 4c255e87442eb17f710f1674e13303ff56be0c7a /rquota_server.c | |
download | quota-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.c | 331 |
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)); +} |