nfsd warning fix
[safe/jmp/linux-2.6] / fs / nfsd / nfs4xdr.c
index f3f239d..8ef0964 100644 (file)
@@ -44,7 +44,6 @@
 
 #include <linux/param.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
 #include <linux/vfs.h>
@@ -57,6 +56,8 @@
 #include <linux/nfsd_idmap.h>
 #include <linux/nfs4.h>
 #include <linux/nfs4_acl.h>
+#include <linux/sunrpc/gss_api.h>
+#include <linux/sunrpc/svcauth_gss.h>
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -199,24 +200,22 @@ defer_free(struct nfsd4_compoundargs *argp,
 
 static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
 {
-       void *new = NULL;
        if (p == argp->tmp) {
-               new = kmalloc(nbytes, GFP_KERNEL);
-               if (!new) return NULL;
-               p = new;
+               p = kmalloc(nbytes, GFP_KERNEL);
+               if (!p)
+                       return NULL;
                memcpy(p, argp->tmp, nbytes);
        } else {
                BUG_ON(p != argp->tmpp);
                argp->tmpp = NULL;
        }
        if (defer_free(argp, kfree, p)) {
-               kfree(new);
+               kfree(p);
                return NULL;
        } else
                return (char *)p;
 }
 
-
 static __be32
 nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
 {
@@ -255,7 +254,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
                return status;
 
        /*
-        * According to spec, unsupported attributes return ERR_NOTSUPP;
+        * According to spec, unsupported attributes return ERR_ATTRNOTSUPP;
         * read-only attributes return ERR_INVAL.
         */
        if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) || (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
@@ -273,42 +272,42 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
                iattr->ia_valid |= ATTR_SIZE;
        }
        if (bmval[0] & FATTR4_WORD0_ACL) {
-               int nace, i;
-               struct nfs4_ace ace;
+               int nace;
+               struct nfs4_ace *ace;
 
                READ_BUF(4); len += 4;
                READ32(nace);
 
-               *acl = nfs4_acl_new();
+               if (nace > NFS4_ACL_MAX)
+                       return nfserr_resource;
+
+               *acl = nfs4_acl_new(nace);
                if (*acl == NULL) {
                        host_err = -ENOMEM;
                        goto out_nfserr;
                }
-               defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl);
+               defer_free(argp, kfree, *acl);
 
-               for (i = 0; i < nace; i++) {
+               (*acl)->naces = nace;
+               for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {
                        READ_BUF(16); len += 16;
-                       READ32(ace.type);
-                       READ32(ace.flag);
-                       READ32(ace.access_mask);
+                       READ32(ace->type);
+                       READ32(ace->flag);
+                       READ32(ace->access_mask);
                        READ32(dummy32);
                        READ_BUF(dummy32);
                        len += XDR_QUADLEN(dummy32) << 2;
                        READMEM(buf, dummy32);
-                       ace.whotype = nfs4_acl_get_whotype(buf, dummy32);
+                       ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
                        host_err = 0;
-                       if (ace.whotype != NFS4_ACL_WHO_NAMED)
-                               ace.who = 0;
-                       else if (ace.flag & NFS4_ACE_IDENTIFIER_GROUP)
+                       if (ace->whotype != NFS4_ACL_WHO_NAMED)
+                               ace->who = 0;
+                       else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
                                host_err = nfsd_map_name_to_gid(argp->rqstp,
-                                               buf, dummy32, &ace.who);
+                                               buf, dummy32, &ace->who);
                        else
                                host_err = nfsd_map_name_to_uid(argp->rqstp,
-                                               buf, dummy32, &ace.who);
-                       if (host_err)
-                               goto out_nfserr;
-                       host_err = nfs4_acl_add_ace(*acl, ace.type, ace.flag,
-                                ace.access_mask, ace.whotype, ace.who);
+                                               buf, dummy32, &ace->who);
                        if (host_err)
                                goto out_nfserr;
                }
@@ -822,6 +821,23 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
 }
 
 static __be32
+nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
+                    struct nfsd4_secinfo *secinfo)
+{
+       DECODE_HEAD;
+
+       READ_BUF(4);
+       READ32(secinfo->si_namelen);
+       READ_BUF(secinfo->si_namelen);
+       SAVEMEM(secinfo->si_name, secinfo->si_namelen);
+       status = check_filename(secinfo->si_name, secinfo->si_namelen,
+                                                               nfserr_noent);
+       if (status)
+               return status;
+       DECODE_TAIL;
+}
+
+static __be32
 nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
 {
        DECODE_HEAD;
@@ -1134,6 +1150,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                case OP_SAVEFH:
                        op->status = nfs_ok;
                        break;
+               case OP_SECINFO:
+                       op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo);
+                       break;
                case OP_SETATTR:
                        op->status = nfsd4_decode_setattr(argp, &op->u.setattr);
                        break;
@@ -1299,7 +1318,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
        char *path, *rootpath;
 
        fh_init(&tmp_fh, NFS4_FHSIZE);
-       *stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle);
+       *stat = exp_pseudoroot(rqstp, &tmp_fh);
        if (*stat)
                return NULL;
        rootpath = tmp_fh.fh_export->ex_path;
@@ -1563,14 +1582,20 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                if (exp->ex_fslocs.migrated) {
                        WRITE64(NFS4_REFERRAL_FSID_MAJOR);
                        WRITE64(NFS4_REFERRAL_FSID_MINOR);
-               } else if (is_fsid(fhp, rqstp->rq_reffh)) {
+               } else switch(fsid_source(fhp)) {
+               case FSIDSOURCE_FSID:
                        WRITE64((u64)exp->ex_fsid);
                        WRITE64((u64)0);
-               } else {
+                       break;
+               case FSIDSOURCE_DEV:
                        WRITE32(0);
                        WRITE32(MAJOR(stat.dev));
                        WRITE32(0);
                        WRITE32(MINOR(stat.dev));
+                       break;
+               case FSIDSOURCE_UUID:
+                       WRITEMEM(exp->ex_uuid, 16);
+                       break;
                }
        }
        if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
@@ -1590,7 +1615,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        }
        if (bmval0 & FATTR4_WORD0_ACL) {
                struct nfs4_ace *ace;
-               struct list_head *h;
 
                if (acl == NULL) {
                        if ((buflen -= 4) < 0)
@@ -1603,9 +1627,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                        goto out_resource;
                WRITE32(acl->naces);
 
-               list_for_each(h, &acl->ace_head) {
-                       ace = list_entry(h, struct nfs4_ace, l_ace);
-
+               for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
                        if ((buflen -= 4*3) < 0)
                                goto out_resource;
                        WRITE32(ace->type);
@@ -1815,7 +1837,7 @@ out_acl:
        status = nfs_ok;
 
 out:
-       nfs4_acl_free(acl);
+       kfree(acl);
        if (fhp == &tempfh)
                fh_put(&tempfh);
        return status;
@@ -1845,17 +1867,21 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
 
        exp_get(exp);
        if (d_mountpoint(dentry)) {
-               if (nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp)) {
+               int err;
+
                /*
-                * -EAGAIN is the only error returned from
-                * nfsd_cross_mnt() and it indicates that an
-                * up-call has  been initiated to fill in the export
-                * options on exp.  When the answer comes back,
-                * this call will be retried.
+                * Why the heck aren't we just using nfsd_lookup??
+                * Different "."/".." handling?  Something else?
+                * At least, add a comment here to explain....
                 */
-                       nfserr = nfserr_dropit;
+               err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
+               if (err) {
+                       nfserr = nfserrno(err);
                        goto out_put;
                }
+               nfserr = check_nfsd_access(exp, cd->rd_rqstp);
+               if (nfserr)
+                       goto out_put;
 
        }
        nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
@@ -1884,9 +1910,10 @@ nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
 }
 
 static int
-nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
-                   loff_t offset, ino_t ino, unsigned int d_type)
+nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
+                   loff_t offset, u64 ino, unsigned int d_type)
 {
+       struct readdir_cd *ccd = ccdv;
        struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
        int buflen;
        __be32 *p = cd->buffer;
@@ -2422,6 +2449,72 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
        }
 }
 
+static void
+nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
+                    struct nfsd4_secinfo *secinfo)
+{
+       int i = 0;
+       struct svc_export *exp = secinfo->si_exp;
+       u32 nflavs;
+       struct exp_flavor_info *flavs;
+       struct exp_flavor_info def_flavs[2];
+       ENCODE_HEAD;
+
+       if (nfserr)
+               goto out;
+       if (exp->ex_nflavors) {
+               flavs = exp->ex_flavors;
+               nflavs = exp->ex_nflavors;
+       } else { /* Handling of some defaults in absence of real secinfo: */
+               flavs = def_flavs;
+               if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) {
+                       nflavs = 2;
+                       flavs[0].pseudoflavor = RPC_AUTH_UNIX;
+                       flavs[1].pseudoflavor = RPC_AUTH_NULL;
+               } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) {
+                       nflavs = 1;
+                       flavs[0].pseudoflavor
+                                       = svcauth_gss_flavor(exp->ex_client);
+               } else {
+                       nflavs = 1;
+                       flavs[0].pseudoflavor
+                                       = exp->ex_client->flavour->flavour;
+               }
+       }
+
+       RESERVE_SPACE(4);
+       WRITE32(nflavs);
+       ADJUST_ARGS();
+       for (i = 0; i < nflavs; i++) {
+               u32 flav = flavs[i].pseudoflavor;
+               struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
+
+               if (gm) {
+                       RESERVE_SPACE(4);
+                       WRITE32(RPC_AUTH_GSS);
+                       ADJUST_ARGS();
+                       RESERVE_SPACE(4 + gm->gm_oid.len);
+                       WRITE32(gm->gm_oid.len);
+                       WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
+                       ADJUST_ARGS();
+                       RESERVE_SPACE(4);
+                       WRITE32(0); /* qop */
+                       ADJUST_ARGS();
+                       RESERVE_SPACE(4);
+                       WRITE32(gss_pseudoflavor_to_service(gm, flav));
+                       ADJUST_ARGS();
+                       gss_mech_put(gm);
+               } else {
+                       RESERVE_SPACE(4);
+                       WRITE32(flav);
+                       ADJUST_ARGS();
+               }
+       }
+out:
+       if (exp)
+               exp_put(exp);
+}
+
 /*
  * The SETATTR encode routine is special -- it always encodes a bitmap,
  * regardless of the error status.
@@ -2562,6 +2655,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
                break;
        case OP_SAVEFH:
                break;
+       case OP_SECINFO:
+               nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo);
+               break;
        case OP_SETATTR:
                nfsd4_encode_setattr(resp, op->status, &op->u.setattr);
                break;