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