summaryrefslogtreecommitdiff
path: root/fs/nfsd/nfs4xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r--fs/nfsd/nfs4xdr.c101
1 files changed, 100 insertions, 1 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 15809dfd88a5..b3d55c6747fd 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -56,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
@@ -819,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;
@@ -1131,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;
@@ -1296,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;
@@ -1847,11 +1869,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 +2449,72 @@ 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;
+ 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.
@@ -2559,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;