Add flags to enable NFS over TLS to the NFS client and server.

An Internet Draft titled "Towards Remote Procedure Call Encryption By Default"
(soon to be an RFC I think) describes how Sun RPC is to use TLS with NFS
as a specific application case.
Various commits prepared the NFS code to use KERN_TLS, mainly enabling use
of ext_pgs mbufs for large RPC messages.
r364475 added TLS support to the kernel RPC.

This commit (which is the final one for kernel changes required to do
NFS over TLS) adds support for three export flags:
MNT_EXTLS - Requires a TLS connection.
MNT_EXTLSCERT - Requires a TLS connection where the client presents a valid
            X.509 certificate during TLS handshake.
MNT_EXTLSCERTUSER - Requires a TLS connection where the client presents a
            valid X.509 certificate with "user@domain" in the otherName
            field of the SubjectAltName during TLS handshake.
Without these export options, clients are permitted, but not required, to
use TLS.

For the client, a new nmount(2) option called "tls" makes the client do
a STARTTLS Null RPC and TLS handshake for all TCP connections used for the
mount. The CLSET_TLS client control option is used to indicate to the kernel RPC
that this should be done.

Unless the above export flags or "tls" option is used, semantics should
not change for the NFS client nor server.

For NFS over TLS to work, the userspace daemons rpctlscd(8) { for client }
or rpctlssd(8) daemon { for server } must be running.
This commit is contained in:
Rick Macklem 2020-08-27 23:57:30 +00:00
parent 66ac5b2c5a
commit 6e4b6ff88f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=364896
10 changed files with 114 additions and 9 deletions

View File

@ -281,6 +281,8 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one); CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
if ((nmp->nm_flag & NFSMNT_RESVPORT)) if ((nmp->nm_flag & NFSMNT_RESVPORT))
CLNT_CONTROL(client, CLSET_PRIVPORT, &one); CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
if (NFSHASTLS(nmp))
CLNT_CONTROL(client, CLSET_TLS, &one);
if (NFSHASSOFT(nmp)) { if (NFSHASSOFT(nmp)) {
if (nmp->nm_sotype == SOCK_DGRAM) if (nmp->nm_sotype == SOCK_DGRAM)
/* /*

View File

@ -81,6 +81,9 @@ struct nfsexstuff {
#define NFSVNO_EXPORTANON(e) ((e)->nes_exflag & MNT_EXPORTANON) #define NFSVNO_EXPORTANON(e) ((e)->nes_exflag & MNT_EXPORTANON)
#define NFSVNO_EXSTRICTACCESS(e) ((e)->nes_exflag & MNT_EXSTRICTACCESS) #define NFSVNO_EXSTRICTACCESS(e) ((e)->nes_exflag & MNT_EXSTRICTACCESS)
#define NFSVNO_EXV4ONLY(e) ((e)->nes_exflag & MNT_EXV4ONLY) #define NFSVNO_EXV4ONLY(e) ((e)->nes_exflag & MNT_EXV4ONLY)
#define NFSVNO_EXTLS(e) ((e)->nes_exflag & MNT_EXTLS)
#define NFSVNO_EXTLSCERT(e) ((e)->nes_exflag & MNT_EXTLSCERT)
#define NFSVNO_EXTLSCERTUSER(e) ((e)->nes_exflag & MNT_EXTLSCERTUSER)
#define NFSVNO_SETEXRDONLY(e) ((e)->nes_exflag = (MNT_EXPORTED|MNT_EXRDONLY)) #define NFSVNO_SETEXRDONLY(e) ((e)->nes_exflag = (MNT_EXPORTED|MNT_EXRDONLY))

View File

@ -1055,6 +1055,7 @@ bool ncl_pager_setsize(struct vnode *vp, u_quad_t *nsizep);
#define NFSHASOPENMODE(n) ((n)->nm_state & NFSSTA_OPENMODE) #define NFSHASOPENMODE(n) ((n)->nm_state & NFSSTA_OPENMODE)
#define NFSHASONEOPENOWN(n) (((n)->nm_flag & NFSMNT_ONEOPENOWN) != 0 && \ #define NFSHASONEOPENOWN(n) (((n)->nm_flag & NFSMNT_ONEOPENOWN) != 0 && \
(n)->nm_minorvers > 0) (n)->nm_minorvers > 0)
#define NFSHASTLS(n) (((n)->nm_newflag & NFSMNT_TLS) != 0)
/* /*
* Set boottime. * Set boottime.

View File

@ -37,12 +37,14 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include "opt_kgssapi.h" #include "opt_kgssapi.h"
#include "opt_kern_tls.h"
#include <fs/nfs/nfsport.h> #include <fs/nfs/nfsport.h>
#include <rpc/rpc.h> #include <rpc/rpc.h>
#include <rpc/rpcsec_gss.h>
#include <rpc/replay.h> #include <rpc/replay.h>
#include <rpc/rpcsec_gss.h>
#include <rpc/rpcsec_tls.h>
NFSDLOCKMUTEX; NFSDLOCKMUTEX;
@ -67,6 +69,9 @@ nfscb_program(struct svc_req *rqst, SVCXPRT *xprt)
{ {
struct nfsrv_descript nd; struct nfsrv_descript nd;
int cacherep, credflavor; int cacherep, credflavor;
#ifdef KERN_TLS
u_int maxlen;
#endif
memset(&nd, 0, sizeof(nd)); memset(&nd, 0, sizeof(nd));
if (rqst->rq_proc != NFSPROC_NULL && if (rqst->rq_proc != NFSPROC_NULL &&
@ -107,6 +112,13 @@ nfscb_program(struct svc_req *rqst, SVCXPRT *xprt)
#ifdef MAC #ifdef MAC
mac_cred_associate_nfsd(nd.nd_cred); mac_cred_associate_nfsd(nd.nd_cred);
#endif #endif
#endif
#ifdef KERN_TLS
if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0 &&
rpctls_getinfo(&maxlen, false, false)) {
nd.nd_flag |= ND_EXTPG;
nd.nd_maxextsiz = maxlen;
}
#endif #endif
cacherep = nfs_cbproc(&nd, rqst->rq_xid); cacherep = nfs_cbproc(&nd, rqst->rq_xid);
} else { } else {

View File

@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include "opt_bootp.h" #include "opt_bootp.h"
#include "opt_nfsroot.h" #include "opt_nfsroot.h"
#include "opt_kern_tls.h"
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
@ -77,6 +78,8 @@ __FBSDID("$FreeBSD$");
#include <fs/nfsclient/nfs.h> #include <fs/nfsclient/nfs.h>
#include <nfs/nfsdiskless.h> #include <nfs/nfsdiskless.h>
#include <rpc/rpcsec_tls.h>
FEATURE(nfscl, "NFSv4 client"); FEATURE(nfscl, "NFSv4 client");
extern int nfscl_ticks; extern int nfscl_ticks;
@ -117,7 +120,7 @@ static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
static int mountnfs(struct nfs_args *, struct mount *, static int mountnfs(struct nfs_args *, struct mount *,
struct sockaddr *, char *, u_char *, int, u_char *, int, struct sockaddr *, char *, u_char *, int, u_char *, int,
u_char *, int, struct vnode **, struct ucred *, u_char *, int, struct vnode **, struct ucred *,
struct thread *, int, int, int); struct thread *, int, int, int, uint32_t);
static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
struct sockaddr_storage *, int *, off_t *, struct sockaddr_storage *, int *, off_t *,
struct timeval *); struct timeval *);
@ -544,7 +547,7 @@ nfs_mountdiskless(char *path,
nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen, if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO, NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
NFS_DEFAULT_NEGNAMETIMEO, 0)) != 0) { NFS_DEFAULT_NEGNAMETIMEO, 0, 0)) != 0) {
printf("nfs_mountroot: mount %s on /: %d\n", path, error); printf("nfs_mountroot: mount %s on /: %d\n", path, error);
return (error); return (error);
} }
@ -746,7 +749,7 @@ static const char *nfs_opts[] = { "from", "nfs_args",
"resvport", "readahead", "hostname", "timeo", "timeout", "addr", "fh", "resvport", "readahead", "hostname", "timeo", "timeout", "addr", "fh",
"nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath", "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath",
"minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr", "minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr",
"pnfs", "wcommitsize", "oneopenown", "pnfs", "wcommitsize", "oneopenown", "tls",
NULL }; NULL };
/* /*
@ -897,9 +900,11 @@ nfs_mount(struct mount *mp)
int dirlen, has_nfs_args_opt, has_nfs_from_opt, int dirlen, has_nfs_args_opt, has_nfs_from_opt,
krbnamelen, srvkrbnamelen; krbnamelen, srvkrbnamelen;
size_t hstlen; size_t hstlen;
uint32_t newflag;
has_nfs_args_opt = 0; has_nfs_args_opt = 0;
has_nfs_from_opt = 0; has_nfs_from_opt = 0;
newflag = 0;
hst = malloc(MNAMELEN, M_TEMP, M_WAITOK); hst = malloc(MNAMELEN, M_TEMP, M_WAITOK);
if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
error = EINVAL; error = EINVAL;
@ -983,6 +988,8 @@ nfs_mount(struct mount *mp)
args.flags |= NFSMNT_PNFS; args.flags |= NFSMNT_PNFS;
if (vfs_getopt(mp->mnt_optnew, "oneopenown", NULL, NULL) == 0) if (vfs_getopt(mp->mnt_optnew, "oneopenown", NULL, NULL) == 0)
args.flags |= NFSMNT_ONEOPENOWN; args.flags |= NFSMNT_ONEOPENOWN;
if (vfs_getopt(mp->mnt_optnew, "tls", NULL, NULL) == 0)
newflag |= NFSMNT_TLS;
if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
if (opt == NULL) { if (opt == NULL) {
vfs_mount_error(mp, "illegal readdirsize"); vfs_mount_error(mp, "illegal readdirsize");
@ -1337,7 +1344,7 @@ nfs_mount(struct mount *mp)
args.fh = nfh; args.fh = nfh;
error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td, dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
nametimeo, negnametimeo, minvers); nametimeo, negnametimeo, minvers, newflag);
out: out:
if (!error) { if (!error) {
MNT_ILOCK(mp); MNT_ILOCK(mp);
@ -1386,7 +1393,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen, char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp, u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo, struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo,
int minvers) int minvers, uint32_t newflag)
{ {
struct nfsmount *nmp; struct nfsmount *nmp;
struct nfsnode *np; struct nfsnode *np;
@ -1396,6 +1403,9 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
struct nfsclds *dsp, *tdsp; struct nfsclds *dsp, *tdsp;
uint32_t lease; uint32_t lease;
static u_int64_t clval = 0; static u_int64_t clval = 0;
#ifdef KERN_TLS
u_int maxlen;
#endif
NFSCL_DEBUG(3, "in mnt\n"); NFSCL_DEBUG(3, "in mnt\n");
clp = NULL; clp = NULL;
@ -1405,9 +1415,22 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
free(nam, M_SONAME); free(nam, M_SONAME);
return (0); return (0);
} else { } else {
/* NFS-over-TLS requires that rpctls be functioning. */
if ((newflag & NFSMNT_TLS) != 0) {
error = EINVAL;
#ifdef KERN_TLS
if (rpctls_getinfo(&maxlen, true, false))
error = 0;
#endif
if (error != 0) {
free(nam, M_SONAME);
return (error);
}
}
nmp = malloc(sizeof (struct nfsmount) + nmp = malloc(sizeof (struct nfsmount) +
krbnamelen + dirlen + srvkrbnamelen + 2, krbnamelen + dirlen + srvkrbnamelen + 2,
M_NEWNFSMNT, M_WAITOK | M_ZERO); M_NEWNFSMNT, M_WAITOK | M_ZERO);
nmp->nm_newflag = newflag;
TAILQ_INIT(&nmp->nm_bufq); TAILQ_INIT(&nmp->nm_bufq);
TAILQ_INIT(&nmp->nm_sess); TAILQ_INIT(&nmp->nm_sess);
if (clval == 0) if (clval == 0)
@ -2011,6 +2034,8 @@ void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen); nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen);
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport", nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport",
&buf, &blen); &buf, &blen);
nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf,
&blen);
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn", nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
&buf, &blen); &buf, &blen);
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf, nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,

View File

@ -47,6 +47,7 @@
struct nfsmount { struct nfsmount {
struct nfsmount_common nm_com; /* Common fields for nlm */ struct nfsmount_common nm_com; /* Common fields for nlm */
uint32_t nm_privflag; /* Private flags */ uint32_t nm_privflag; /* Private flags */
uint32_t nm_newflag; /* New mount flags */
int nm_numgrps; /* Max. size of groupslist */ int nm_numgrps; /* Max. size of groupslist */
u_char nm_fh[NFSX_FHMAX]; /* File handle of root dir */ u_char nm_fh[NFSX_FHMAX]; /* File handle of root dir */
int nm_fhsize; /* Size of root file handle */ int nm_fhsize; /* Size of root file handle */
@ -114,6 +115,9 @@ struct nfsmount {
#define NFSMNTP_NOADVISE 0x00000100 #define NFSMNTP_NOADVISE 0x00000100
#define NFSMNTP_NOALLOCATE 0x00000200 #define NFSMNTP_NOALLOCATE 0x00000200
/* New mount flags only used by the kernel via nmount(2). */
#define NFSMNT_TLS 0x00000001
#define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1])) #define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1]))
#define NFSMNT_SRVKRBNAME(m) \ #define NFSMNT_SRVKRBNAME(m) \
(&((m)->nm_name[(m)->nm_krbnamelen + (m)->nm_dirpathlen + 2])) (&((m)->nm_name[(m)->nm_krbnamelen + (m)->nm_dirpathlen + 2]))

View File

@ -38,11 +38,13 @@ __FBSDID("$FreeBSD$");
#include "opt_inet6.h" #include "opt_inet6.h"
#include "opt_kgssapi.h" #include "opt_kgssapi.h"
#include "opt_kern_tls.h"
#include <fs/nfs/nfsport.h> #include <fs/nfs/nfsport.h>
#include <rpc/rpc.h> #include <rpc/rpc.h>
#include <rpc/rpcsec_gss.h> #include <rpc/rpcsec_gss.h>
#include <rpc/rpcsec_tls.h>
#include <fs/nfsserver/nfs_fha_new.h> #include <fs/nfsserver/nfs_fha_new.h>
@ -120,6 +122,9 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
struct nfsrv_descript nd; struct nfsrv_descript nd;
struct nfsrvcache *rp = NULL; struct nfsrvcache *rp = NULL;
int cacherep, credflavor; int cacherep, credflavor;
#ifdef KERN_TLS
u_int maxlen;
#endif
memset(&nd, 0, sizeof(nd)); memset(&nd, 0, sizeof(nd));
if (rqst->rq_vers == NFS_VER2) { if (rqst->rq_vers == NFS_VER2) {
@ -234,6 +239,14 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
goto out; goto out;
} }
if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0) {
nd.nd_flag |= ND_TLS;
if ((xprt->xp_tls & RPCTLS_FLAGS_VERIFIED) != 0)
nd.nd_flag |= ND_TLSCERT;
if ((xprt->xp_tls & RPCTLS_FLAGS_CERTUSER) != 0)
nd.nd_flag |= ND_TLSCERTUSER;
}
nd.nd_maxextsiz = 16384;
#ifdef MAC #ifdef MAC
mac_cred_associate_nfsd(nd.nd_cred); mac_cred_associate_nfsd(nd.nd_cred);
#endif #endif
@ -268,6 +281,11 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
} }
} }
#ifdef KERN_TLS
if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0 &&
rpctls_getinfo(&maxlen, false, false))
nd.nd_maxextsiz = maxlen;
#endif
cacherep = nfs_proc(&nd, rqst->rq_xid, xprt, &rp); cacherep = nfs_proc(&nd, rqst->rq_xid, xprt, &rp);
NFSLOCKV4ROOTMUTEX(); NFSLOCKV4ROOTMUTEX();
nfsv4_relref(&nfsd_suspend_lock); nfsv4_relref(&nfsd_suspend_lock);

View File

@ -3283,6 +3283,19 @@ nfsd_fhtovp(struct nfsrv_descript *nd, struct nfsrvfh *nfp, int lktype,
nd->nd_repstat = EACCES; nd->nd_repstat = EACCES;
} }
/*
* If TLS is required by the export, check the flags in nd_flag.
*/
if (nd->nd_repstat == 0 && ((NFSVNO_EXTLS(exp) &&
(nd->nd_flag & ND_TLS) == 0) ||
(NFSVNO_EXTLSCERT(exp) &&
(nd->nd_flag & ND_TLSCERT) == 0) ||
(NFSVNO_EXTLSCERTUSER(exp) &&
(nd->nd_flag & ND_TLSCERTUSER) == 0))) {
vput(*vpp);
nd->nd_repstat = NFSERR_ACCES;
}
/* /*
* Personally, I've never seen any point in requiring a * Personally, I've never seen any point in requiring a
* reserved port#, since only in the rare case where the * reserved port#, since only in the rare case where the
@ -3547,6 +3560,15 @@ nfsvno_v4rootexport(struct nfsrv_descript *nd)
nd->nd_flag |= ND_EXGSSPRIVACY; nd->nd_flag |= ND_EXGSSPRIVACY;
} }
/* And set ND_EXxx flags for TLS. */
if ((exflags & MNT_EXTLS) != 0) {
nd->nd_flag |= ND_EXTLS;
if ((exflags & MNT_EXTLSCERT) != 0)
nd->nd_flag |= ND_EXTLSCERT;
if ((exflags & MNT_EXTLSCERTUSER) != 0)
nd->nd_flag |= ND_EXTLSCERTUSER;
}
out: out:
NFSEXITCODE(error); NFSEXITCODE(error);
return (error); return (error);

View File

@ -3816,6 +3816,11 @@ nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
clp->lc_uid = nd->nd_cred->cr_uid; clp->lc_uid = nd->nd_cred->cr_uid;
clp->lc_gid = nd->nd_cred->cr_gid; clp->lc_gid = nd->nd_cred->cr_gid;
} }
/* If the client is using TLS, do so for the callback connection. */
if (nd->nd_flag & ND_TLS)
clp->lc_flags |= LCL_TLSCB;
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
clp->lc_program = fxdr_unsigned(u_int32_t, *tl); clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
error = nfsrv_getclientipaddr(nd, clp); error = nfsrv_getclientipaddr(nd, clp);

View File

@ -2114,15 +2114,28 @@ nfsd_checkrootexp(struct nfsrv_descript *nd)
{ {
if ((nd->nd_flag & (ND_GSS | ND_EXAUTHSYS)) == ND_EXAUTHSYS) if ((nd->nd_flag & (ND_GSS | ND_EXAUTHSYS)) == ND_EXAUTHSYS)
return (0); goto checktls;
if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY)) == if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY)) ==
(ND_GSSINTEGRITY | ND_EXGSSINTEGRITY)) (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY))
return (0); goto checktls;
if ((nd->nd_flag & (ND_GSSPRIVACY | ND_EXGSSPRIVACY)) == if ((nd->nd_flag & (ND_GSSPRIVACY | ND_EXGSSPRIVACY)) ==
(ND_GSSPRIVACY | ND_EXGSSPRIVACY)) (ND_GSSPRIVACY | ND_EXGSSPRIVACY))
return (0); goto checktls;
if ((nd->nd_flag & (ND_GSS | ND_GSSINTEGRITY | ND_GSSPRIVACY | if ((nd->nd_flag & (ND_GSS | ND_GSSINTEGRITY | ND_GSSPRIVACY |
ND_EXGSS)) == (ND_GSS | ND_EXGSS)) ND_EXGSS)) == (ND_GSS | ND_EXGSS))
goto checktls;
return (1);
checktls:
if ((nd->nd_flag & ND_EXTLS) == 0)
return (0);
if ((nd->nd_flag & (ND_TLSCERTUSER | ND_EXTLSCERTUSER)) ==
(ND_TLSCERTUSER | ND_EXTLSCERTUSER))
return (0);
if ((nd->nd_flag & (ND_TLSCERT | ND_EXTLSCERT | ND_EXTLSCERTUSER)) ==
(ND_TLSCERT | ND_EXTLSCERT))
return (0);
if ((nd->nd_flag & (ND_TLS | ND_EXTLSCERTUSER | ND_EXTLSCERT)) ==
ND_TLS)
return (0); return (0);
return (1); return (1);
} }