diff options
Diffstat (limited to 'fs/nfsd/export.c')
| -rw-r--r-- | fs/nfsd/export.c | 64 | 
1 files changed, 54 insertions, 10 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 668c7527b17e..ae85257b4238 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -123,11 +123,11 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)  	/* OK, we seem to have a valid key */  	key.h.flags = 0; -	key.h.expiry_time = get_expiry(&mesg); -	if (key.h.expiry_time == 0) +	err = get_expiry(&mesg, &key.h.expiry_time); +	if (err)  		goto out; -	key.ek_client = dom;	 +	key.ek_client = dom;  	key.ek_fsidtype = fsidtype;  	memcpy(key.ek_fsid, buf, len); @@ -439,7 +439,6 @@ static int check_export(struct path *path, int *flags, unsigned char *uuid)  		return -EINVAL;  	}  	return 0; -  }  #ifdef CONFIG_NFSD_V4 @@ -546,6 +545,29 @@ static inline int  secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }  #endif +static int xprtsec_parse(char **mesg, char *buf, struct svc_export *exp) +{ +	unsigned int i, mode, listsize; +	int err; + +	err = get_uint(mesg, &listsize); +	if (err) +		return err; +	if (listsize > NFSEXP_XPRTSEC_NUM) +		return -EINVAL; + +	exp->ex_xprtsec_modes = 0; +	for (i = 0; i < listsize; i++) { +		err = get_uint(mesg, &mode); +		if (err) +			return err; +		if (mode > NFSEXP_XPRTSEC_MTLS) +			return -EINVAL; +		exp->ex_xprtsec_modes |= mode; +	} +	return 0; +} +  static inline int  nfsd_uuid_parse(char **mesg, char *buf, unsigned char **puuid)  { @@ -608,11 +630,11 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)  	exp.ex_client = dom;  	exp.cd = cd;  	exp.ex_devid_map = NULL; +	exp.ex_xprtsec_modes = NFSEXP_XPRTSEC_ALL;  	/* expiry */ -	err = -EINVAL; -	exp.h.expiry_time = get_expiry(&mesg); -	if (exp.h.expiry_time == 0) +	err = get_expiry(&mesg, &exp.h.expiry_time); +	if (err)  		goto out3;  	/* flags */ @@ -624,7 +646,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)  		if (err || an_int < 0)  			goto out3;  		exp.ex_flags= an_int; -	 +  		/* anon uid */  		err = get_int(&mesg, &an_int);  		if (err) @@ -650,6 +672,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)  				err = nfsd_uuid_parse(&mesg, buf, &exp.ex_uuid);  			else if (strcmp(buf, "secinfo") == 0)  				err = secinfo_parse(&mesg, buf, &exp); +			else if (strcmp(buf, "xprtsec") == 0) +				err = xprtsec_parse(&mesg, buf, &exp);  			else  				/* quietly ignore unknown words and anything  				 * following. Newer user-space can try to set @@ -663,6 +687,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)  		err = check_export(&exp.ex_path, &exp.ex_flags, exp.ex_uuid);  		if (err)  			goto out4; +  		/*  		 * No point caching this if it would immediately expire.  		 * Also, this protects exportfs's dummy export from the @@ -824,6 +849,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)  	for (i = 0; i < MAX_SECINFO_LIST; i++) {  		new->ex_flavors[i] = item->ex_flavors[i];  	} +	new->ex_xprtsec_modes = item->ex_xprtsec_modes;  }  static struct cache_head *svc_export_alloc(void) @@ -1035,9 +1061,26 @@ static struct svc_export *exp_find(struct cache_detail *cd,  __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)  { -	struct exp_flavor_info *f; -	struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; +	struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors; +	struct svc_xprt *xprt = rqstp->rq_xprt; + +	if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_NONE) { +		if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags)) +			goto ok; +	} +	if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_TLS) { +		if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) && +		    !test_bit(XPT_PEER_AUTH, &xprt->xpt_flags)) +			goto ok; +	} +	if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_MTLS) { +		if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) && +		    test_bit(XPT_PEER_AUTH, &xprt->xpt_flags)) +			goto ok; +	} +	goto denied; +ok:  	/* legacy gss-only clients are always OK: */  	if (exp->ex_client == rqstp->rq_gssclient)  		return 0; @@ -1062,6 +1105,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)  	if (nfsd4_spo_must_allow(rqstp))  		return 0; +denied:  	return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;  }  |