diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 1996-03-31 13:16:48 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 1996-03-31 13:16:48 +0000 |
commit | 21504931d6eeb371924b7751ab95d7209ef959db (patch) | |
tree | d80b42388119345065cd25ccf71050a3ed63ae26 /sys/nfs/nfs_socket.c | |
parent | 633344117da42400851635ede8dd4464fb125ae7 (diff) |
From NetBSD: NFSv3 import (tomorrow's Net's kernel)
Open's patches kept in. i'll possibly take a look at Lite2 soon,
is there smth usefull ?..
Diffstat (limited to 'sys/nfs/nfs_socket.c')
-rw-r--r-- | sys/nfs/nfs_socket.c | 568 |
1 files changed, 377 insertions, 191 deletions
diff --git a/sys/nfs/nfs_socket.c b/sys/nfs/nfs_socket.c index 84bc8cb97e4..bd01a9830a3 100644 --- a/sys/nfs/nfs_socket.c +++ b/sys/nfs/nfs_socket.c @@ -1,8 +1,8 @@ -/* $OpenBSD: nfs_socket.c,v 1.3 1996/02/29 09:24:53 niklas Exp $ */ -/* $NetBSD: nfs_socket.c,v 1.23 1996/02/09 21:48:29 christos Exp $ */ +/* $OpenBSD: nfs_socket.c,v 1.4 1996/03/31 13:15:47 mickey Exp $ */ +/* $NetBSD: nfs_socket.c,v 1.26 1996/02/25 17:47:26 fvdl Exp $ */ /* - * Copyright (c) 1989, 1991, 1993 + * Copyright (c) 1989, 1991, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +36,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_socket.c 8.3 (Berkeley) 1/12/94 + * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 */ /* @@ -60,8 +60,9 @@ #include <netinet/in.h> #include <netinet/tcp.h> + #include <nfs/rpcv2.h> -#include <nfs/nfsv2.h> +#include <nfs/nfsproto.h> #include <nfs/nfs.h> #include <nfs/xdr_subs.h> #include <nfs/nfsm_subs.h> @@ -97,36 +98,13 @@ * External data, mostly RPC constants in XDR form */ extern u_int32_t rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, - rpc_auth_unix, rpc_msgaccepted, rpc_call, rpc_autherr, rpc_rejectedcred, + rpc_auth_unix, rpc_msgaccepted, rpc_call, rpc_autherr, rpc_auth_kerb; -extern u_int32_t nfs_prog, nfs_vers, nqnfs_prog, nqnfs_vers; +extern u_int32_t nfs_prog, nqnfs_prog; extern time_t nqnfsstarttime; -extern int nonidempotent[NFS_NPROCS]; - -/* - * Maps errno values to nfs error numbers. - * Use NFSERR_IO as the catch all for ones not specifically defined in - * RFC 1094. - */ -static int nfsrv_errmap[ELAST] = { - NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, - NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, - NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, -}; +extern struct nfsstats nfsstats; +extern int nfsv3_procid[NFS_NPROCS]; +extern int nfs_ticks; /* * Defines which timer to use for the procnum. @@ -137,7 +115,8 @@ static int nfsrv_errmap[ELAST] = { * 4 - write */ static int proct[NFS_NPROCS] = { - 0, 1, 0, 0, 2, 3, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, + 0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, }; /* @@ -177,8 +156,8 @@ nfs_connect(nmp, rep) nmp->nm_so = (struct socket *)0; saddr = mtod(nmp->nm_nam, struct sockaddr *); - error = socreate(saddr->sa_family, - &nmp->nm_so, nmp->nm_sotype, nmp->nm_soproto); + error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype, + nmp->nm_soproto); if (error) goto bad; so = nmp->nm_so; @@ -213,7 +192,8 @@ nfs_connect(nmp, rep) goto bad; } } else { - if ((error = soconnect(so, nmp->nm_nam)) != 0) + error = soconnect(so, nmp->nm_nam); + if (error) goto bad; /* @@ -227,7 +207,7 @@ nfs_connect(nmp, rep) "nfscon", 2 * hz); if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 && rep && - (error = nfs_sigintr(nmp, rep, rep->r_procp))) { + (error = nfs_sigintr(nmp, rep, rep->r_procp)) != 0){ so->so_state &= ~SS_ISCONNECTING; splx(s); goto bad; @@ -250,10 +230,12 @@ nfs_connect(nmp, rep) } if (nmp->nm_sotype == SOCK_DGRAM) { sndreserve = nmp->nm_wsize + NFS_MAXPKTHDR; - rcvreserve = nmp->nm_rsize + NFS_MAXPKTHDR; + rcvreserve = max(nmp->nm_rsize, nmp->nm_readdirsize) + + NFS_MAXPKTHDR; } else if (nmp->nm_sotype == SOCK_SEQPACKET) { sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2; - rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR) * 2; + rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) + + NFS_MAXPKTHDR) * 2; } else { if (nmp->nm_sotype != SOCK_STREAM) panic("nfscon sotype"); @@ -274,7 +256,8 @@ nfs_connect(nmp, rep) rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + sizeof (u_int32_t)) * 2; } - if ((error = soreserve(so, sndreserve, rcvreserve)) != 0) + error = soreserve(so, sndreserve, rcvreserve); + if (error) goto bad; so->so_rcv.sb_flags |= SB_NOINTR; so->so_snd.sb_flags |= SB_NOINTR; @@ -460,7 +443,8 @@ nfs_receive(rep, aname, mp) * until we have an entire rpc request/reply. */ if (sotype != SOCK_DGRAM) { - if ((error = nfs_sndlock(&rep->r_nmp->nm_flag, rep)) != 0) + error = nfs_sndlock(&rep->r_nmp->nm_flag, rep); + if (error) return (error); tryagain: /* @@ -476,8 +460,10 @@ tryagain: nfs_sndunlock(&rep->r_nmp->nm_flag); return (EINTR); } - if ((so = rep->r_nmp->nm_so) == NULL) { - if ((error = nfs_reconnect(rep)) != 0) { + so = rep->r_nmp->nm_so; + if (!so) { + error = nfs_reconnect(rep); + if (error) { nfs_sndunlock(&rep->r_nmp->nm_flag); return (error); } @@ -489,7 +475,7 @@ tryagain: error = nfs_send(so, rep->r_nmp->nm_nam, m, rep); if (error) { if (error == EINTR || error == ERESTART || - (error = nfs_reconnect(rep))) { + (error = nfs_reconnect(rep)) != 0) { nfs_sndunlock(&rep->r_nmp->nm_flag); return (error); } @@ -658,7 +644,8 @@ nfs_reply(myrep) * Also necessary for connection based protocols to avoid * race conditions during a reconnect. */ - if ((error = nfs_rcvlock(myrep)) != 0) + error = nfs_rcvlock(myrep); + if (error) return (error); /* Already received, bye bye */ if (myrep->r_mrep != NULL) { @@ -820,13 +807,16 @@ nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp) struct nfsmount *nmp; struct mbuf *md, *mheadend; struct nfsnode *np; + char nickv[RPCX_NICKVERF]; time_t reqtime, waituntil; caddr_t dpos, cp2; int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type; int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0; + int verf_len, verf_type; u_int32_t xid; u_quad_t frev; - char *auth_str; + char *auth_str, *verf_str; + NFSKERBKEY_T key; /* save session key */ nmp = VFSTONFS(vp->v_mount); MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); @@ -846,19 +836,21 @@ nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp) * Get the RPC header with authorization. */ kerbauth: - auth_str = (char *)0; + verf_str = auth_str = (char *)0; if (nmp->nm_flag & NFSMNT_KERB) { - if (failed_auth) { - error = nfs_getauth(nmp, rep, cred, &auth_type, - &auth_str, &auth_len); + verf_str = nickv; + verf_len = sizeof (nickv); + auth_type = RPCAUTH_KERB4; + bzero((caddr_t)key, sizeof (key)); + if (failed_auth || nfs_getnickauth(nmp, cred, &auth_str, + &auth_len, verf_str, verf_len)) { + error = nfs_getauth(nmp, rep, cred, &auth_str, + &auth_len, verf_str, &verf_len, key); if (error) { free((caddr_t)rep, M_NFSREQ); m_freem(mrest); return (error); } - } else { - auth_type = RPCAUTH_UNIX; - auth_len = 5 * NFSX_UNSIGNED; } } else { auth_type = RPCAUTH_UNIX; @@ -866,8 +858,8 @@ kerbauth: nmp->nm_numgrps : cred->cr_ngroups) << 2) + 5 * NFSX_UNSIGNED; } - m = nfsm_rpchead(cred, (nmp->nm_flag & NFSMNT_NQNFS), procnum, - auth_type, auth_len, auth_str, mrest, mrest_len, &mheadend, &xid); + m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len, + auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid); if (auth_str) free(auth_str, M_TEMP); @@ -973,12 +965,12 @@ tryagain: /* * break down the rpc header and check if ok */ - nfsm_dissect(tl, u_int32_t *, 3*NFSX_UNSIGNED); + nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); if (*tl++ == rpc_msgdenied) { if (*tl == rpc_mismatch) error = EOPNOTSUPP; else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) { - if (*tl == rpc_rejectedcred && failed_auth == 0) { + if (!failed_auth) { failed_auth++; mheadend->m_next = (struct mbuf *)0; m_freem(mrep); @@ -995,22 +987,25 @@ tryagain: } /* - * skip over the auth_verf, someday we may want to cache auth_short's - * for nfs_reqhead(), but for now just dump it + * Grab any Kerberos verifier, otherwise just throw it away. */ - if (*++tl != 0) { - i = nfsm_rndup(fxdr_unsigned(int32_t, *tl)); - nfsm_adv(i); - } + verf_type = fxdr_unsigned(int, *tl++); + i = fxdr_unsigned(int32_t, *tl); + if ((nmp->nm_flag & NFSMNT_KERB) && verf_type == RPCAUTH_KERB4) { + error = nfs_savenickauth(nmp, cred, i, key, &md, &dpos, mrep); + if (error) + goto nfsmout; + } else if (i > 0) + nfsm_adv(nfsm_rndup(i)); nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); /* 0 == ok */ if (*tl == 0) { nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); if (*tl != 0) { error = fxdr_unsigned(int, *tl); - m_freem(mrep); - if ((nmp->nm_flag & NFSMNT_NQNFS) && - error == NQNFS_TRYLATER) { + if ((nmp->nm_flag & NFSMNT_NFSV3) && + error == NFSERR_TRYLATER) { + m_freem(mrep); error = 0; waituntil = time.tv_sec + trylater_delay; while (time.tv_sec < waituntil) @@ -1028,6 +1023,13 @@ tryagain: */ if (error == ESTALE) cache_purge(vp); + if (nmp->nm_flag & NFSMNT_NFSV3) { + *mrp = mrep; + *mdp = md; + *dposp = dpos; + error |= NFSERR_RETERR; + } else + m_freem(mrep); m_freem(rep->r_mreq); free((caddr_t)rep, M_NFSREQ); return (error); @@ -1059,10 +1061,10 @@ tryagain: return (0); } m_freem(mrep); - m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); error = EPROTONOSUPPORT; nfsmout: + m_freem(rep->r_mreq); + free((caddr_t)rep, M_NFSREQ); return (error); } #endif /* NFSCLIENT */ @@ -1072,9 +1074,10 @@ nfsmout: * siz arg. is used to decide if adding a cluster is worthwhile */ int -nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) +nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp) int siz; - struct nfsd *nd; + struct nfsrv_descript *nd; + struct nfssvc_sock *slp; int err; int cache; u_quad_t *frev; @@ -1099,47 +1102,97 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) } else mreq->m_data += max_hdr; tl = mtod(mreq, u_int32_t *); - mreq->m_len = 6*NFSX_UNSIGNED; - bpos = ((caddr_t)tl)+mreq->m_len; + mreq->m_len = 6 * NFSX_UNSIGNED; + bpos = ((caddr_t)tl) + mreq->m_len; *tl++ = txdr_unsigned(nd->nd_retxid); *tl++ = rpc_reply; - if (err == ERPCMISMATCH || err == NQNFS_AUTHERR) { + if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) { *tl++ = rpc_msgdenied; - if (err == NQNFS_AUTHERR) { + if (err & NFSERR_AUTHERR) { *tl++ = rpc_autherr; - *tl = rpc_rejectedcred; + *tl = txdr_unsigned(err & ~NFSERR_AUTHERR); mreq->m_len -= NFSX_UNSIGNED; bpos -= NFSX_UNSIGNED; } else { *tl++ = rpc_mismatch; - *tl++ = txdr_unsigned(2); - *tl = txdr_unsigned(2); + *tl++ = txdr_unsigned(RPC_VER2); + *tl = txdr_unsigned(RPC_VER2); } } else { *tl++ = rpc_msgaccepted; - *tl++ = 0; - *tl++ = 0; + + /* + * For Kerberos authentication, we must send the nickname + * verifier back, otherwise just RPCAUTH_NULL. + */ + if (nd->nd_flag & ND_KERBFULL) { + register struct nfsuid *nuidp; + struct timeval ktvin, ktvout; + + for (nuidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first; + nuidp != 0; nuidp = nuidp->nu_hash.le_next) { + if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid && + (!nd->nd_nam2 || netaddr_match(NU_NETFAM(nuidp), + &nuidp->nu_haddr, nd->nd_nam2))) + break; + } + if (nuidp) { + ktvin.tv_sec = + txdr_unsigned(nuidp->nu_timestamp.tv_sec - 1); + ktvin.tv_usec = + txdr_unsigned(nuidp->nu_timestamp.tv_usec); + + /* + * Encrypt the timestamp in ecb mode using the + * session key. + */ +#ifdef NFSKERB + XXX +#endif + + *tl++ = rpc_auth_kerb; + *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED); + *tl = ktvout.tv_sec; + nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + *tl++ = ktvout.tv_usec; + *tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid); + } else { + *tl++ = 0; + *tl++ = 0; + } + } else { + *tl++ = 0; + *tl++ = 0; + } switch (err) { case EPROGUNAVAIL: *tl = txdr_unsigned(RPC_PROGUNAVAIL); break; case EPROGMISMATCH: *tl = txdr_unsigned(RPC_PROGMISMATCH); - nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); - *tl++ = txdr_unsigned(2); - *tl = txdr_unsigned(2); /* someday 3 */ + nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + if (nd->nd_flag & ND_NQNFS) { + *tl++ = txdr_unsigned(3); + *tl = txdr_unsigned(3); + } else { + *tl++ = txdr_unsigned(2); + *tl = txdr_unsigned(3); + } break; case EPROCUNAVAIL: *tl = txdr_unsigned(RPC_PROCUNAVAIL); break; + case EBADRPC: + *tl = txdr_unsigned(RPC_GARBAGE); + break; default: *tl = 0; - if (err != VNOVAL) { + if (err != NFSERR_RETVOID) { nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); if (err) - *tl = txdr_unsigned(nfsrv_errmap[err - 1]); + *tl = txdr_unsigned(nfsrv_errmap(nd, err)); else - *tl = 0; + *tl = 0; } break; }; @@ -1148,16 +1201,14 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) /* * For nqnfs, piggyback lease as requested. */ - if (nd->nd_nqlflag != NQL_NOVAL && err == 0) { - if (nd->nd_nqlflag) { - nfsm_build(tl, u_int32_t *, 5*NFSX_UNSIGNED); - *tl++ = txdr_unsigned(nd->nd_nqlflag); + if ((nd->nd_flag & ND_NQNFS) && err == 0) { + if (nd->nd_flag & ND_LEASE) { + nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(nd->nd_flag & ND_LEASE); *tl++ = txdr_unsigned(cache); *tl++ = txdr_unsigned(nd->nd_duration); txdr_hyper(frev, tl); } else { - if (nd->nd_nqlflag != 0) - panic("nqreph"); nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); *tl = 0; } @@ -1165,7 +1216,7 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) *mrq = mreq; *mbp = mb; *bposp = bpos; - if (err != 0 && err != VNOVAL) + if (err != 0 && err != NFSERR_RETVOID) nfsstats.srvrpc_errs++; return (0); } @@ -1178,17 +1229,19 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) */ void nfs_timer(arg) - void *arg; + void *arg; /* never used */ { register struct nfsreq *rep; register struct mbuf *m; register struct socket *so; register struct nfsmount *nmp; register int timeo; + register struct nfssvc_sock *slp; #ifdef NFSSERVER static long lasttime = 0; #endif int s, error; + u_quad_t cur_usec; s = splsoftnet(); for (rep = nfs_reqq.tqh_first; rep != 0; rep = rep->r_chain.tqe_next) { @@ -1286,9 +1339,20 @@ nfs_timer(arg) lasttime = time.tv_sec; nqnfs_serverd(); } + + /* + * Scan the write gathering queues for writes that need to be + * completed now. + */ + cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec; + for (slp = nfssvc_sockhead.tqh_first; slp != 0; + slp = slp->ns_chain.tqe_next) { + if (slp->ns_tq.lh_first && slp->ns_tq.lh_first->nd_time<=cur_usec) + nfsrv_wakenfsd(slp); + } #endif /* NFSSERVER */ splx(s); - timeout(nfs_timer, (void *)0, hz / NFS_HZ); + timeout(nfs_timer, (void *)0, nfs_ticks); } /* @@ -1504,8 +1568,9 @@ nfs_realign(m, hsiz) * - fill in the cred struct. */ int -nfs_getreq(nd, has_header) - register struct nfsd *nd; +nfs_getreq(nd, nfsd, has_header) + register struct nfsrv_descript *nd; + struct nfsd *nfsd; int has_header; { register int len, i; @@ -1513,57 +1578,66 @@ nfs_getreq(nd, has_header) register int32_t t1; struct uio uio; struct iovec iov; - caddr_t dpos, cp2; + caddr_t dpos, cp2, cp; u_int32_t nfsvers, auth_type; - int error = 0, nqnfs = 0; + uid_t nickuid; + int error = 0, nqnfs = 0, ticklen; struct mbuf *mrep, *md; + register struct nfsuid *nuidp; + struct timeval tvin, tvout; mrep = nd->nd_mrep; md = nd->nd_md; dpos = nd->nd_dpos; if (has_header) { - nfsm_dissect(tl, u_int32_t *, 10*NFSX_UNSIGNED); - nd->nd_retxid = fxdr_unsigned(u_int32_t , *tl++); + nfsm_dissect(tl, u_int32_t *, 10 * NFSX_UNSIGNED); + nd->nd_retxid = fxdr_unsigned(u_int32_t, *tl++); if (*tl++ != rpc_call) { m_freem(mrep); return (EBADRPC); } - } else { - nfsm_dissect(tl, u_int32_t *, 8*NFSX_UNSIGNED); - } + } else + nfsm_dissect(tl, u_int32_t *, 8 * NFSX_UNSIGNED); nd->nd_repstat = 0; + nd->nd_flag = 0; if (*tl++ != rpc_vers) { nd->nd_repstat = ERPCMISMATCH; nd->nd_procnum = NFSPROC_NOOP; return (0); } - nfsvers = nfs_vers; if (*tl != nfs_prog) { - if (*tl == nqnfs_prog) { + if (*tl == nqnfs_prog) nqnfs++; - nfsvers = nqnfs_vers; - } else { + else { nd->nd_repstat = EPROGUNAVAIL; nd->nd_procnum = NFSPROC_NOOP; return (0); } } tl++; - if (*tl++ != nfsvers) { + nfsvers = fxdr_unsigned(u_int32_t, *tl++); + if (((nfsvers < NFS_VER2 || nfsvers > NFS_VER3) && !nqnfs) || + (nfsvers != NQNFS_VER3 && nqnfs)) { nd->nd_repstat = EPROGMISMATCH; nd->nd_procnum = NFSPROC_NOOP; return (0); } - nd->nd_procnum = fxdr_unsigned(u_int32_t , *tl++); + if (nqnfs) + nd->nd_flag = (ND_NFSV3 | ND_NQNFS); + else if (nfsvers == NFS_VER3) + nd->nd_flag = ND_NFSV3; + nd->nd_procnum = fxdr_unsigned(u_int32_t, *tl++); if (nd->nd_procnum == NFSPROC_NULL) return (0); if (nd->nd_procnum >= NFS_NPROCS || - (!nqnfs && nd->nd_procnum > NFSPROC_STATFS) || - (*tl != rpc_auth_unix && *tl != rpc_auth_kerb)) { + (!nqnfs && nd->nd_procnum >= NQNFSPROC_GETLEASE) || + (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) { nd->nd_repstat = EPROCUNAVAIL; nd->nd_procnum = NFSPROC_NOOP; return (0); } + if ((nd->nd_flag & ND_NFSV3) == 0) + nd->nd_procnum = nfsv3_procid[nd->nd_procnum]; auth_type = *tl++; len = fxdr_unsigned(int, *tl++); if (len < 0 || len > RPCAUTH_MAXSIZ) { @@ -1571,6 +1645,7 @@ nfs_getreq(nd, has_header) return (EBADRPC); } + nd->nd_flag &= ~ND_KERBAUTH; /* * Handle auth_unix or auth_kerb. */ @@ -1581,7 +1656,9 @@ nfs_getreq(nd, has_header) return (EBADRPC); } nfsm_adv(nfsm_rndup(len)); - nfsm_dissect(tl, u_int32_t *, 3*NFSX_UNSIGNED); + nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + bzero((caddr_t)&nd->nd_cr, sizeof (struct ucred)); + nd->nd_cr.cr_ref = 1; nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++); len = fxdr_unsigned(int, *tl); @@ -1589,45 +1666,124 @@ nfs_getreq(nd, has_header) m_freem(mrep); return (EBADRPC); } - nfsm_dissect(tl, u_int32_t *, (len + 2)*NFSX_UNSIGNED); + nfsm_dissect(tl, u_int32_t *, (len + 2) * NFSX_UNSIGNED); for (i = 0; i < len; i++) - if (i < NGROUPS) - nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); - else - tl++; + if (i < NGROUPS) + nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); + else + tl++; nd->nd_cr.cr_ngroups = (len > NGROUPS) ? NGROUPS : len; - } else if (auth_type == rpc_auth_kerb) { - nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); - nd->nd_authlen = fxdr_unsigned(int, *tl); - uio.uio_resid = nfsm_rndup(nd->nd_authlen); - if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { + if (nd->nd_cr.cr_ngroups > 1) + nfsrvw_sort(nd->nd_cr.cr_groups, nd->nd_cr.cr_ngroups); + len = fxdr_unsigned(int, *++tl); + if (len < 0 || len > RPCAUTH_MAXSIZ) { m_freem(mrep); return (EBADRPC); } - uio.uio_offset = 0; - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_segflg = UIO_SYSSPACE; - iov.iov_base = (caddr_t)nd->nd_authstr; - iov.iov_len = RPCAUTH_MAXSIZ; - nfsm_mtouio(&uio, uio.uio_resid); - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - nd->nd_flag |= NFSD_NEEDAUTH; - } + if (len > 0) + nfsm_adv(nfsm_rndup(len)); + } else if (auth_type == rpc_auth_kerb) { + switch (fxdr_unsigned(int, *tl++)) { + case RPCAKN_FULLNAME: + ticklen = fxdr_unsigned(int, *tl); + *((u_int32_t *)nfsd->nfsd_authstr) = *tl; + uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED; + nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED; + if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { + m_freem(mrep); + return (EBADRPC); + } + uio.uio_offset = 0; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_segflg = UIO_SYSSPACE; + iov.iov_base = (caddr_t)&nfsd->nfsd_authstr[4]; + iov.iov_len = RPCAUTH_MAXSIZ - 4; + nfsm_mtouio(&uio, uio.uio_resid); + nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + if (*tl++ != rpc_auth_kerb || + fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) { + printf("Bad kerb verifier\n"); + nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + nfsm_dissect(cp, caddr_t, 4 * NFSX_UNSIGNED); + tl = (u_int32_t *)cp; + if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) { + printf("Not fullname kerb verifier\n"); + nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + cp += NFSX_UNSIGNED; + bcopy(cp, nfsd->nfsd_verfstr, 3 * NFSX_UNSIGNED); + nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED; + nd->nd_flag |= ND_KERBFULL; + nfsd->nfsd_flag |= NFSD_NEEDAUTH; + break; + case RPCAKN_NICKNAME: + if (len != 2 * NFSX_UNSIGNED) { + printf("Kerb nickname short\n"); + nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + nickuid = fxdr_unsigned(uid_t, *tl); + nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + if (*tl++ != rpc_auth_kerb || + fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) { + printf("Kerb nick verifier bad\n"); + nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + tvin.tv_sec = *tl++; + tvin.tv_usec = *tl; + + for (nuidp = NUIDHASH(nfsd->nfsd_slp,nickuid)->lh_first; + nuidp != 0; nuidp = nuidp->nu_hash.le_next) { + if (nuidp->nu_cr.cr_uid == nickuid && + (!nd->nd_nam2 || + netaddr_match(NU_NETFAM(nuidp), + &nuidp->nu_haddr, nd->nd_nam2))) + break; + } + if (!nuidp) { + nd->nd_repstat = + (NFSERR_AUTHERR|AUTH_REJECTCRED); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } - /* - * Do we have any use for the verifier. - * According to the "Remote Procedure Call Protocol Spec." it - * should be AUTH_NULL, but some clients make it AUTH_UNIX? - * For now, just skip over it - */ - len = fxdr_unsigned(int, *++tl); - if (len < 0 || len > RPCAUTH_MAXSIZ) { - m_freem(mrep); - return (EBADRPC); - } - if (len > 0) { - nfsm_adv(nfsm_rndup(len)); + /* + * Now, decrypt the timestamp using the session key + * and validate it. + */ +#ifdef NFSKERB + XXX +#endif + + tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec); + tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec); + if (nuidp->nu_expire < time.tv_sec || + nuidp->nu_timestamp.tv_sec > tvout.tv_sec || + (nuidp->nu_timestamp.tv_sec == tvout.tv_sec && + nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) { + nuidp->nu_expire = 0; + nd->nd_repstat = + (NFSERR_AUTHERR|AUTH_REJECTVERF); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + nfsrv_setcred(&nuidp->nu_cr, &nd->nd_cr); + nd->nd_flag |= ND_KERBNICK; + }; + } else { + nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED); + nd->nd_procnum = NFSPROC_NOOP; + return (0); } /* @@ -1635,16 +1791,14 @@ nfs_getreq(nd, has_header) */ if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) { nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - nd->nd_nqlflag = fxdr_unsigned(int, *tl); - if (nd->nd_nqlflag) { + nd->nd_flag |= fxdr_unsigned(int, *tl); + if (nd->nd_flag & ND_LEASE) { nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - nd->nd_duration = fxdr_unsigned(int, *tl); + nd->nd_duration = fxdr_unsigned(u_int32_t, *tl); } else nd->nd_duration = NQ_MINLEASE; - } else { - nd->nd_nqlflag = NQL_NOVAL; + } else nd->nd_duration = NQ_MINLEASE; - } nd->nd_md = md; nd->nd_dpos = dpos; return (0); @@ -1652,7 +1806,7 @@ nfsmout: return (error); } -void +int nfs_msg(p, server, msg) struct proc *p; char *server, *msg; @@ -1665,35 +1819,39 @@ nfs_msg(p, server, msg) tpr = NULL; tprintf(tpr, "nfs server %s: %s\n", server, msg); tprintf_close(tpr); + return (0); } #ifdef NFSSERVER -int (*nfsrv_procs[NFS_NPROCS]) __P((struct nfsd *, struct mbuf *, struct mbuf *, - caddr_t, struct ucred *, struct mbuf *, +int (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *, + struct nfssvc_sock *, struct proc *, struct mbuf **)) = { nfsrv_null, nfsrv_getattr, nfsrv_setattr, - nfsrv_noop, nfsrv_lookup, + nfsrv3_access, nfsrv_readlink, nfsrv_read, - nfsrv_noop, nfsrv_write, nfsrv_create, + nfsrv_mkdir, + nfsrv_symlink, + nfsrv_mknod, nfsrv_remove, + nfsrv_rmdir, nfsrv_rename, nfsrv_link, - nfsrv_symlink, - nfsrv_mkdir, - nfsrv_rmdir, nfsrv_readdir, + nfsrv_readdirplus, nfsrv_statfs, - nqnfsrv_readdirlook, + nfsrv_fsinfo, + nfsrv_pathconf, + nfsrv_commit, nqnfsrv_getlease, nqnfsrv_vacated, nfsrv_noop, - nqnfsrv_access, + nfsrv_noop }; /* @@ -1764,7 +1922,8 @@ nfsrv_rcv(so, arg, waitflag) /* * Now try and parse record(s) out of the raw stream data. */ - if ((error = nfsrv_getstream(slp, waitflag)) != 0) { + error = nfsrv_getstream(slp, waitflag); + if (error) { if (error == EPERM) slp->ns_flag |= SLP_DISCONN; else @@ -1819,11 +1978,11 @@ nfsrv_getstream(slp, waitflag) register struct nfssvc_sock *slp; int waitflag; { - register struct mbuf *m; + register struct mbuf *m, **mpp; register char *cp1, *cp2; register int len; struct mbuf *om, *m2, *recm = NULL; - u_long recmark; + u_int32_t recmark; if (slp->ns_flag & SLP_GETSTREAM) panic("nfs getstream"); @@ -1853,7 +2012,12 @@ nfsrv_getstream(slp, waitflag) } } slp->ns_cc -= NFSX_UNSIGNED; - slp->ns_reclen = ntohl(recmark) & ~0x80000000; + recmark = ntohl(recmark); + slp->ns_reclen = recmark & ~0x80000000; + if (recmark & 0x80000000) + slp->ns_flag |= SLP_LASTFRAG; + else + slp->ns_flag &= ~SLP_LASTFRAG; if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) { slp->ns_flag &= ~SLP_GETSTREAM; return (EPERM); @@ -1907,12 +2071,23 @@ nfsrv_getstream(slp, waitflag) slp->ns_flag &= ~SLP_GETSTREAM; return (0); } - nfs_realign(recm, 10 * NFSX_UNSIGNED); - if (slp->ns_recend) - slp->ns_recend->m_nextpkt = recm; - else - slp->ns_rec = recm; - slp->ns_recend = recm; + + /* + * Accumulate the fragments into a record. + */ + mpp = &slp->ns_frag; + while (*mpp) + mpp = &((*mpp)->m_next); + *mpp = recm; + if (slp->ns_flag & SLP_LASTFRAG) { + nfs_realign(slp->ns_frag, 10 * NFSX_UNSIGNED); + if (slp->ns_recend) + slp->ns_recend->m_nextpkt = slp->ns_frag; + else + slp->ns_rec = slp->ns_frag; + slp->ns_recend = slp->ns_frag; + slp->ns_frag = (struct mbuf *)0; + } } } @@ -1920,36 +2095,47 @@ nfsrv_getstream(slp, waitflag) * Parse an RPC header. */ int -nfsrv_dorec(slp, nd) +nfsrv_dorec(slp, nfsd, ndp) register struct nfssvc_sock *slp; - register struct nfsd *nd; + struct nfsd *nfsd; + struct nfsrv_descript **ndp; { - register struct mbuf *m; + register struct mbuf *m, *nam; + register struct nfsrv_descript *nd; int error; + *ndp = NULL; if ((slp->ns_flag & SLP_VALID) == 0 || (m = slp->ns_rec) == (struct mbuf *)0) return (ENOBUFS); - if ((slp->ns_rec = m->m_nextpkt) != NULL) + slp->ns_rec = m->m_nextpkt; + if (slp->ns_rec) m->m_nextpkt = (struct mbuf *)0; else slp->ns_recend = (struct mbuf *)0; if (m->m_type == MT_SONAME) { - nd->nd_nam = m; - nd->nd_md = nd->nd_mrep = m->m_next; - m->m_next = (struct mbuf *)0; - } else { - nd->nd_nam = (struct mbuf *)0; - nd->nd_md = nd->nd_mrep = m; - } - nd->nd_dpos = mtod(nd->nd_md, caddr_t); - if ((error = nfs_getreq(nd, TRUE)) != 0) { - m_freem(nd->nd_nam); + nam = m; + m = m->m_next; + nam->m_next = NULL; + } else + nam = NULL; + MALLOC(nd, struct nfsrv_descript *, sizeof (struct nfsrv_descript), + M_NFSRVDESC, M_WAITOK); + nd->nd_md = nd->nd_mrep = m; + nd->nd_nam2 = nam; + nd->nd_dpos = mtod(m, caddr_t); + error = nfs_getreq(nd, nfsd, TRUE); + if (error) { + m_freem(nam); + free((caddr_t)nd, M_NFSRVDESC); return (error); } + *ndp = nd; + nfsd->nfsd_nd = nd; return (0); } + /* * Search for a sleeping nfsd and wake it up. * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the @@ -1963,13 +2149,13 @@ nfsrv_wakenfsd(slp) if ((slp->ns_flag & SLP_VALID) == 0) return; - for (nd = nfsd_head.tqh_first; nd != 0; nd = nd->nd_chain.tqe_next) { - if (nd->nd_flag & NFSD_WAITING) { - nd->nd_flag &= ~NFSD_WAITING; - if (nd->nd_slp) + for (nd = nfsd_head.tqh_first; nd != 0; nd = nd->nfsd_chain.tqe_next) { + if (nd->nfsd_flag & NFSD_WAITING) { + nd->nfsd_flag &= ~NFSD_WAITING; + if (nd->nfsd_slp) panic("nfsd wakeup"); slp->ns_sref++; - nd->nd_slp = slp; + nd->nfsd_slp = slp; wakeup((caddr_t)nd); return; } |