knfsd: nfsd4: implement secinfo
Andy Adamson [Tue, 17 Jul 2007 11:04:51 +0000 (04:04 -0700)]
Implement the secinfo operation.

(Thanks to Usha Ketineni wrote an earlier version of this support.)

Cc: Usha Ketineni <uketinen@us.ibm.com>
Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

fs/nfsd/nfs4proc.c
fs/nfsd/nfs4xdr.c
include/linux/nfsd/nfsd.h
include/linux/nfsd/xdr4.h

index a106e3b..3c62712 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 #include <linux/nfs4_acl.h>
+#include <linux/sunrpc/gss_api.h>
 
 #define NFSDDBG_FACILITY               NFSDDBG_PROC
 
@@ -610,6 +611,30 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 }
 
 static __be32
+nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+             struct nfsd4_secinfo *secinfo)
+{
+       struct svc_fh resfh;
+       struct svc_export *exp;
+       struct dentry *dentry;
+       __be32 err;
+
+       fh_init(&resfh, NFS4_FHSIZE);
+       err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
+                                   secinfo->si_name, secinfo->si_namelen,
+                                   &exp, &dentry);
+       if (err)
+               return err;
+       if (dentry->d_inode == NULL) {
+               exp_put(exp);
+               err = nfserr_noent;
+       } else
+               secinfo->si_exp = exp;
+       dput(dentry);
+       return err;
+}
+
+static __be32
 nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
              struct nfsd4_setattr *setattr)
 {
@@ -1008,6 +1033,9 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
        [OP_SAVEFH] = {
                .op_func = (nfsd4op_func)nfsd4_savefh,
        },
+       [OP_SECINFO] = {
+               .op_func = (nfsd4op_func)nfsd4_secinfo,
+       },
        [OP_SETATTR] = {
                .op_func = (nfsd4op_func)nfsd4_setattr,
        },
index b0bfbda..864498f 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/nfsd_idmap.h>
 #include <linux/nfs4.h>
 #include <linux/nfs4_acl.h>
+#include <linux/sunrpc/gss_api.h>
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -819,6 +820,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;
@@ -1131,6 +1149,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;
@@ -1847,11 +1868,19 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
        if (d_mountpoint(dentry)) {
                int err;
 
+               /*
+                * Why the heck aren't we just using nfsd_lookup??
+                * Different "."/".." handling?  Something else?
+                * At least, add a comment here to explain....
+                */
                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,
@@ -2419,6 +2448,49 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
        }
 }
 
+static void
+nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, int nfserr,
+                    struct nfsd4_secinfo *secinfo)
+{
+       int i = 0;
+       struct svc_export *exp = secinfo->si_exp;
+       ENCODE_HEAD;
+
+       if (nfserr)
+               goto out;
+       RESERVE_SPACE(4);
+       WRITE32(exp->ex_nflavors);
+       ADJUST_ARGS();
+       for (i = 0; i < exp->ex_nflavors; i++) {
+               u32 flav = exp->ex_flavors[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.
@@ -2559,6 +2631,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;
index 54ef1a1..e452256 100644 (file)
@@ -71,6 +71,9 @@ int           nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
                                struct svc_export **expp);
 __be32         nfsd_lookup(struct svc_rqst *, struct svc_fh *,
                                const char *, int, struct svc_fh *);
+__be32          nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
+                               const char *, int,
+                               struct svc_export **, struct dentry **);
 __be32         nfsd_setattr(struct svc_rqst *, struct svc_fh *,
                                struct iattr *, int, time_t);
 #ifdef CONFIG_NFSD_V4
index 09799bc..1b65326 100644 (file)
@@ -293,6 +293,12 @@ struct nfsd4_rename {
        struct nfsd4_change_info  rn_tinfo; /* response */
 };
 
+struct nfsd4_secinfo {
+       u32 si_namelen;                                 /* request */
+       char *si_name;                                  /* request */
+       struct svc_export *si_exp;                      /* response */
+};
+
 struct nfsd4_setattr {
        stateid_t       sa_stateid;         /* request */
        u32             sa_bmval[2];        /* request */
@@ -365,6 +371,7 @@ struct nfsd4_op {
                struct nfsd4_remove             remove;
                struct nfsd4_rename             rename;
                clientid_t                      renew;
+               struct nfsd4_secinfo            secinfo;
                struct nfsd4_setattr            setattr;
                struct nfsd4_setclientid        setclientid;
                struct nfsd4_setclientid_confirm setclientid_confirm;