
nfs4_set_secinfo() queries a struct svc_export->ex_flavors list and stuffs
an nfsd4_secinfo struct with an ordered list of supported pseudoflavors.
OP_SECINFO processin calls nfsd_lookup using the curent directory filehandle 
and name. This is the only nfsd_lookup call that passes a non-NULL secinfo
parameter. nfs4_set_secinfo() is either called by nfsd_cross_mnt() when the
given name is in a different export than the current file handle, or by
nfsd4_secinfo when the given name is in the same export as the current
file handle.

Signed-off-by: Andy Adamson <andros@citi.umich.edu>

---

---

 linux-2.6.18-rc5-andros/fs/nfsd/nfs4proc.c |   79 +++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff -puN fs/nfsd/nfs4proc.c~nfsd-secinfo-proc fs/nfsd/nfs4proc.c
--- linux-2.6.18-rc5/fs/nfsd/nfs4proc.c~nfsd-secinfo-proc	2006-10-11 17:36:49.000000000 -0400
+++ linux-2.6.18-rc5-andros/fs/nfsd/nfs4proc.c	2006-10-11 17:36:49.000000000 -0400
@@ -54,6 +54,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
 
@@ -67,9 +68,13 @@ fh_dup2(struct svc_fh *dst, struct svc_f
 	*dst = *src;
 }
 
+/* forward declaration */
+void nfs4_set_secinfo(struct svc_export *exp, void *secinfo);
+
 int
 nfs4_set_secinfo_xmnt(struct svc_export *exp, void *secinfo)
 {
+	nfs4_set_secinfo(exp, (struct nfsd4_secinfo *)secinfo);
 	return nfserr_wrongsec;
 }
 
@@ -593,6 +598,77 @@ nfsd4_rename(struct svc_rqst *rqstp, str
 	return status;
 }
 
+void
+nfs4_set_secinfo(struct svc_export *exp, void *secinfo)
+{
+	struct nfsd4_secinfo *si = (struct nfsd4_secinfo *)secinfo;
+	struct gss_api_mech *mech;
+	int i, order;
+
+	if (!si)
+		return;
+	si->nmech = 0;
+	for (i = 0; i < MAX_SECINFO_LIST; i++) {
+		int flav = exp->ex_flavors[i].pseudoflavor;
+
+		if (flav == -1)
+			continue;
+
+		/* Order of pseudoflavor(s) in /etc/export file */
+		order = exp->ex_flavors[i].order;
+
+		/* AUTH_SYS and AUTH_NULL return only flavor */
+		if (flav == 1 ||flav == 0) {
+			si->mechs[order].flavor = flav;
+			si->nmech++;
+			continue;
+		}
+		mech = gss_mech_get_by_pseudoflavor(flav);
+		if (!mech) {
+			printk(KERN_WARNING "%s: export pseudoflavor %d not found!",
+				__FUNCTION__, flav);
+			continue;
+		}
+		si->mechs[order].st.oid = mech->gm_oid;
+		/* Currently qop is set to 0, can be replaced later with a value
+		* of pos->gm_pfs[i].qop when qop is being used.*/
+		si->mechs[order].st.qop = 0;
+		si->mechs[order].st.service = gss_pseudoflavor_to_service(mech,flav);
+		si->mechs[order].flavor = 6;
+		si->nmech++;
+	}
+}
+
+static inline int
+nfsd4_secinfo(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_secinfo *secinfo)
+{
+	struct svc_fh resfh;
+	int status;
+
+	/* XXX also check UTF-8 compliance */
+	if (secinfo->len == 0) {
+		status = nfserr_inval;
+		goto out;
+	}
+
+	fh_init(&resfh, NFS4_FHSIZE);
+	status = __nfsd_lookup(rqstp, current_fh, secinfo->name, secinfo->len,
+			&resfh, secinfo);
+	if (status == nfserr_wrongsec) {
+		/* attempt to cross mountpoint with wrong security.
+		 * nfs4_set_secinfo_xmnt called by nfs4_cross_mnt
+		 * which calls nfs4_set_secinfo(); succeed the secinfo call.
+		 */
+		status = 0;
+		goto out;
+	}
+	if (status)
+		goto out;
+	nfs4_set_secinfo(current_fh->fh_export, secinfo);
+out:
+	return status;
+}
+
 static inline int
 nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
 {
@@ -915,6 +991,9 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 		case OP_SAVEFH:
 			op->status = nfsd4_savefh(current_fh, save_fh);
 			break;
+		case OP_SECINFO:
+			op->status = nfsd4_secinfo(rqstp, current_fh, &op->u.secinfo);
+			break;
 		case OP_SETATTR:
 			op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr);
 			break;
_
