#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
return status;
}
+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)
[OP_SAVEFH] = {
.op_func = (nfsd4op_func)nfsd4_savefh,
},
+ [OP_SECINFO] = {
+ .op_func = (nfsd4op_func)nfsd4_secinfo,
+ },
[OP_SETATTR] = {
.op_func = (nfsd4op_func)nfsd4_setattr,
},
#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
DECODE_TAIL;
}
+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)
{
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;
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,
}
}
+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.
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;
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
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 */
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;