Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dcb488a3 authored by Andy Adamson's avatar Andy Adamson Committed by Linus Torvalds
Browse files

knfsd: nfsd4: implement secinfo



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: default avatarAndy Adamson <andros@citi.umich.edu>
Signed-off-by: default avatar"J. Bruce Fields" <bfields@citi.umich.edu>
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ae4c40b1
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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

@@ -609,6 +610,30 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	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)
@@ -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,
	},
+75 −0
Original line number Diff line number Diff line
@@ -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

@@ -818,6 +819,23 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
	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)
{
@@ -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;
+3 −0
Original line number Diff line number Diff line
@@ -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
+7 −0
Original line number Diff line number Diff line
@@ -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;