nfsd: Add support for the SP4_MACH_CRED case in ExchangeID
Commit f4179ad46f
added support for operation bitmaps for
NFSv4.1/4.2. This commit uses those to implement the SP4_MACH_CRED
case for the NFSv4.1/4.2 ExchangeID operation since the Linux
NFSv4.1/4.2 client is now using this for Kerberized mounts.
The Linux Kerberized NFSv4.1/4.2 mounts currently work without
support for this because Linux will fall back to SP4_NONE,
but there is no guarantee this fallback will work forever.
This commit only affects Kerberized NFSv4.1/4.2 mounts from
Linux at this time.
MFC after: 3 months
This commit is contained in:
parent
66fbc19fbd
commit
ff2f1f691c
@ -99,7 +99,7 @@ int nfsrv_setclient(struct nfsrv_descript *, struct nfsclient **,
|
||||
nfsquad_t *, nfsquad_t *, NFSPROC_T *);
|
||||
int nfsrv_getclient(nfsquad_t, int, struct nfsclient **, struct nfsdsession *,
|
||||
nfsquad_t, uint32_t, struct nfsrv_descript *, NFSPROC_T *);
|
||||
int nfsrv_destroyclient(nfsquad_t, NFSPROC_T *);
|
||||
int nfsrv_destroyclient(struct nfsrv_descript *, nfsquad_t, NFSPROC_T *);
|
||||
int nfsrv_destroysession(struct nfsrv_descript *, uint8_t *);
|
||||
int nfsrv_bindconnsess(struct nfsrv_descript *, uint8_t *, int *);
|
||||
int nfsrv_freestateid(struct nfsrv_descript *, nfsv4stateid_t *, NFSPROC_T *);
|
||||
|
@ -105,6 +105,8 @@ struct nfsclient {
|
||||
time_t lc_delegtime; /* Old deleg expiry (sec) */
|
||||
nfsquad_t lc_clientid; /* 64 bit clientid */
|
||||
nfsquad_t lc_confirm; /* 64 bit confirm value */
|
||||
nfsopbit_t lc_mustops; /* Must ops SP4_MACH_CRED */
|
||||
nfsopbit_t lc_allowops; /* Allowed ops SP4_MACH_CRED */
|
||||
u_int32_t lc_program; /* RPC Program # */
|
||||
u_int32_t lc_callback; /* Callback id */
|
||||
u_int32_t lc_stateindex; /* Current state index# */
|
||||
|
@ -108,6 +108,7 @@ extern time_t nfsdev_time;
|
||||
extern int nfsrv_writerpc[NFS_NPROCS];
|
||||
extern volatile int nfsrv_devidcnt;
|
||||
extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS];
|
||||
extern int nfsd_debuglevel;
|
||||
|
||||
NFSD_VNET_DECLARE(struct proc *, nfsd_master_proc);
|
||||
|
||||
@ -126,7 +127,9 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
|
||||
{
|
||||
struct nfsrv_descript nd;
|
||||
struct nfsrvcache *rp = NULL;
|
||||
int cacherep, credflavor;
|
||||
rpc_gss_rawcred_t *rcredp;
|
||||
int cacherep, credflavor, i, j;
|
||||
u_char *p;
|
||||
#ifdef KERN_TLS
|
||||
u_int maxlen;
|
||||
#endif
|
||||
@ -245,6 +248,58 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Acquire the principal name for the RPCSEC_GSS cases. */
|
||||
if ((nd.nd_flag & (ND_NFSV4 | ND_GSS)) == (ND_NFSV4 | ND_GSS)) {
|
||||
rcredp = NULL;
|
||||
rpc_gss_getcred_call(rqst, &rcredp, NULL, NULL);
|
||||
/*
|
||||
* The exported principal name consists of:
|
||||
* - TOK_ID bytes with value of 4 and 1.
|
||||
* - 2 byte mech length
|
||||
* - mech
|
||||
* - 4 byte principal name length
|
||||
* - principal name
|
||||
* A call to gss_import_name() would be an
|
||||
* upcall to the gssd, so parse it here.
|
||||
* See lib/libgssapi/gss_import_name.c for the
|
||||
* above format.
|
||||
*/
|
||||
if (rcredp != NULL &&
|
||||
rcredp->client_principal->len > 4 &&
|
||||
rcredp->client_principal->name[0] == 4 &&
|
||||
rcredp->client_principal->name[1] == 1) {
|
||||
/* Skip over the mech. */
|
||||
p = &rcredp->client_principal->name[2];
|
||||
i = (p[0] << 8) | p[1];
|
||||
p += i + 2;
|
||||
i += 4;
|
||||
/*
|
||||
* Set "j" to a bogus length so that the
|
||||
* "i + j" check will fail unless the below
|
||||
* code sets "j" correctly.
|
||||
*/
|
||||
j = rcredp->client_principal->len;
|
||||
if (rcredp->client_principal->len > i + 4) {
|
||||
j = (p[0] << 24) | (p[1] << 16) |
|
||||
(p[2] << 8) | p[3];
|
||||
i += 4;
|
||||
p += 4;
|
||||
}
|
||||
if (i + j == rcredp->client_principal->len) {
|
||||
nd.nd_principal = malloc(j + 1, M_TEMP,
|
||||
M_WAITOK);
|
||||
nd.nd_princlen = j;
|
||||
memcpy(nd.nd_principal, p, j);
|
||||
nd.nd_principal[j] = '\0';
|
||||
NFSD_DEBUG(1, "nfssvc_program: "
|
||||
"principal=%s\n", nd.nd_principal);
|
||||
}
|
||||
}
|
||||
if (nd.nd_princlen == 0)
|
||||
printf("nfssvc_program: cannot get RPCSEC_GSS "
|
||||
"principal name\n");
|
||||
}
|
||||
|
||||
if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0) {
|
||||
nd.nd_flag |= ND_TLS;
|
||||
if ((xprt->xp_tls & RPCTLS_FLAGS_VERIFIED) != 0)
|
||||
@ -334,6 +389,7 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
|
||||
svc_freereq(rqst);
|
||||
|
||||
out:
|
||||
free(nd.nd_principal, M_TEMP);
|
||||
NFSD_CURVNET_RESTORE();
|
||||
ast_kclear(curthread);
|
||||
NFSEXITCODE(0);
|
||||
|
@ -4282,6 +4282,7 @@ nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
uint8_t *verf;
|
||||
uint32_t sp4type, v41flags;
|
||||
struct timespec verstime;
|
||||
nfsopbit_t mustops, allowops;
|
||||
#ifdef INET
|
||||
struct sockaddr_in *sin, *rin;
|
||||
#endif
|
||||
@ -4376,7 +4377,22 @@ nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
else
|
||||
v41flags = NFSV4EXCH_USEPNFSMDS;
|
||||
sp4type = fxdr_unsigned(uint32_t, *tl);
|
||||
if (sp4type != NFSV4EXCH_SP4NONE) {
|
||||
if (sp4type == NFSV4EXCH_SP4MACHCRED) {
|
||||
if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 ||
|
||||
nd->nd_princlen == 0)
|
||||
nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
|
||||
if (nd->nd_repstat == 0)
|
||||
nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL);
|
||||
if (nd->nd_repstat == 0)
|
||||
nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL);
|
||||
if (nd->nd_repstat != 0)
|
||||
goto nfsmout;
|
||||
NFSOPBIT_CLRNOTMUST(&mustops);
|
||||
NFSSET_OPBIT(&clp->lc_mustops, &mustops);
|
||||
NFSOPBIT_CLRNOTALLOWED(&allowops);
|
||||
NFSSET_OPBIT(&clp->lc_allowops, &allowops);
|
||||
clp->lc_flags |= LCL_MACHCRED;
|
||||
} else if (sp4type != NFSV4EXCH_SP4NONE) {
|
||||
nd->nd_repstat = NFSERR_NOTSUPP;
|
||||
goto nfsmout;
|
||||
}
|
||||
@ -4398,12 +4414,17 @@ nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
if (nd->nd_repstat == 0) {
|
||||
if (confirm.lval[1] != 0)
|
||||
v41flags |= NFSV4EXCH_CONFIRMEDR;
|
||||
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
|
||||
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
|
||||
*tl++ = clientid.lval[0]; /* ClientID */
|
||||
*tl++ = clientid.lval[1];
|
||||
*tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
|
||||
*tl++ = txdr_unsigned(v41flags); /* Exch flags */
|
||||
*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
|
||||
*tl = txdr_unsigned(sp4type); /* No SSV */
|
||||
if (sp4type == NFSV4EXCH_SP4MACHCRED) {
|
||||
nfsrv_putopbit(nd, &mustops);
|
||||
nfsrv_putopbit(nd, &allowops);
|
||||
}
|
||||
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER);
|
||||
txdr_hyper(nfsrv_owner_minor, tl); /* Owner Minor */
|
||||
if (nfsrv_owner_major[0] != 0)
|
||||
s = nfsrv_owner_major;
|
||||
@ -4642,7 +4663,7 @@ nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
|
||||
clientid.lval[0] = *tl++;
|
||||
clientid.lval[1] = *tl;
|
||||
nd->nd_repstat = nfsrv_destroyclient(clientid, p);
|
||||
nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p);
|
||||
nfsmout:
|
||||
NFSEXITCODE2(error, nd);
|
||||
return (error);
|
||||
|
@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <fs/nfs/nfsport.h>
|
||||
|
||||
#include <security/mac/mac_framework.h>
|
||||
|
||||
extern struct nfsrvfh nfs_pubfh;
|
||||
extern int nfs_pubfhset;
|
||||
extern struct nfsv4lock nfsv4rootfs_lock;
|
||||
@ -466,6 +468,8 @@ static int nfsv3to4op[NFS_V3NPROCS] = {
|
||||
static struct mtx nfsrvd_statmtx;
|
||||
MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
|
||||
|
||||
static struct ucred *nfsrv_createrootcred(void);
|
||||
|
||||
static void
|
||||
nfsrvd_statstart(int op, struct bintime *now)
|
||||
{
|
||||
@ -715,7 +719,7 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
|
||||
vnode_t vp, nvp, savevp;
|
||||
struct nfsrvfh fh;
|
||||
mount_t new_mp, temp_mp = NULL;
|
||||
struct ucred *credanon;
|
||||
struct ucred *credanon, *rootcred, *savecred;
|
||||
struct nfsexstuff nes, vpnes, savevpnes;
|
||||
fsid_t cur_fsid, save_fsid;
|
||||
static u_int64_t compref = 0;
|
||||
@ -726,6 +730,7 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
|
||||
int bextpg, bextpgsiz;
|
||||
|
||||
p = curthread;
|
||||
rootcred = savecred = NULL;
|
||||
|
||||
/* Check for and optionally clear the no space flags for DSs. */
|
||||
nfsrv_checknospc();
|
||||
@ -967,6 +972,30 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
|
||||
retops++;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for the case of SP4_MACH_CRED and an operation in
|
||||
* the allow set. For these operations, replace nd_cred with
|
||||
* root credentials so that the operation will not fail due
|
||||
* to credentials.
|
||||
* NB: ND_MACHCRED is set by Sequence when the ClientID
|
||||
* specifies LCL_MACHCRED and the RPC is being performed
|
||||
* via krb5i or krb5p using the machine principal.
|
||||
*/
|
||||
if ((nd->nd_flag & ND_MACHCRED) != 0) {
|
||||
if (NFSISSET_OPBIT(&nd->nd_allowops, op)) {
|
||||
/* Replace nd_cred with root creds. */
|
||||
if (rootcred == NULL)
|
||||
rootcred = nfsrv_createrootcred();
|
||||
if (savecred == NULL)
|
||||
savecred = nd->nd_cred;
|
||||
nd->nd_cred = rootcred;
|
||||
} else if (savecred != NULL) {
|
||||
nd->nd_cred = savecred;
|
||||
savecred = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (nfsv4_opflag[op].savereply)
|
||||
nd->nd_flag |= ND_SAVEREPLY;
|
||||
switch (op) {
|
||||
@ -1379,9 +1408,33 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
|
||||
vrele(vp);
|
||||
if (savevp)
|
||||
vrele(savevp);
|
||||
if (savecred != NULL)
|
||||
nd->nd_cred = savecred;
|
||||
if (rootcred != NULL)
|
||||
crfree(rootcred);
|
||||
NFSLOCKV4ROOTMUTEX();
|
||||
nfsv4_relref(&nfsv4rootfs_lock);
|
||||
NFSUNLOCKV4ROOTMUTEX();
|
||||
|
||||
NFSEXITCODE2(0, nd);
|
||||
}
|
||||
|
||||
/* Create a credential for "root". */
|
||||
static struct ucred *
|
||||
nfsrv_createrootcred(void)
|
||||
{
|
||||
struct ucred *cr;
|
||||
gid_t grp;
|
||||
|
||||
cr = crget();
|
||||
cr->cr_uid = cr->cr_ruid = cr->cr_svuid = UID_ROOT;
|
||||
grp = GID_WHEEL;
|
||||
crsetgroups(cr, 1, &grp);
|
||||
cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
|
||||
cr->cr_prison = curthread->td_ucred->cr_prison;
|
||||
prison_hold(cr->cr_prison);
|
||||
#ifdef MAC
|
||||
mac_cred_associate_nfsd(cr);
|
||||
#endif
|
||||
return (cr);
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ static int nfsrv_delegconflict(struct nfsstate *stp, int *haslockp,
|
||||
NFSPROC_T *p, vnode_t vp);
|
||||
static int nfsrv_cleandeleg(vnode_t vp, struct nfslockfile *lfp,
|
||||
struct nfsclient *clp, int *haslockp, NFSPROC_T *p);
|
||||
static int nfsrv_notsamecredname(struct nfsrv_descript *nd,
|
||||
static int nfsrv_notsamecredname(int op, struct nfsrv_descript *nd,
|
||||
struct nfsclient *clp);
|
||||
static time_t nfsrv_leaseexpiry(void);
|
||||
static void nfsrv_delaydelegtimeout(struct nfsstate *stp);
|
||||
@ -205,7 +205,8 @@ static void nfsrv_locallock_commit(struct nfslockfile *lfp, int flags,
|
||||
static void nfsrv_locklf(struct nfslockfile *lfp);
|
||||
static void nfsrv_unlocklf(struct nfslockfile *lfp);
|
||||
static struct nfsdsession *nfsrv_findsession(uint8_t *sessionid);
|
||||
static int nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid);
|
||||
static int nfsrv_freesession(struct nfsrv_descript *nd, struct nfsdsession *sep,
|
||||
uint8_t *sessionid);
|
||||
static int nfsv4_setcbsequence(struct nfsrv_descript *nd, struct nfsclient *clp,
|
||||
int dont_replycache, struct nfsdsession **sepp, int *slotposp);
|
||||
static int nfsv4_getcbsession(struct nfsclient *clp, struct nfsdsession **sepp);
|
||||
@ -239,6 +240,8 @@ static int nfsrv_createdsfile(vnode_t vp, fhandle_t *fhp, struct pnfsdsfile *pf,
|
||||
vnode_t dvp, struct nfsdevice *ds, struct ucred *cred, NFSPROC_T *p,
|
||||
vnode_t *tvpp);
|
||||
static struct nfsdevice *nfsrv_findmirroredds(struct nfsmount *nmp);
|
||||
static int nfsrv_checkmachcred(int op, struct nfsrv_descript *nd,
|
||||
struct nfsclient *clp);
|
||||
|
||||
/*
|
||||
* Scan the client list for a match and either return the current one,
|
||||
@ -378,7 +381,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||
/*
|
||||
* Now, handle the cases where the id is already issued.
|
||||
*/
|
||||
if (nfsrv_notsamecredname(nd, clp)) {
|
||||
if (nfsrv_notsamecredname(NFSV4OP_EXCHANGEID, nd, clp)) {
|
||||
/*
|
||||
* Check to see if there is expired state that should go away.
|
||||
*/
|
||||
@ -447,7 +450,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||
|
||||
/* Get rid of all sessions on this clientid. */
|
||||
LIST_FOREACH_SAFE(sep, &clp->lc_session, sess_list, nsep) {
|
||||
ret = nfsrv_freesession(sep, NULL);
|
||||
ret = nfsrv_freesession(NULL, sep, NULL);
|
||||
if (ret != 0)
|
||||
printf("nfsrv_setclient: verifier changed free"
|
||||
" session failed=%d\n", ret);
|
||||
@ -706,7 +709,8 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||
} else if ((nd->nd_flag & ND_NFSV41) == 0 &&
|
||||
clp->lc_confirm.qval != confirm.qval)
|
||||
error = NFSERR_STALECLIENTID;
|
||||
if (error == 0 && nfsrv_notsamecredname(nd, clp))
|
||||
if (error == 0 && nfsrv_notsamecredname(NFSV4OP_CREATESESSION,
|
||||
nd, clp))
|
||||
error = NFSERR_CLIDINUSE;
|
||||
|
||||
if (!error) {
|
||||
@ -779,7 +783,7 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||
* If called by the Renew Op, we must check the principal.
|
||||
*/
|
||||
if (!error && (opflags & CLOPS_RENEWOP)) {
|
||||
if (nfsrv_notsamecredname(nd, clp)) {
|
||||
if (nfsrv_notsamecredname(0, nd, clp)) {
|
||||
doneok = 0;
|
||||
for (i = 0; i < nfsrv_statehashsize && doneok == 0; i++) {
|
||||
LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) {
|
||||
@ -819,7 +823,7 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||
* Perform the NFSv4.1 destroy clientid.
|
||||
*/
|
||||
int
|
||||
nfsrv_destroyclient(nfsquad_t clientid, NFSPROC_T *p)
|
||||
nfsrv_destroyclient(struct nfsrv_descript *nd, nfsquad_t clientid, NFSPROC_T *p)
|
||||
{
|
||||
struct nfsclient *clp;
|
||||
struct nfsclienthashhead *hp;
|
||||
@ -852,6 +856,15 @@ nfsrv_destroyclient(nfsquad_t clientid, NFSPROC_T *p)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for the SP4_MACH_CRED case. */
|
||||
error = nfsrv_checkmachcred(NFSV4OP_DESTROYCLIENTID, nd, clp);
|
||||
if (error != 0) {
|
||||
NFSLOCKV4ROOTMUTEX();
|
||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
||||
NFSUNLOCKV4ROOTMUTEX();
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up all layouts on the clientid. Should the client return the
|
||||
* layouts?
|
||||
@ -1374,7 +1387,7 @@ nfsrv_cleanclient(struct nfsclient *clp, NFSPROC_T *p)
|
||||
nfsrv_freeopenowner(stp, 1, p);
|
||||
if ((clp->lc_flags & LCL_ADMINREVOKED) == 0)
|
||||
LIST_FOREACH_SAFE(sep, &clp->lc_session, sess_list, nsep)
|
||||
(void)nfsrv_freesession(sep, NULL);
|
||||
(void)nfsrv_freesession(NULL, sep, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4605,7 +4618,7 @@ nfsrv_docallback(struct nfsclient *clp, int procnum, nfsv4stateid_t *stateidp,
|
||||
if (procnum != NFSV4PROC_CBNULL)
|
||||
nfsv4_freeslot(&sep->sess_cbsess, slotpos,
|
||||
true);
|
||||
nfsrv_freesession(sep, NULL);
|
||||
nfsrv_freesession(NULL, sep, NULL);
|
||||
} else if (nd->nd_procnum == NFSV4PROC_CBNULL)
|
||||
error = newnfs_connect(NULL, &clp->lc_req, cred,
|
||||
NULL, 1, dotls, &clp->lc_req.nr_client);
|
||||
@ -4654,7 +4667,7 @@ nfsrv_docallback(struct nfsclient *clp, int procnum, nfsv4stateid_t *stateidp,
|
||||
nfsv4_freeslot(&sep->sess_cbsess, slotpos,
|
||||
true);
|
||||
}
|
||||
nfsrv_freesession(sep, NULL);
|
||||
nfsrv_freesession(NULL, sep, NULL);
|
||||
} else
|
||||
error = newnfs_request(nd, NULL, clp, &clp->lc_req,
|
||||
NULL, NULL, cred, clp->lc_program,
|
||||
@ -5877,12 +5890,18 @@ nfsrv_throwawayopens(NFSPROC_T *p)
|
||||
/*
|
||||
* This function checks to see if the credentials are the same.
|
||||
* The check for same credentials is needed for state management operations
|
||||
* for NFSv4.0 where 1 is returned if not same, 0 is returned otherwise.
|
||||
* for NFSv4.0 or NFSv4.1/4.2 when SP4_MACH_CRED is configured via
|
||||
* ExchangeID.
|
||||
* Returns 1 for not same, 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
nfsrv_notsamecredname(struct nfsrv_descript *nd, struct nfsclient *clp)
|
||||
nfsrv_notsamecredname(int op, struct nfsrv_descript *nd, struct nfsclient *clp)
|
||||
{
|
||||
|
||||
/* Check for the SP4_MACH_CRED case. */
|
||||
if (op != 0 && nfsrv_checkmachcred(op, nd, clp) != 0)
|
||||
return (1);
|
||||
|
||||
/* For NFSv4.1/4.2, SP4_NONE always allows this. */
|
||||
if ((nd->nd_flag & ND_NFSV41) != 0)
|
||||
return (0);
|
||||
@ -6301,6 +6320,16 @@ nfsrv_checksequence(struct nfsrv_descript *nd, uint32_t sequenceid,
|
||||
nd->nd_clientid.qval = sep->sess_clp->lc_clientid.qval;
|
||||
nd->nd_flag |= ND_IMPLIEDCLID;
|
||||
|
||||
/* Handle the SP4_MECH_CRED case for NFSv4.1/4.2. */
|
||||
if ((sep->sess_clp->lc_flags & LCL_MACHCRED) != 0 &&
|
||||
(nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) != 0 &&
|
||||
nd->nd_princlen == sep->sess_clp->lc_namelen &&
|
||||
!NFSBCMP(sep->sess_clp->lc_name, nd->nd_principal,
|
||||
nd->nd_princlen)) {
|
||||
nd->nd_flag |= ND_MACHCRED;
|
||||
NFSSET_OPBIT(&nd->nd_allowops, &sep->sess_clp->lc_allowops);
|
||||
}
|
||||
|
||||
/* Save maximum request and reply sizes. */
|
||||
nd->nd_maxreq = sep->sess_maxreq;
|
||||
nd->nd_maxresp = sep->sess_maxresp;
|
||||
@ -6458,7 +6487,7 @@ nfsrv_destroysession(struct nfsrv_descript *nd, uint8_t *sessionid)
|
||||
} while (igotlock == 0);
|
||||
NFSUNLOCKV4ROOTMUTEX();
|
||||
|
||||
error = nfsrv_freesession(NULL, sessionid);
|
||||
error = nfsrv_freesession(nd, NULL, sessionid);
|
||||
if (error == 0 && samesess != 0)
|
||||
nd->nd_flag &= ~ND_HASSEQUENCE;
|
||||
|
||||
@ -6491,6 +6520,9 @@ nfsrv_bindconnsess(struct nfsrv_descript *nd, uint8_t *sessionid, int *foreaftp)
|
||||
sep = nfsrv_findsession(sessionid);
|
||||
if (sep != NULL) {
|
||||
clp = sep->sess_clp;
|
||||
error = nfsrv_checkmachcred(NFSV4OP_BINDCONNTOSESS, nd, clp);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
if (*foreaftp == NFSCDFC4_BACK ||
|
||||
*foreaftp == NFSCDFC4_BACK_OR_BOTH ||
|
||||
*foreaftp == NFSCDFC4_FORE_OR_BOTH) {
|
||||
@ -6538,6 +6570,7 @@ nfsrv_bindconnsess(struct nfsrv_descript *nd, uint8_t *sessionid, int *foreaftp)
|
||||
}
|
||||
} else
|
||||
error = NFSERR_BADSESSION;
|
||||
out:
|
||||
NFSUNLOCKSESSION(shp);
|
||||
NFSUNLOCKSTATE();
|
||||
if (savxprt != NULL)
|
||||
@ -6549,7 +6582,8 @@ nfsrv_bindconnsess(struct nfsrv_descript *nd, uint8_t *sessionid, int *foreaftp)
|
||||
* Free up a session structure.
|
||||
*/
|
||||
static int
|
||||
nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid)
|
||||
nfsrv_freesession(struct nfsrv_descript *nd, struct nfsdsession *sep,
|
||||
uint8_t *sessionid)
|
||||
{
|
||||
struct nfssessionhash *shp;
|
||||
int i;
|
||||
@ -6564,6 +6598,14 @@ nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid)
|
||||
NFSLOCKSESSION(shp);
|
||||
}
|
||||
if (sep != NULL) {
|
||||
/* Check for the SP4_MACH_CRED case. */
|
||||
if (nd != NULL && nfsrv_checkmachcred(NFSV4OP_DESTROYSESSION,
|
||||
nd, sep->sess_clp) != 0) {
|
||||
NFSUNLOCKSESSION(shp);
|
||||
NFSUNLOCKSTATE();
|
||||
return (NFSERR_AUTHERR | AUTH_TOOWEAK);
|
||||
}
|
||||
|
||||
sep->sess_refcnt--;
|
||||
if (sep->sess_refcnt > 0) {
|
||||
NFSUNLOCKSESSION(shp);
|
||||
@ -8883,3 +8925,23 @@ nfsrv_marknospc(char *devid, bool setit)
|
||||
NFSUNLOCKLAYOUT(lhyp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if SP4_MACH_CRED is in use and, if it is, check that the
|
||||
* correct machine credential is being used.
|
||||
*/
|
||||
static int
|
||||
nfsrv_checkmachcred(int op, struct nfsrv_descript *nd, struct nfsclient *clp)
|
||||
{
|
||||
|
||||
if ((clp->lc_flags & LCL_MACHCRED) == 0 ||
|
||||
!NFSISSET_OPBIT(&clp->lc_mustops, op))
|
||||
return (0);
|
||||
KASSERT((nd->nd_flag & ND_NFSV41) != 0,
|
||||
("nfsrv_checkmachcred: MachCred for NFSv4.0"));
|
||||
if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) != 0 &&
|
||||
nd->nd_princlen == clp->lc_namelen &&
|
||||
!NFSBCMP(nd->nd_principal, clp->lc_name, nd->nd_princlen))
|
||||
return (0);
|
||||
return (NFSERR_AUTHERR | AUTH_TOOWEAK);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user