linux/fs/nfsd/nfs2acl.c
<<
>>
Prefs
   1/*
   2 * Process version 2 NFSACL requests.
   3 *
   4 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
   5 */
   6
   7#include "nfsd.h"
   8/* FIXME: nfsacl.h is a broken header */
   9#include <linux/nfsacl.h>
  10#include <linux/gfp.h>
  11#include "cache.h"
  12#include "xdr3.h"
  13#include "vfs.h"
  14
  15#define NFSDDBG_FACILITY                NFSDDBG_PROC
  16#define RETURN_STATUS(st)       { resp->status = (st); return (st); }
  17
  18/*
  19 * NULL call.
  20 */
  21static __be32
  22nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
  23{
  24        return nfs_ok;
  25}
  26
  27/*
  28 * Get the Access and/or Default ACL of a file.
  29 */
  30static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
  31                struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
  32{
  33        struct posix_acl *acl;
  34        struct inode *inode;
  35        svc_fh *fh;
  36        __be32 nfserr = 0;
  37
  38        dprintk("nfsd: GETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
  39
  40        fh = fh_copy(&resp->fh, &argp->fh);
  41        nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
  42        if (nfserr)
  43                RETURN_STATUS(nfserr);
  44
  45        inode = d_inode(fh->fh_dentry);
  46
  47        if (argp->mask & ~NFS_ACL_MASK)
  48                RETURN_STATUS(nfserr_inval);
  49        resp->mask = argp->mask;
  50
  51        nfserr = fh_getattr(fh, &resp->stat);
  52        if (nfserr)
  53                RETURN_STATUS(nfserr);
  54
  55        if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
  56                acl = get_acl(inode, ACL_TYPE_ACCESS);
  57                if (acl == NULL) {
  58                        /* Solaris returns the inode's minimum ACL. */
  59                        acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
  60                }
  61                if (IS_ERR(acl)) {
  62                        nfserr = nfserrno(PTR_ERR(acl));
  63                        goto fail;
  64                }
  65                resp->acl_access = acl;
  66        }
  67        if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
  68                /* Check how Solaris handles requests for the Default ACL
  69                   of a non-directory! */
  70                acl = get_acl(inode, ACL_TYPE_DEFAULT);
  71                if (IS_ERR(acl)) {
  72                        nfserr = nfserrno(PTR_ERR(acl));
  73                        goto fail;
  74                }
  75                resp->acl_default = acl;
  76        }
  77
  78        /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
  79        RETURN_STATUS(0);
  80
  81fail:
  82        posix_acl_release(resp->acl_access);
  83        posix_acl_release(resp->acl_default);
  84        RETURN_STATUS(nfserr);
  85}
  86
  87/*
  88 * Set the Access and/or Default ACL of a file.
  89 */
  90static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
  91                struct nfsd3_setaclargs *argp,
  92                struct nfsd_attrstat *resp)
  93{
  94        struct inode *inode;
  95        svc_fh *fh;
  96        __be32 nfserr = 0;
  97        int error;
  98
  99        dprintk("nfsd: SETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
 100
 101        fh = fh_copy(&resp->fh, &argp->fh);
 102        nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
 103        if (nfserr)
 104                goto out;
 105
 106        inode = d_inode(fh->fh_dentry);
 107        if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) {
 108                error = -EOPNOTSUPP;
 109                goto out_errno;
 110        }
 111
 112        error = fh_want_write(fh);
 113        if (error)
 114                goto out_errno;
 115
 116        error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS);
 117        if (error)
 118                goto out_drop_write;
 119        error = inode->i_op->set_acl(inode, argp->acl_default,
 120                                     ACL_TYPE_DEFAULT);
 121        if (error)
 122                goto out_drop_write;
 123
 124        fh_drop_write(fh);
 125
 126        nfserr = fh_getattr(fh, &resp->stat);
 127
 128out:
 129        /* argp->acl_{access,default} may have been allocated in
 130           nfssvc_decode_setaclargs. */
 131        posix_acl_release(argp->acl_access);
 132        posix_acl_release(argp->acl_default);
 133        return nfserr;
 134out_drop_write:
 135        fh_drop_write(fh);
 136out_errno:
 137        nfserr = nfserrno(error);
 138        goto out;
 139}
 140
 141/*
 142 * Check file attributes
 143 */
 144static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
 145                struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
 146{
 147        __be32 nfserr;
 148        dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
 149
 150        fh_copy(&resp->fh, &argp->fh);
 151        nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
 152        if (nfserr)
 153                return nfserr;
 154        nfserr = fh_getattr(&resp->fh, &resp->stat);
 155        return nfserr;
 156}
 157
 158/*
 159 * Check file access
 160 */
 161static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
 162                struct nfsd3_accessres *resp)
 163{
 164        __be32 nfserr;
 165
 166        dprintk("nfsd: ACCESS(2acl)   %s 0x%x\n",
 167                        SVCFH_fmt(&argp->fh),
 168                        argp->access);
 169
 170        fh_copy(&resp->fh, &argp->fh);
 171        resp->access = argp->access;
 172        nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
 173        if (nfserr)
 174                return nfserr;
 175        nfserr = fh_getattr(&resp->fh, &resp->stat);
 176        return nfserr;
 177}
 178
 179/*
 180 * XDR decode functions
 181 */
 182static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
 183                struct nfsd3_getaclargs *argp)
 184{
 185        p = nfs2svc_decode_fh(p, &argp->fh);
 186        if (!p)
 187                return 0;
 188        argp->mask = ntohl(*p); p++;
 189
 190        return xdr_argsize_check(rqstp, p);
 191}
 192
 193
 194static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
 195                struct nfsd3_setaclargs *argp)
 196{
 197        struct kvec *head = rqstp->rq_arg.head;
 198        unsigned int base;
 199        int n;
 200
 201        p = nfs2svc_decode_fh(p, &argp->fh);
 202        if (!p)
 203                return 0;
 204        argp->mask = ntohl(*p++);
 205        if (argp->mask & ~NFS_ACL_MASK ||
 206            !xdr_argsize_check(rqstp, p))
 207                return 0;
 208
 209        base = (char *)p - (char *)head->iov_base;
 210        n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
 211                          (argp->mask & NFS_ACL) ?
 212                          &argp->acl_access : NULL);
 213        if (n > 0)
 214                n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
 215                                  (argp->mask & NFS_DFACL) ?
 216                                  &argp->acl_default : NULL);
 217        return (n > 0);
 218}
 219
 220static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p,
 221                struct nfsd_fhandle *argp)
 222{
 223        p = nfs2svc_decode_fh(p, &argp->fh);
 224        if (!p)
 225                return 0;
 226        return xdr_argsize_check(rqstp, p);
 227}
 228
 229static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
 230                struct nfsd3_accessargs *argp)
 231{
 232        p = nfs2svc_decode_fh(p, &argp->fh);
 233        if (!p)
 234                return 0;
 235        argp->access = ntohl(*p++);
 236
 237        return xdr_argsize_check(rqstp, p);
 238}
 239
 240/*
 241 * XDR encode functions
 242 */
 243
 244/*
 245 * There must be an encoding function for void results so svc_process
 246 * will work properly.
 247 */
 248static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 249{
 250        return xdr_ressize_check(rqstp, p);
 251}
 252
 253/* GETACL */
 254static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
 255                struct nfsd3_getaclres *resp)
 256{
 257        struct dentry *dentry = resp->fh.fh_dentry;
 258        struct inode *inode;
 259        struct kvec *head = rqstp->rq_res.head;
 260        unsigned int base;
 261        int n;
 262        int w;
 263
 264        /*
 265         * Since this is version 2, the check for nfserr in
 266         * nfsd_dispatch actually ensures the following cannot happen.
 267         * However, it seems fragile to depend on that.
 268         */
 269        if (dentry == NULL || d_really_is_negative(dentry))
 270                return 0;
 271        inode = d_inode(dentry);
 272
 273        p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
 274        *p++ = htonl(resp->mask);
 275        if (!xdr_ressize_check(rqstp, p))
 276                return 0;
 277        base = (char *)p - (char *)head->iov_base;
 278
 279        rqstp->rq_res.page_len = w = nfsacl_size(
 280                (resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
 281                (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
 282        while (w > 0) {
 283                if (!*(rqstp->rq_next_page++))
 284                        return 0;
 285                w -= PAGE_SIZE;
 286        }
 287
 288        n = nfsacl_encode(&rqstp->rq_res, base, inode,
 289                          resp->acl_access,
 290                          resp->mask & NFS_ACL, 0);
 291        if (n > 0)
 292                n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
 293                                  resp->acl_default,
 294                                  resp->mask & NFS_DFACL,
 295                                  NFS_ACL_DEFAULT);
 296        return (n > 0);
 297}
 298
 299static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p,
 300                struct nfsd_attrstat *resp)
 301{
 302        p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
 303        return xdr_ressize_check(rqstp, p);
 304}
 305
 306/* ACCESS */
 307static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
 308                struct nfsd3_accessres *resp)
 309{
 310        p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
 311        *p++ = htonl(resp->access);
 312        return xdr_ressize_check(rqstp, p);
 313}
 314
 315/*
 316 * XDR release functions
 317 */
 318static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
 319                struct nfsd3_getaclres *resp)
 320{
 321        fh_put(&resp->fh);
 322        posix_acl_release(resp->acl_access);
 323        posix_acl_release(resp->acl_default);
 324        return 1;
 325}
 326
 327static int nfsaclsvc_release_attrstat(struct svc_rqst *rqstp, __be32 *p,
 328                struct nfsd_attrstat *resp)
 329{
 330        fh_put(&resp->fh);
 331        return 1;
 332}
 333
 334static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p,
 335               struct nfsd3_accessres *resp)
 336{
 337       fh_put(&resp->fh);
 338       return 1;
 339}
 340
 341#define nfsaclsvc_decode_voidargs       NULL
 342#define nfsaclsvc_release_void          NULL
 343#define nfsd3_fhandleargs       nfsd_fhandle
 344#define nfsd3_attrstatres       nfsd_attrstat
 345#define nfsd3_voidres           nfsd3_voidargs
 346struct nfsd3_voidargs { int dummy; };
 347
 348#define PROC(name, argt, rest, relt, cache, respsize)   \
 349 { (svc_procfunc) nfsacld_proc_##name,          \
 350   (kxdrproc_t) nfsaclsvc_decode_##argt##args,  \
 351   (kxdrproc_t) nfsaclsvc_encode_##rest##res,   \
 352   (kxdrproc_t) nfsaclsvc_release_##relt,               \
 353   sizeof(struct nfsd3_##argt##args),           \
 354   sizeof(struct nfsd3_##rest##res),            \
 355   0,                                           \
 356   cache,                                       \
 357   respsize,                                    \
 358 }
 359
 360#define ST 1            /* status*/
 361#define AT 21           /* attributes */
 362#define pAT (1+AT)      /* post attributes - conditional */
 363#define ACL (1+NFS_ACL_MAX_ENTRIES*3)  /* Access Control List */
 364
 365static struct svc_procedure             nfsd_acl_procedures2[] = {
 366  PROC(null,    void,           void,           void,     RC_NOCACHE, ST),
 367  PROC(getacl,  getacl,         getacl,         getacl,   RC_NOCACHE, ST+1+2*(1+ACL)),
 368  PROC(setacl,  setacl,         attrstat,       attrstat, RC_NOCACHE, ST+AT),
 369  PROC(getattr, fhandle,        attrstat,       attrstat, RC_NOCACHE, ST+AT),
 370  PROC(access,  access,         access,         access,   RC_NOCACHE, ST+AT+1),
 371};
 372
 373struct svc_version      nfsd_acl_version2 = {
 374                .vs_vers        = 2,
 375                .vs_nproc       = 5,
 376                .vs_proc        = nfsd_acl_procedures2,
 377                .vs_dispatch    = nfsd_dispatch,
 378                .vs_xdrsize     = NFS3_SVC_XDRSIZE,
 379                .vs_hidden      = 0,
 380};
 381