linux/fs/nfsd/nfs2acl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Process version 2 NFSACL requests.
   4 *
   5 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
   6 */
   7
   8#include "nfsd.h"
   9/* FIXME: nfsacl.h is a broken header */
  10#include <linux/nfsacl.h>
  11#include <linux/gfp.h>
  12#include "cache.h"
  13#include "xdr3.h"
  14#include "vfs.h"
  15
  16#define NFSDDBG_FACILITY                NFSDDBG_PROC
  17
  18/*
  19 * NULL call.
  20 */
  21static __be32
  22nfsacld_proc_null(struct svc_rqst *rqstp)
  23{
  24        return rpc_success;
  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{
  32        struct nfsd3_getaclargs *argp = rqstp->rq_argp;
  33        struct nfsd3_getaclres *resp = rqstp->rq_resp;
  34        struct posix_acl *acl;
  35        struct inode *inode;
  36        svc_fh *fh;
  37
  38        dprintk("nfsd: GETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
  39
  40        fh = fh_copy(&resp->fh, &argp->fh);
  41        resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
  42        if (resp->status != nfs_ok)
  43                goto out;
  44
  45        inode = d_inode(fh->fh_dentry);
  46
  47        if (argp->mask & ~NFS_ACL_MASK) {
  48                resp->status = nfserr_inval;
  49                goto out;
  50        }
  51        resp->mask = argp->mask;
  52
  53        resp->status = fh_getattr(fh, &resp->stat);
  54        if (resp->status != nfs_ok)
  55                goto out;
  56
  57        if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
  58                acl = get_acl(inode, ACL_TYPE_ACCESS);
  59                if (acl == NULL) {
  60                        /* Solaris returns the inode's minimum ACL. */
  61                        acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
  62                }
  63                if (IS_ERR(acl)) {
  64                        resp->status = nfserrno(PTR_ERR(acl));
  65                        goto fail;
  66                }
  67                resp->acl_access = acl;
  68        }
  69        if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
  70                /* Check how Solaris handles requests for the Default ACL
  71                   of a non-directory! */
  72                acl = get_acl(inode, ACL_TYPE_DEFAULT);
  73                if (IS_ERR(acl)) {
  74                        resp->status = nfserrno(PTR_ERR(acl));
  75                        goto fail;
  76                }
  77                resp->acl_default = acl;
  78        }
  79
  80        /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
  81out:
  82        return rpc_success;
  83
  84fail:
  85        posix_acl_release(resp->acl_access);
  86        posix_acl_release(resp->acl_default);
  87        goto out;
  88}
  89
  90/*
  91 * Set the Access and/or Default ACL of a file.
  92 */
  93static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
  94{
  95        struct nfsd3_setaclargs *argp = rqstp->rq_argp;
  96        struct nfsd_attrstat *resp = rqstp->rq_resp;
  97        struct inode *inode;
  98        svc_fh *fh;
  99        int error;
 100
 101        dprintk("nfsd: SETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
 102
 103        fh = fh_copy(&resp->fh, &argp->fh);
 104        resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
 105        if (resp->status != nfs_ok)
 106                goto out;
 107
 108        inode = d_inode(fh->fh_dentry);
 109
 110        error = fh_want_write(fh);
 111        if (error)
 112                goto out_errno;
 113
 114        fh_lock(fh);
 115
 116        error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
 117                              argp->acl_access);
 118        if (error)
 119                goto out_drop_lock;
 120        error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
 121                              argp->acl_default);
 122        if (error)
 123                goto out_drop_lock;
 124
 125        fh_unlock(fh);
 126
 127        fh_drop_write(fh);
 128
 129        resp->status = fh_getattr(fh, &resp->stat);
 130
 131out:
 132        /* argp->acl_{access,default} may have been allocated in
 133           nfssvc_decode_setaclargs. */
 134        posix_acl_release(argp->acl_access);
 135        posix_acl_release(argp->acl_default);
 136        return rpc_success;
 137
 138out_drop_lock:
 139        fh_unlock(fh);
 140        fh_drop_write(fh);
 141out_errno:
 142        resp->status = nfserrno(error);
 143        goto out;
 144}
 145
 146/*
 147 * Check file attributes
 148 */
 149static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp)
 150{
 151        struct nfsd_fhandle *argp = rqstp->rq_argp;
 152        struct nfsd_attrstat *resp = rqstp->rq_resp;
 153
 154        dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
 155
 156        fh_copy(&resp->fh, &argp->fh);
 157        resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
 158        if (resp->status != nfs_ok)
 159                goto out;
 160        resp->status = fh_getattr(&resp->fh, &resp->stat);
 161out:
 162        return rpc_success;
 163}
 164
 165/*
 166 * Check file access
 167 */
 168static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
 169{
 170        struct nfsd3_accessargs *argp = rqstp->rq_argp;
 171        struct nfsd3_accessres *resp = rqstp->rq_resp;
 172
 173        dprintk("nfsd: ACCESS(2acl)   %s 0x%x\n",
 174                        SVCFH_fmt(&argp->fh),
 175                        argp->access);
 176
 177        fh_copy(&resp->fh, &argp->fh);
 178        resp->access = argp->access;
 179        resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
 180        if (resp->status != nfs_ok)
 181                goto out;
 182        resp->status = fh_getattr(&resp->fh, &resp->stat);
 183out:
 184        return rpc_success;
 185}
 186
 187/*
 188 * XDR decode functions
 189 */
 190
 191static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p)
 192{
 193        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 194        struct nfsd3_getaclargs *argp = rqstp->rq_argp;
 195
 196        if (!svcxdr_decode_fhandle(xdr, &argp->fh))
 197                return 0;
 198        if (xdr_stream_decode_u32(xdr, &argp->mask) < 0)
 199                return 0;
 200
 201        return 1;
 202}
 203
 204static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p)
 205{
 206        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 207        struct nfsd3_setaclargs *argp = rqstp->rq_argp;
 208
 209        if (!svcxdr_decode_fhandle(xdr, &argp->fh))
 210                return 0;
 211        if (xdr_stream_decode_u32(xdr, &argp->mask) < 0)
 212                return 0;
 213        if (argp->mask & ~NFS_ACL_MASK)
 214                return 0;
 215        if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ?
 216                                   &argp->acl_access : NULL))
 217                return 0;
 218        if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ?
 219                                   &argp->acl_default : NULL))
 220                return 0;
 221
 222        return 1;
 223}
 224
 225static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p)
 226{
 227        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 228        struct nfsd3_accessargs *args = rqstp->rq_argp;
 229
 230        if (!svcxdr_decode_fhandle(xdr, &args->fh))
 231                return 0;
 232        if (xdr_stream_decode_u32(xdr, &args->access) < 0)
 233                return 0;
 234
 235        return 1;
 236}
 237
 238/*
 239 * XDR encode functions
 240 */
 241
 242/* GETACL */
 243static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
 244{
 245        struct xdr_stream *xdr = &rqstp->rq_res_stream;
 246        struct nfsd3_getaclres *resp = rqstp->rq_resp;
 247        struct dentry *dentry = resp->fh.fh_dentry;
 248        struct inode *inode;
 249        int w;
 250
 251        if (!svcxdr_encode_stat(xdr, resp->status))
 252                return 0;
 253
 254        if (dentry == NULL || d_really_is_negative(dentry))
 255                return 1;
 256        inode = d_inode(dentry);
 257
 258        if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
 259                return 0;
 260        if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
 261                return 0;
 262
 263        rqstp->rq_res.page_len = w = nfsacl_size(
 264                (resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
 265                (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
 266        while (w > 0) {
 267                if (!*(rqstp->rq_next_page++))
 268                        return 1;
 269                w -= PAGE_SIZE;
 270        }
 271
 272        if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access,
 273                                   resp->mask & NFS_ACL, 0))
 274                return 0;
 275        if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default,
 276                                   resp->mask & NFS_DFACL, NFS_ACL_DEFAULT))
 277                return 0;
 278
 279        return 1;
 280}
 281
 282/* ACCESS */
 283static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
 284{
 285        struct xdr_stream *xdr = &rqstp->rq_res_stream;
 286        struct nfsd3_accessres *resp = rqstp->rq_resp;
 287
 288        if (!svcxdr_encode_stat(xdr, resp->status))
 289                return 0;
 290        switch (resp->status) {
 291        case nfs_ok:
 292                if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
 293                        return 0;
 294                if (xdr_stream_encode_u32(xdr, resp->access) < 0)
 295                        return 0;
 296                break;
 297        }
 298
 299        return 1;
 300}
 301
 302/*
 303 * XDR release functions
 304 */
 305static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp)
 306{
 307        struct nfsd3_getaclres *resp = rqstp->rq_resp;
 308
 309        fh_put(&resp->fh);
 310        posix_acl_release(resp->acl_access);
 311        posix_acl_release(resp->acl_default);
 312}
 313
 314static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
 315{
 316        struct nfsd3_accessres *resp = rqstp->rq_resp;
 317
 318        fh_put(&resp->fh);
 319}
 320
 321struct nfsd3_voidargs { int dummy; };
 322
 323#define ST 1            /* status*/
 324#define AT 21           /* attributes */
 325#define pAT (1+AT)      /* post attributes - conditional */
 326#define ACL (1+NFS_ACL_MAX_ENTRIES*3)  /* Access Control List */
 327
 328static const struct svc_procedure nfsd_acl_procedures2[5] = {
 329        [ACLPROC2_NULL] = {
 330                .pc_func = nfsacld_proc_null,
 331                .pc_decode = nfssvc_decode_voidarg,
 332                .pc_encode = nfssvc_encode_voidres,
 333                .pc_argsize = sizeof(struct nfsd_voidargs),
 334                .pc_ressize = sizeof(struct nfsd_voidres),
 335                .pc_cachetype = RC_NOCACHE,
 336                .pc_xdrressize = ST,
 337                .pc_name = "NULL",
 338        },
 339        [ACLPROC2_GETACL] = {
 340                .pc_func = nfsacld_proc_getacl,
 341                .pc_decode = nfsaclsvc_decode_getaclargs,
 342                .pc_encode = nfsaclsvc_encode_getaclres,
 343                .pc_release = nfsaclsvc_release_getacl,
 344                .pc_argsize = sizeof(struct nfsd3_getaclargs),
 345                .pc_ressize = sizeof(struct nfsd3_getaclres),
 346                .pc_cachetype = RC_NOCACHE,
 347                .pc_xdrressize = ST+1+2*(1+ACL),
 348                .pc_name = "GETACL",
 349        },
 350        [ACLPROC2_SETACL] = {
 351                .pc_func = nfsacld_proc_setacl,
 352                .pc_decode = nfsaclsvc_decode_setaclargs,
 353                .pc_encode = nfssvc_encode_attrstatres,
 354                .pc_release = nfssvc_release_attrstat,
 355                .pc_argsize = sizeof(struct nfsd3_setaclargs),
 356                .pc_ressize = sizeof(struct nfsd_attrstat),
 357                .pc_cachetype = RC_NOCACHE,
 358                .pc_xdrressize = ST+AT,
 359                .pc_name = "SETACL",
 360        },
 361        [ACLPROC2_GETATTR] = {
 362                .pc_func = nfsacld_proc_getattr,
 363                .pc_decode = nfssvc_decode_fhandleargs,
 364                .pc_encode = nfssvc_encode_attrstatres,
 365                .pc_release = nfssvc_release_attrstat,
 366                .pc_argsize = sizeof(struct nfsd_fhandle),
 367                .pc_ressize = sizeof(struct nfsd_attrstat),
 368                .pc_cachetype = RC_NOCACHE,
 369                .pc_xdrressize = ST+AT,
 370                .pc_name = "GETATTR",
 371        },
 372        [ACLPROC2_ACCESS] = {
 373                .pc_func = nfsacld_proc_access,
 374                .pc_decode = nfsaclsvc_decode_accessargs,
 375                .pc_encode = nfsaclsvc_encode_accessres,
 376                .pc_release = nfsaclsvc_release_access,
 377                .pc_argsize = sizeof(struct nfsd3_accessargs),
 378                .pc_ressize = sizeof(struct nfsd3_accessres),
 379                .pc_cachetype = RC_NOCACHE,
 380                .pc_xdrressize = ST+AT+1,
 381                .pc_name = "SETATTR",
 382        },
 383};
 384
 385static unsigned int nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)];
 386const struct svc_version nfsd_acl_version2 = {
 387        .vs_vers        = 2,
 388        .vs_nproc       = 5,
 389        .vs_proc        = nfsd_acl_procedures2,
 390        .vs_count       = nfsd_acl_count2,
 391        .vs_dispatch    = nfsd_dispatch,
 392        .vs_xdrsize     = NFS3_SVC_XDRSIZE,
 393};
 394