nfs_nfsiod.c revision 12274
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley by 61541Srgrimes * Rick Macklem at The University of Guelph. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 3. All advertising materials mentioning features or use of this software 171541Srgrimes * must display the following acknowledgement: 181541Srgrimes * This product includes software developed by the University of 191541Srgrimes * California, Berkeley and its contributors. 201541Srgrimes * 4. Neither the name of the University nor the names of its contributors 211541Srgrimes * may be used to endorse or promote products derived from this software 221541Srgrimes * without specific prior written permission. 231541Srgrimes * 241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341541Srgrimes * SUCH DAMAGE. 351541Srgrimes * 361541Srgrimes * @(#)nfs_syscalls.c 8.3 (Berkeley) 1/4/94 3712274Sbde * $Id: nfs_syscalls.c,v 1.8 1995/10/29 15:33:11 phk Exp $ 381541Srgrimes */ 391541Srgrimes 401541Srgrimes#include <sys/param.h> 411541Srgrimes#include <sys/systm.h> 4212274Sbde#include <sys/sysproto.h> 431541Srgrimes#include <sys/kernel.h> 441541Srgrimes#include <sys/file.h> 451541Srgrimes#include <sys/stat.h> 461541Srgrimes#include <sys/vnode.h> 471541Srgrimes#include <sys/mount.h> 481541Srgrimes#include <sys/proc.h> 491541Srgrimes#include <sys/uio.h> 501541Srgrimes#include <sys/malloc.h> 511541Srgrimes#include <sys/buf.h> 521541Srgrimes#include <sys/mbuf.h> 531541Srgrimes#include <sys/socket.h> 541541Srgrimes#include <sys/socketvar.h> 551541Srgrimes#include <sys/domain.h> 561541Srgrimes#include <sys/protosw.h> 571541Srgrimes#include <sys/namei.h> 581541Srgrimes#include <sys/syslog.h> 591541Srgrimes 601541Srgrimes#include <netinet/in.h> 611541Srgrimes#include <netinet/tcp.h> 621541Srgrimes#ifdef ISO 631541Srgrimes#include <netiso/iso.h> 641541Srgrimes#endif 659336Sdfr#include <nfs/xdr_subs.h> 661541Srgrimes#include <nfs/rpcv2.h> 679336Sdfr#include <nfs/nfsproto.h> 681541Srgrimes#include <nfs/nfs.h> 699336Sdfr#include <nfs/nfsm_subs.h> 701541Srgrimes#include <nfs/nfsrvcache.h> 711541Srgrimes#include <nfs/nfsmount.h> 721541Srgrimes#include <nfs/nfsnode.h> 731541Srgrimes#include <nfs/nqnfs.h> 741541Srgrimes#include <nfs/nfsrtt.h> 751541Srgrimes 761549Srgrimesvoid nfsrv_zapsock __P((struct nfssvc_sock *)); 771549Srgrimes 781541Srgrimes/* Global defs. */ 799336Sdfrextern int (*nfsrv3_procs[NFS_NPROCS])(); 801541Srgrimesextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 811541Srgrimesextern int nfs_numasync; 821541Srgrimesextern time_t nqnfsstarttime; 831541Srgrimesextern int nqsrv_writeslack; 841541Srgrimesextern int nfsrtton; 859336Sdfrextern struct nfsstats nfsstats; 869336Sdfrextern int nfsrvw_procrastinate; 871541Srgrimesstruct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; 881541Srgrimesint nuidhash_max = NFS_MAXUIDHASH; 891541Srgrimesstatic int nfs_numnfsd = 0; 901541Srgrimesint nfsd_waiting = 0; 911541Srgrimesstatic int notstarted = 1; 921541Srgrimesstatic int modify_flag = 0; 931541Srgrimesstatic struct nfsdrt nfsdrt; 941541Srgrimesvoid nfsrv_cleancache(), nfsrv_rcv(), nfsrv_wakenfsd(), nfs_sndunlock(); 951541Srgrimesstatic void nfsd_rt(); 963664Sphkvoid nfsrv_slpderef(); 971541Srgrimes 981541Srgrimes#define TRUE 1 991541Srgrimes#define FALSE 0 1001541Srgrimes 1011541Srgrimesstatic int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 1021541Srgrimes/* 1031541Srgrimes * NFS server system calls 1041541Srgrimes * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 1051541Srgrimes */ 1061541Srgrimes 1071541Srgrimes/* 1081541Srgrimes * Get file handle system call 1091541Srgrimes */ 11012274Sbde#ifndef _SYS_SYSPROTO_H_ 1111541Srgrimesstruct getfh_args { 1121541Srgrimes char *fname; 1131541Srgrimes fhandle_t *fhp; 1141541Srgrimes}; 11512274Sbde#endif 1161549Srgrimesint 1171541Srgrimesgetfh(p, uap, retval) 1181541Srgrimes struct proc *p; 1191541Srgrimes register struct getfh_args *uap; 1201541Srgrimes int *retval; 1211541Srgrimes{ 1221541Srgrimes register struct vnode *vp; 1231541Srgrimes fhandle_t fh; 1241541Srgrimes int error; 1251541Srgrimes struct nameidata nd; 1261541Srgrimes 1271541Srgrimes /* 1281541Srgrimes * Must be super user 1291541Srgrimes */ 1303305Sphk error = suser(p->p_ucred, &p->p_acflag); 1313305Sphk if(error) 1321541Srgrimes return (error); 1331541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 1343305Sphk error = namei(&nd); 1353305Sphk if (error) 1361541Srgrimes return (error); 1371541Srgrimes vp = nd.ni_vp; 1381541Srgrimes bzero((caddr_t)&fh, sizeof(fh)); 1391541Srgrimes fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1401541Srgrimes error = VFS_VPTOFH(vp, &fh.fh_fid); 1411541Srgrimes vput(vp); 1421541Srgrimes if (error) 1431541Srgrimes return (error); 1441541Srgrimes error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 1451541Srgrimes return (error); 1461541Srgrimes} 1471541Srgrimes 1481541Srgrimes/* 1491541Srgrimes * Nfs server psuedo system call for the nfsd's 1501541Srgrimes * Based on the flag value it either: 1511541Srgrimes * - adds a socket to the selection list 1521541Srgrimes * - remains in the kernel as an nfsd 1531541Srgrimes * - remains in the kernel as an nfsiod 1541541Srgrimes */ 15512274Sbde#ifndef _SYS_SYSPROTO_H_ 1561541Srgrimesstruct nfssvc_args { 1571541Srgrimes int flag; 1581541Srgrimes caddr_t argp; 1591541Srgrimes}; 16012274Sbde#endif 1611549Srgrimesint 1621541Srgrimesnfssvc(p, uap, retval) 1631541Srgrimes struct proc *p; 1641541Srgrimes register struct nfssvc_args *uap; 1651541Srgrimes int *retval; 1661541Srgrimes{ 1671541Srgrimes struct nameidata nd; 1681541Srgrimes struct file *fp; 1691541Srgrimes struct mbuf *nam; 1701541Srgrimes struct nfsd_args nfsdarg; 1711541Srgrimes struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; 1721541Srgrimes struct nfsd_cargs ncd; 1731541Srgrimes struct nfsd *nfsd; 1741541Srgrimes struct nfssvc_sock *slp; 1753664Sphk struct nfsuid *nuidp; 1761541Srgrimes struct nfsmount *nmp; 1771541Srgrimes int error; 1781541Srgrimes 1791541Srgrimes /* 1801541Srgrimes * Must be super user 1811541Srgrimes */ 1823305Sphk error = suser(p->p_ucred, &p->p_acflag); 1833305Sphk if(error) 1841541Srgrimes return (error); 1853664Sphk while (nfssvc_sockhead_flag & SLP_INIT) { 1863664Sphk nfssvc_sockhead_flag |= SLP_WANTINIT; 1871541Srgrimes (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); 1881541Srgrimes } 1891541Srgrimes if (uap->flag & NFSSVC_BIOD) 1901541Srgrimes error = nfssvc_iod(p); 1911541Srgrimes else if (uap->flag & NFSSVC_MNTD) { 1923305Sphk error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); 1933305Sphk if (error) 1941541Srgrimes return (error); 1951541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1961541Srgrimes ncd.ncd_dirp, p); 1973305Sphk error = namei(&nd); 1983305Sphk if (error) 1991541Srgrimes return (error); 2001541Srgrimes if ((nd.ni_vp->v_flag & VROOT) == 0) 2011541Srgrimes error = EINVAL; 2021541Srgrimes nmp = VFSTONFS(nd.ni_vp->v_mount); 2031541Srgrimes vput(nd.ni_vp); 2041541Srgrimes if (error) 2051541Srgrimes return (error); 2061541Srgrimes if ((nmp->nm_flag & NFSMNT_MNTD) && 2071541Srgrimes (uap->flag & NFSSVC_GOTAUTH) == 0) 2081541Srgrimes return (0); 2091541Srgrimes nmp->nm_flag |= NFSMNT_MNTD; 2101541Srgrimes error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, 2111541Srgrimes uap->argp, p); 2121541Srgrimes } else if (uap->flag & NFSSVC_ADDSOCK) { 2133305Sphk error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); 2143305Sphk if (error) 2151541Srgrimes return (error); 2163305Sphk error = getsock(p->p_fd, nfsdarg.sock, &fp); 2173305Sphk if (error) 2181541Srgrimes return (error); 2191541Srgrimes /* 2201541Srgrimes * Get the client address for connected sockets. 2211541Srgrimes */ 2221541Srgrimes if (nfsdarg.name == NULL || nfsdarg.namelen == 0) 2231541Srgrimes nam = (struct mbuf *)0; 2243305Sphk else { 2253305Sphk error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, 2263305Sphk MT_SONAME); 2273305Sphk if (error) 2283305Sphk return (error); 2293305Sphk } 2301541Srgrimes error = nfssvc_addsock(fp, nam); 2311541Srgrimes } else { 2323305Sphk error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); 2333305Sphk if (error) 2341541Srgrimes return (error); 2353305Sphk if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) && 2369336Sdfr (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { 2379336Sdfr slp = nfsd->nfsd_slp; 2381541Srgrimes 2391541Srgrimes /* 2401541Srgrimes * First check to see if another nfsd has already 2411541Srgrimes * added this credential. 2421541Srgrimes */ 2439336Sdfr for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; 2443664Sphk nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 2459336Sdfr if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid && 2469336Sdfr (!nfsd->nfsd_nd->nd_nam2 || 2479336Sdfr netaddr_match(NU_NETFAM(nuidp), 2489336Sdfr &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) 2491541Srgrimes break; 2501541Srgrimes } 2519336Sdfr if (nuidp) { 2529336Sdfr nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr); 2539336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 2549336Sdfr } else { 2551541Srgrimes /* 2561541Srgrimes * Nope, so we will. 2571541Srgrimes */ 2581541Srgrimes if (slp->ns_numuids < nuidhash_max) { 2591541Srgrimes slp->ns_numuids++; 2601541Srgrimes nuidp = (struct nfsuid *) 2611541Srgrimes malloc(sizeof (struct nfsuid), M_NFSUID, 2621541Srgrimes M_WAITOK); 2631541Srgrimes } else 2641541Srgrimes nuidp = (struct nfsuid *)0; 2651541Srgrimes if ((slp->ns_flag & SLP_VALID) == 0) { 2661541Srgrimes if (nuidp) 2671541Srgrimes free((caddr_t)nuidp, M_NFSUID); 2681541Srgrimes } else { 2691541Srgrimes if (nuidp == (struct nfsuid *)0) { 2703664Sphk nuidp = slp->ns_uidlruhead.tqh_first; 2713664Sphk LIST_REMOVE(nuidp, nu_hash); 2723664Sphk TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, 2733664Sphk nu_lru); 2749336Sdfr if (nuidp->nu_flag & NU_NAM) 2759336Sdfr m_freem(nuidp->nu_nam); 2761541Srgrimes } 2779336Sdfr nuidp->nu_flag = 0; 2781541Srgrimes nuidp->nu_cr = nsd->nsd_cr; 2791541Srgrimes if (nuidp->nu_cr.cr_ngroups > NGROUPS) 2809336Sdfr nuidp->nu_cr.cr_ngroups = NGROUPS; 2811541Srgrimes nuidp->nu_cr.cr_ref = 1; 2829336Sdfr nuidp->nu_timestamp = nsd->nsd_timestamp; 2839336Sdfr nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl; 2849336Sdfr /* 2859336Sdfr * and save the session key in nu_key. 2869336Sdfr */ 2879336Sdfr bcopy(nsd->nsd_key, nuidp->nu_key, 2889336Sdfr sizeof (nsd->nsd_key)); 2899336Sdfr if (nfsd->nfsd_nd->nd_nam2) { 2909336Sdfr struct sockaddr_in *saddr; 2919336Sdfr 2929336Sdfr saddr = mtod(nfsd->nfsd_nd->nd_nam2, 2939336Sdfr struct sockaddr_in *); 2949336Sdfr switch (saddr->sin_family) { 2959336Sdfr case AF_INET: 2969336Sdfr nuidp->nu_flag |= NU_INETADDR; 2979336Sdfr nuidp->nu_inetaddr = 2989336Sdfr saddr->sin_addr.s_addr; 2999336Sdfr break; 3009336Sdfr case AF_ISO: 3019336Sdfr default: 3029336Sdfr nuidp->nu_flag |= NU_NAM; 3039336Sdfr nuidp->nu_nam = m_copym( 3049336Sdfr nfsd->nfsd_nd->nd_nam2, 0, 3059336Sdfr M_COPYALL, M_WAIT); 3069336Sdfr break; 3079336Sdfr }; 3089336Sdfr } 3093664Sphk TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, 3103664Sphk nu_lru); 3113664Sphk LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), 3123664Sphk nuidp, nu_hash); 3139336Sdfr nfsrv_setcred(&nuidp->nu_cr, 3149336Sdfr &nfsd->nfsd_nd->nd_cr); 3159336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 3161541Srgrimes } 3171541Srgrimes } 3181541Srgrimes } 3191541Srgrimes if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) 3209336Sdfr nfsd->nfsd_flag |= NFSD_AUTHFAIL; 3211541Srgrimes error = nfssvc_nfsd(nsd, uap->argp, p); 3221541Srgrimes } 3231541Srgrimes if (error == EINTR || error == ERESTART) 3241541Srgrimes error = 0; 3251541Srgrimes return (error); 3261541Srgrimes} 3271541Srgrimes 3281541Srgrimes/* 3291541Srgrimes * Adds a socket to the list for servicing by nfsds. 3301541Srgrimes */ 3311549Srgrimesint 3321541Srgrimesnfssvc_addsock(fp, mynam) 3331541Srgrimes struct file *fp; 3341541Srgrimes struct mbuf *mynam; 3351541Srgrimes{ 3361541Srgrimes register struct mbuf *m; 3371541Srgrimes register int siz; 3381541Srgrimes register struct nfssvc_sock *slp; 3391541Srgrimes register struct socket *so; 3401541Srgrimes struct nfssvc_sock *tslp; 3411541Srgrimes int error, s; 3421541Srgrimes 3431541Srgrimes so = (struct socket *)fp->f_data; 3441541Srgrimes tslp = (struct nfssvc_sock *)0; 3451541Srgrimes /* 3461541Srgrimes * Add it to the list, as required. 3471541Srgrimes */ 3481541Srgrimes if (so->so_proto->pr_protocol == IPPROTO_UDP) { 3491541Srgrimes tslp = nfs_udpsock; 3501541Srgrimes if (tslp->ns_flag & SLP_VALID) { 3511541Srgrimes m_freem(mynam); 3521541Srgrimes return (EPERM); 3531541Srgrimes } 3541541Srgrimes#ifdef ISO 3551541Srgrimes } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) { 3561541Srgrimes tslp = nfs_cltpsock; 3571541Srgrimes if (tslp->ns_flag & SLP_VALID) { 3581541Srgrimes m_freem(mynam); 3591541Srgrimes return (EPERM); 3601541Srgrimes } 3611541Srgrimes#endif /* ISO */ 3621541Srgrimes } 3631541Srgrimes if (so->so_type == SOCK_STREAM) 3641541Srgrimes siz = NFS_MAXPACKET + sizeof (u_long); 3651541Srgrimes else 3661541Srgrimes siz = NFS_MAXPACKET; 3678876Srgrimes error = soreserve(so, siz, siz); 3683305Sphk if (error) { 3691541Srgrimes m_freem(mynam); 3701541Srgrimes return (error); 3711541Srgrimes } 3721541Srgrimes 3731541Srgrimes /* 3741541Srgrimes * Set protocol specific options { for now TCP only } and 3751541Srgrimes * reserve some space. For datagram sockets, this can get called 3761541Srgrimes * repeatedly for the same socket, but that isn't harmful. 3771541Srgrimes */ 3781541Srgrimes if (so->so_type == SOCK_STREAM) { 3791541Srgrimes MGET(m, M_WAIT, MT_SOOPTS); 3801541Srgrimes *mtod(m, int *) = 1; 3811541Srgrimes m->m_len = sizeof(int); 3821541Srgrimes sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 3831541Srgrimes } 3841541Srgrimes if (so->so_proto->pr_domain->dom_family == AF_INET && 3851541Srgrimes so->so_proto->pr_protocol == IPPROTO_TCP) { 3861541Srgrimes MGET(m, M_WAIT, MT_SOOPTS); 3871541Srgrimes *mtod(m, int *) = 1; 3881541Srgrimes m->m_len = sizeof(int); 3891541Srgrimes sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 3901541Srgrimes } 3911541Srgrimes so->so_rcv.sb_flags &= ~SB_NOINTR; 3921541Srgrimes so->so_rcv.sb_timeo = 0; 3931541Srgrimes so->so_snd.sb_flags &= ~SB_NOINTR; 3941541Srgrimes so->so_snd.sb_timeo = 0; 3951541Srgrimes if (tslp) 3961541Srgrimes slp = tslp; 3971541Srgrimes else { 3981541Srgrimes slp = (struct nfssvc_sock *) 3991541Srgrimes malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 4001541Srgrimes bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); 4013664Sphk TAILQ_INIT(&slp->ns_uidlruhead); 4023664Sphk TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); 4031541Srgrimes } 4041541Srgrimes slp->ns_so = so; 4051541Srgrimes slp->ns_nam = mynam; 4061541Srgrimes fp->f_count++; 4071541Srgrimes slp->ns_fp = fp; 4081541Srgrimes s = splnet(); 4091541Srgrimes so->so_upcallarg = (caddr_t)slp; 4101541Srgrimes so->so_upcall = nfsrv_rcv; 4111541Srgrimes slp->ns_flag = (SLP_VALID | SLP_NEEDQ); 4121541Srgrimes nfsrv_wakenfsd(slp); 4131541Srgrimes splx(s); 4141541Srgrimes return (0); 4151541Srgrimes} 4161541Srgrimes 4171541Srgrimes/* 4181541Srgrimes * Called by nfssvc() for nfsds. Just loops around servicing rpc requests 4191541Srgrimes * until it is killed by a signal. 4201541Srgrimes */ 4211549Srgrimesint 4221541Srgrimesnfssvc_nfsd(nsd, argp, p) 4231541Srgrimes struct nfsd_srvargs *nsd; 4241541Srgrimes caddr_t argp; 4251541Srgrimes struct proc *p; 4261541Srgrimes{ 4279336Sdfr register struct mbuf *m; 4281541Srgrimes register int siz; 4291541Srgrimes register struct nfssvc_sock *slp; 4301541Srgrimes register struct socket *so; 4311541Srgrimes register int *solockp; 4329336Sdfr struct nfsd *nfsd = nsd->nsd_nfsd; 4339336Sdfr struct nfsrv_descript *nd = NULL; 4349336Sdfr struct mbuf *mreq; 4359336Sdfr int error = 0, cacherep, s, sotype, writes_todo; 4369336Sdfr u_quad_t cur_usec; 4371541Srgrimes 4389336Sdfr#ifndef nolint 4399336Sdfr cacherep = RC_DOIT; 4409336Sdfr writes_todo = 0; 4419336Sdfr#endif 4421541Srgrimes s = splnet(); 4439336Sdfr if (nfsd == (struct nfsd *)0) { 4449336Sdfr nsd->nsd_nfsd = nfsd = (struct nfsd *) 4451541Srgrimes malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK); 4469336Sdfr bzero((caddr_t)nfsd, sizeof (struct nfsd)); 4479336Sdfr nfsd->nfsd_procp = p; 4489336Sdfr TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); 4491541Srgrimes nfs_numnfsd++; 4501541Srgrimes } 4511541Srgrimes /* 4521541Srgrimes * Loop getting rpc requests until SIGKILL. 4531541Srgrimes */ 4541541Srgrimes for (;;) { 4559336Sdfr if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { 4569336Sdfr while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 4573664Sphk (nfsd_head_flag & NFSD_CHECKSLP) == 0) { 4589336Sdfr nfsd->nfsd_flag |= NFSD_WAITING; 4591541Srgrimes nfsd_waiting++; 4609336Sdfr error = tsleep((caddr_t)nfsd, PSOCK | PCATCH, 4619336Sdfr "nfsd", 0); 4621541Srgrimes nfsd_waiting--; 4631541Srgrimes if (error) 4641541Srgrimes goto done; 4651541Srgrimes } 4669336Sdfr if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 4673664Sphk (nfsd_head_flag & NFSD_CHECKSLP) != 0) { 4683664Sphk for (slp = nfssvc_sockhead.tqh_first; slp != 0; 4693664Sphk slp = slp->ns_chain.tqe_next) { 4701541Srgrimes if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) 4711541Srgrimes == (SLP_VALID | SLP_DOREC)) { 4721541Srgrimes slp->ns_flag &= ~SLP_DOREC; 4731541Srgrimes slp->ns_sref++; 4749336Sdfr nfsd->nfsd_slp = slp; 4751541Srgrimes break; 4761541Srgrimes } 4771541Srgrimes } 4783664Sphk if (slp == 0) 4793664Sphk nfsd_head_flag &= ~NFSD_CHECKSLP; 4801541Srgrimes } 4819336Sdfr if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0) 4821541Srgrimes continue; 4831541Srgrimes if (slp->ns_flag & SLP_VALID) { 4841541Srgrimes if (slp->ns_flag & SLP_DISCONN) 4851541Srgrimes nfsrv_zapsock(slp); 4861541Srgrimes else if (slp->ns_flag & SLP_NEEDQ) { 4871541Srgrimes slp->ns_flag &= ~SLP_NEEDQ; 4881541Srgrimes (void) nfs_sndlock(&slp->ns_solock, 4891541Srgrimes (struct nfsreq *)0); 4901541Srgrimes nfsrv_rcv(slp->ns_so, (caddr_t)slp, 4911541Srgrimes M_WAIT); 4921541Srgrimes nfs_sndunlock(&slp->ns_solock); 4931541Srgrimes } 4949336Sdfr error = nfsrv_dorec(slp, nfsd, &nd); 4959336Sdfr cur_usec = (u_quad_t)time.tv_sec * 1000000 + 4969336Sdfr (u_quad_t)time.tv_usec; 4979336Sdfr if (error && slp->ns_tq.lh_first && 4989336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 4999336Sdfr error = 0; 5009336Sdfr cacherep = RC_DOIT; 5019336Sdfr writes_todo = 1; 5029336Sdfr } else 5039336Sdfr writes_todo = 0; 5049336Sdfr nfsd->nfsd_flag |= NFSD_REQINPROG; 5051541Srgrimes } 5061541Srgrimes } else { 5071541Srgrimes error = 0; 5089336Sdfr slp = nfsd->nfsd_slp; 5091541Srgrimes } 5101541Srgrimes if (error || (slp->ns_flag & SLP_VALID) == 0) { 5119336Sdfr if (nd) { 5129336Sdfr free((caddr_t)nd, M_NFSRVDESC); 5139336Sdfr nd = NULL; 5149336Sdfr } 5159336Sdfr nfsd->nfsd_slp = (struct nfssvc_sock *)0; 5169336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 5171541Srgrimes nfsrv_slpderef(slp); 5181541Srgrimes continue; 5191541Srgrimes } 5201541Srgrimes splx(s); 5211541Srgrimes so = slp->ns_so; 5221541Srgrimes sotype = so->so_type; 5231541Srgrimes if (so->so_proto->pr_flags & PR_CONNREQUIRED) 5241541Srgrimes solockp = &slp->ns_solock; 5251541Srgrimes else 5261541Srgrimes solockp = (int *)0; 5279336Sdfr if (nd) { 5289336Sdfr nd->nd_starttime = time; 5299336Sdfr if (nd->nd_nam2) 5309336Sdfr nd->nd_nam = nd->nd_nam2; 5319336Sdfr else 5329336Sdfr nd->nd_nam = slp->ns_nam; 5331541Srgrimes 5349336Sdfr /* 5359336Sdfr * Check to see if authorization is needed. 5369336Sdfr */ 5379336Sdfr if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { 5389336Sdfr nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; 5399336Sdfr nsd->nsd_haddr = mtod(nd->nd_nam, 5409336Sdfr struct sockaddr_in *)->sin_addr.s_addr; 5419336Sdfr nsd->nsd_authlen = nfsd->nfsd_authlen; 5429336Sdfr nsd->nsd_verflen = nfsd->nfsd_verflen; 5439336Sdfr if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr, 5449336Sdfr nfsd->nfsd_authlen) && 5459336Sdfr !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr, 5469336Sdfr nfsd->nfsd_verflen) && 5479336Sdfr !copyout((caddr_t)nsd, argp, sizeof (*nsd))) 5489336Sdfr return (ENEEDAUTH); 5499336Sdfr cacherep = RC_DROPIT; 5509336Sdfr } else 5519336Sdfr cacherep = nfsrv_getcache(nd, slp, &mreq); 5521541Srgrimes 5539336Sdfr /* 5549336Sdfr * Check for just starting up for NQNFS and send 5559336Sdfr * fake "try again later" replies to the NQNFS clients. 5569336Sdfr */ 5579336Sdfr if (notstarted && nqnfsstarttime <= time.tv_sec) { 5581541Srgrimes if (modify_flag) { 5591541Srgrimes nqnfsstarttime = time.tv_sec + nqsrv_writeslack; 5601541Srgrimes modify_flag = 0; 5611541Srgrimes } else 5621541Srgrimes notstarted = 0; 5639336Sdfr } 5649336Sdfr if (notstarted) { 5659336Sdfr if ((nd->nd_flag & ND_NQNFS) == 0) 5661541Srgrimes cacherep = RC_DROPIT; 5671541Srgrimes else if (nd->nd_procnum != NFSPROC_WRITE) { 5681541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 5691541Srgrimes nd->nd_repstat = NQNFS_TRYLATER; 5701541Srgrimes cacherep = RC_DOIT; 5711541Srgrimes } else 5721541Srgrimes modify_flag = 1; 5739336Sdfr } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { 5749336Sdfr nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; 5751541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 5769336Sdfr nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 5771541Srgrimes cacherep = RC_DOIT; 5789336Sdfr } 5791541Srgrimes } 5801541Srgrimes 5819336Sdfr /* 5829336Sdfr * Loop to get all the write rpc relies that have been 5839336Sdfr * gathered together. 5849336Sdfr */ 5859336Sdfr do { 5869336Sdfr switch (cacherep) { 5879336Sdfr case RC_DOIT: 5889336Sdfr if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && 5899336Sdfr nfsrvw_procrastinate > 0 && !notstarted)) 5909336Sdfr error = nfsrv_writegather(&nd, slp, 5919336Sdfr nfsd->nfsd_procp, &mreq); 5929336Sdfr else 5939336Sdfr error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, 5949336Sdfr slp, nfsd->nfsd_procp, &mreq); 5959336Sdfr if (mreq == NULL) 5969336Sdfr break; 5971541Srgrimes if (error) { 5981541Srgrimes if (nd->nd_procnum != NQNFSPROC_VACATED) 5991541Srgrimes nfsstats.srv_errs++; 6009336Sdfr nfsrv_updatecache(nd, FALSE, mreq); 6019336Sdfr if (nd->nd_nam2) 6029336Sdfr m_freem(nd->nd_nam2); 6031541Srgrimes break; 6041541Srgrimes } 6051541Srgrimes nfsstats.srvrpccnt[nd->nd_procnum]++; 6069336Sdfr nfsrv_updatecache(nd, TRUE, mreq); 6071541Srgrimes nd->nd_mrep = (struct mbuf *)0; 6089336Sdfr case RC_REPLY: 6091541Srgrimes m = mreq; 6101541Srgrimes siz = 0; 6111541Srgrimes while (m) { 6121541Srgrimes siz += m->m_len; 6131541Srgrimes m = m->m_next; 6141541Srgrimes } 6151541Srgrimes if (siz <= 0 || siz > NFS_MAXPACKET) { 6161541Srgrimes printf("mbuf siz=%d\n",siz); 6171541Srgrimes panic("Bad nfs svc reply"); 6181541Srgrimes } 6191541Srgrimes m = mreq; 6201541Srgrimes m->m_pkthdr.len = siz; 6211541Srgrimes m->m_pkthdr.rcvif = (struct ifnet *)0; 6221541Srgrimes /* 6231541Srgrimes * For stream protocols, prepend a Sun RPC 6241541Srgrimes * Record Mark. 6251541Srgrimes */ 6261541Srgrimes if (sotype == SOCK_STREAM) { 6271541Srgrimes M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 6281541Srgrimes *mtod(m, u_long *) = htonl(0x80000000 | siz); 6291541Srgrimes } 6301541Srgrimes if (solockp) 6311541Srgrimes (void) nfs_sndlock(solockp, (struct nfsreq *)0); 6321541Srgrimes if (slp->ns_flag & SLP_VALID) 6339336Sdfr error = nfs_send(so, nd->nd_nam2, m, NULL); 6341541Srgrimes else { 6351541Srgrimes error = EPIPE; 6361541Srgrimes m_freem(m); 6371541Srgrimes } 6381541Srgrimes if (nfsrtton) 6399336Sdfr nfsd_rt(sotype, nd, cacherep); 6409336Sdfr if (nd->nd_nam2) 6419336Sdfr MFREE(nd->nd_nam2, m); 6421541Srgrimes if (nd->nd_mrep) 6431541Srgrimes m_freem(nd->nd_mrep); 6441541Srgrimes if (error == EPIPE) 6451541Srgrimes nfsrv_zapsock(slp); 6461541Srgrimes if (solockp) 6471541Srgrimes nfs_sndunlock(solockp); 6481541Srgrimes if (error == EINTR || error == ERESTART) { 6499336Sdfr free((caddr_t)nd, M_NFSRVDESC); 6501541Srgrimes nfsrv_slpderef(slp); 6511541Srgrimes s = splnet(); 6521541Srgrimes goto done; 6531541Srgrimes } 6541541Srgrimes break; 6559336Sdfr case RC_DROPIT: 6561541Srgrimes if (nfsrtton) 6579336Sdfr nfsd_rt(sotype, nd, cacherep); 6581541Srgrimes m_freem(nd->nd_mrep); 6599336Sdfr m_freem(nd->nd_nam2); 6601541Srgrimes break; 6619336Sdfr }; 6629336Sdfr if (nd) { 6639336Sdfr FREE((caddr_t)nd, M_NFSRVDESC); 6649336Sdfr nd = NULL; 6659336Sdfr } 6669336Sdfr 6679336Sdfr /* 6689336Sdfr * Check to see if there are outstanding writes that 6699336Sdfr * need to be serviced. 6709336Sdfr */ 6719336Sdfr cur_usec = (u_quad_t)time.tv_sec * 1000000 + 6729336Sdfr (u_quad_t)time.tv_usec; 6739336Sdfr s = splsoftclock(); 6749336Sdfr if (slp->ns_tq.lh_first && 6759336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 6769336Sdfr cacherep = RC_DOIT; 6779336Sdfr writes_todo = 1; 6789336Sdfr } else 6799336Sdfr writes_todo = 0; 6809336Sdfr splx(s); 6819336Sdfr } while (writes_todo); 6821541Srgrimes s = splnet(); 6839336Sdfr if (nfsrv_dorec(slp, nfsd, &nd)) { 6849336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 6859336Sdfr nfsd->nfsd_slp = NULL; 6861541Srgrimes nfsrv_slpderef(slp); 6871541Srgrimes } 6881541Srgrimes } 6891541Srgrimesdone: 6909336Sdfr TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); 6911541Srgrimes splx(s); 6929336Sdfr free((caddr_t)nfsd, M_NFSD); 6931541Srgrimes nsd->nsd_nfsd = (struct nfsd *)0; 6941541Srgrimes if (--nfs_numnfsd == 0) 6951541Srgrimes nfsrv_init(TRUE); /* Reinitialize everything */ 6961541Srgrimes return (error); 6971541Srgrimes} 6981541Srgrimes 6991541Srgrimes/* 7001541Srgrimes * Asynchronous I/O daemons for client nfs. 7011541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache. 7021541Srgrimes * Never returns unless it fails or gets killed. 7031541Srgrimes */ 7041549Srgrimesint 7051541Srgrimesnfssvc_iod(p) 7061541Srgrimes struct proc *p; 7071541Srgrimes{ 7089336Sdfr register struct buf *bp, *nbp; 7091541Srgrimes register int i, myiod; 7109336Sdfr struct vnode *vp; 7119336Sdfr int error = 0, s; 7121541Srgrimes 7131541Srgrimes /* 7141541Srgrimes * Assign my position or return error if too many already running 7151541Srgrimes */ 7161541Srgrimes myiod = -1; 7171541Srgrimes for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 7181541Srgrimes if (nfs_asyncdaemon[i] == 0) { 7191541Srgrimes nfs_asyncdaemon[i]++; 7201541Srgrimes myiod = i; 7211541Srgrimes break; 7221541Srgrimes } 7231541Srgrimes if (myiod == -1) 7241541Srgrimes return (EBUSY); 7251541Srgrimes nfs_numasync++; 7261541Srgrimes /* 7271541Srgrimes * Just loop around doin our stuff until SIGKILL 7281541Srgrimes */ 7291541Srgrimes for (;;) { 7309336Sdfr while (nfs_bufq.tqh_first == NULL && error == 0) { 7319336Sdfr nfs_iodwant[myiod] = p; 7329336Sdfr error = tsleep((caddr_t)&nfs_iodwant[myiod], 7339336Sdfr PWAIT | PCATCH, "nfsidl", 0); 7349336Sdfr } 7359336Sdfr while ((bp = nfs_bufq.tqh_first) != NULL) { 7369336Sdfr /* Take one off the front of the list */ 7379336Sdfr TAILQ_REMOVE(&nfs_bufq, bp, b_freelist); 7389336Sdfr if (bp->b_flags & B_READ) 7399336Sdfr (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); 7409336Sdfr else do { 7419336Sdfr /* 7429336Sdfr * Look for a delayed write for the same vnode, so I can do 7439336Sdfr * it now. We must grab it before calling nfs_doio() to 7449336Sdfr * avoid any risk of the vnode getting vclean()'d while 7459336Sdfr * we are doing the write rpc. 7469336Sdfr */ 7479336Sdfr vp = bp->b_vp; 7489336Sdfr s = splbio(); 7499336Sdfr for (nbp = vp->v_dirtyblkhd.lh_first; nbp; 7509336Sdfr nbp = nbp->b_vnbufs.le_next) { 7519336Sdfr if ((nbp->b_flags & 7529336Sdfr (B_BUSY|B_DELWRI|B_NEEDCOMMIT|B_NOCACHE))!=B_DELWRI) 7539336Sdfr continue; 7549336Sdfr bremfree(nbp); 7559336Sdfr vfs_busy_pages(nbp, 1); 7569336Sdfr nbp->b_flags |= (B_BUSY|B_ASYNC); 7579336Sdfr break; 7589336Sdfr } 7599336Sdfr splx(s); 7609336Sdfr /* 7619336Sdfr * For the delayed write, do the first part of nfs_bwrite() 7629336Sdfr * up to, but not including nfs_strategy(). 7639336Sdfr */ 7649336Sdfr if (nbp) { 7659336Sdfr nbp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI); 7669336Sdfr reassignbuf(nbp, nbp->b_vp); 7679336Sdfr nbp->b_vp->v_numoutput++; 7689336Sdfr } 7699336Sdfr (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); 7709336Sdfr } while (bp = nbp); 7719336Sdfr } 7729336Sdfr if (error) { 7739336Sdfr nfs_asyncdaemon[myiod] = 0; 7749336Sdfr nfs_numasync--; 7759336Sdfr return (error); 7769336Sdfr } 7771541Srgrimes } 7781541Srgrimes} 7791541Srgrimes 7801541Srgrimes/* 7811541Srgrimes * Shut down a socket associated with an nfssvc_sock structure. 7821541Srgrimes * Should be called with the send lock set, if required. 7831541Srgrimes * The trick here is to increment the sref at the start, so that the nfsds 7841541Srgrimes * will stop using it and clear ns_flag at the end so that it will not be 7851541Srgrimes * reassigned during cleanup. 7861541Srgrimes */ 7871549Srgrimesvoid 7881541Srgrimesnfsrv_zapsock(slp) 7891541Srgrimes register struct nfssvc_sock *slp; 7901541Srgrimes{ 7913664Sphk register struct nfsuid *nuidp, *nnuidp; 7929336Sdfr register struct nfsrv_descript *nwp, *nnwp; 7931541Srgrimes struct socket *so; 7941541Srgrimes struct file *fp; 7951541Srgrimes struct mbuf *m; 7969336Sdfr int s; 7971541Srgrimes 7981541Srgrimes slp->ns_flag &= ~SLP_ALLFLAGS; 7993305Sphk fp = slp->ns_fp; 8003305Sphk if (fp) { 8011541Srgrimes slp->ns_fp = (struct file *)0; 8021541Srgrimes so = slp->ns_so; 8031541Srgrimes so->so_upcall = NULL; 8041541Srgrimes soshutdown(so, 2); 8051541Srgrimes closef(fp, (struct proc *)0); 8061541Srgrimes if (slp->ns_nam) 8071541Srgrimes MFREE(slp->ns_nam, m); 8081541Srgrimes m_freem(slp->ns_raw); 8091541Srgrimes m_freem(slp->ns_rec); 8103664Sphk for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; 8113664Sphk nuidp = nnuidp) { 8123664Sphk nnuidp = nuidp->nu_lru.tqe_next; 8133664Sphk LIST_REMOVE(nuidp, nu_hash); 8143664Sphk TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); 8159336Sdfr if (nuidp->nu_flag & NU_NAM) 8169336Sdfr m_freem(nuidp->nu_nam); 8173664Sphk free((caddr_t)nuidp, M_NFSUID); 8181541Srgrimes } 8199336Sdfr s = splsoftclock(); 8209336Sdfr for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { 8219336Sdfr nnwp = nwp->nd_tq.le_next; 8229336Sdfr LIST_REMOVE(nwp, nd_tq); 8239336Sdfr free((caddr_t)nwp, M_NFSRVDESC); 8249336Sdfr } 8259336Sdfr LIST_INIT(&slp->ns_tq); 8269336Sdfr splx(s); 8271541Srgrimes } 8281541Srgrimes} 8291541Srgrimes 8301541Srgrimes/* 8311541Srgrimes * Get an authorization string for the uid by having the mount_nfs sitting 8321541Srgrimes * on this mount point porpous out of the kernel and do it. 8331541Srgrimes */ 8341549Srgrimesint 8359336Sdfrnfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) 8361541Srgrimes register struct nfsmount *nmp; 8371541Srgrimes struct nfsreq *rep; 8381541Srgrimes struct ucred *cred; 8391541Srgrimes char **auth_str; 8401541Srgrimes int *auth_len; 8419336Sdfr char *verf_str; 8429336Sdfr int *verf_len; 8439336Sdfr NFSKERBKEY_T key; /* return session key */ 8441541Srgrimes{ 8451541Srgrimes int error = 0; 8461541Srgrimes 8471541Srgrimes while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) { 8481541Srgrimes nmp->nm_flag |= NFSMNT_WANTAUTH; 8491541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, 8501541Srgrimes "nfsauth1", 2 * hz); 8513305Sphk error = nfs_sigintr(nmp, rep, rep->r_procp); 8523305Sphk if (error) { 8531541Srgrimes nmp->nm_flag &= ~NFSMNT_WANTAUTH; 8541541Srgrimes return (error); 8551541Srgrimes } 8561541Srgrimes } 8571541Srgrimes nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH); 8581541Srgrimes nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); 8599336Sdfr nmp->nm_authlen = RPCAUTH_MAXSIZ; 8609336Sdfr nmp->nm_verfstr = verf_str; 8619336Sdfr nmp->nm_verflen = *verf_len; 8621541Srgrimes nmp->nm_authuid = cred->cr_uid; 8631541Srgrimes wakeup((caddr_t)&nmp->nm_authstr); 8641541Srgrimes 8651541Srgrimes /* 8661541Srgrimes * And wait for mount_nfs to do its stuff. 8671541Srgrimes */ 8681541Srgrimes while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) { 8691541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, 8701541Srgrimes "nfsauth2", 2 * hz); 8711541Srgrimes error = nfs_sigintr(nmp, rep, rep->r_procp); 8721541Srgrimes } 8731541Srgrimes if (nmp->nm_flag & NFSMNT_AUTHERR) { 8741541Srgrimes nmp->nm_flag &= ~NFSMNT_AUTHERR; 8751541Srgrimes error = EAUTH; 8761541Srgrimes } 8771541Srgrimes if (error) 8781541Srgrimes free((caddr_t)*auth_str, M_TEMP); 8791541Srgrimes else { 8801541Srgrimes *auth_len = nmp->nm_authlen; 8819336Sdfr *verf_len = nmp->nm_verflen; 8829336Sdfr bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); 8831541Srgrimes } 8841541Srgrimes nmp->nm_flag &= ~NFSMNT_HASAUTH; 8851541Srgrimes nmp->nm_flag |= NFSMNT_WAITAUTH; 8861541Srgrimes if (nmp->nm_flag & NFSMNT_WANTAUTH) { 8871541Srgrimes nmp->nm_flag &= ~NFSMNT_WANTAUTH; 8881541Srgrimes wakeup((caddr_t)&nmp->nm_authtype); 8891541Srgrimes } 8901541Srgrimes return (error); 8911541Srgrimes} 8921541Srgrimes 8931541Srgrimes/* 8949336Sdfr * Get a nickname authenticator and verifier. 8959336Sdfr */ 8969336Sdfrint 8979336Sdfrnfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len) 8989336Sdfr struct nfsmount *nmp; 8999336Sdfr struct ucred *cred; 9009336Sdfr char **auth_str; 9019336Sdfr int *auth_len; 9029336Sdfr char *verf_str; 9039336Sdfr int verf_len; 9049336Sdfr{ 9059336Sdfr register struct nfsuid *nuidp; 9069336Sdfr register u_long *nickp, *verfp; 9079336Sdfr struct timeval ktvin, ktvout; 9089336Sdfr 9099336Sdfr#ifdef DIAGNOSTIC 9109336Sdfr if (verf_len < (4 * NFSX_UNSIGNED)) 9119336Sdfr panic("nfs_getnickauth verf too small"); 9129336Sdfr#endif 9139336Sdfr for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first; 9149336Sdfr nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 9159336Sdfr if (nuidp->nu_cr.cr_uid == cred->cr_uid) 9169336Sdfr break; 9179336Sdfr } 9189336Sdfr if (!nuidp || nuidp->nu_expire < time.tv_sec) 9199336Sdfr return (EACCES); 9209336Sdfr 9219336Sdfr /* 9229336Sdfr * Move to the end of the lru list (end of lru == most recently used). 9239336Sdfr */ 9249336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); 9259336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); 9269336Sdfr 9279336Sdfr nickp = (u_long *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); 9289336Sdfr *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); 9299336Sdfr *nickp = txdr_unsigned(nuidp->nu_nickname); 9309336Sdfr *auth_str = (char *)nickp; 9319336Sdfr *auth_len = 2 * NFSX_UNSIGNED; 9329336Sdfr 9339336Sdfr /* 9349336Sdfr * Now we must encrypt the verifier and package it up. 9359336Sdfr */ 9369336Sdfr verfp = (u_long *)verf_str; 9379336Sdfr *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); 9389336Sdfr if (time.tv_sec > nuidp->nu_timestamp.tv_sec || 9399336Sdfr (time.tv_sec == nuidp->nu_timestamp.tv_sec && 9409336Sdfr time.tv_usec > nuidp->nu_timestamp.tv_usec)) 9419336Sdfr nuidp->nu_timestamp = time; 9429336Sdfr else 9439336Sdfr nuidp->nu_timestamp.tv_usec++; 9449336Sdfr ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); 9459336Sdfr ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); 9469336Sdfr 9479336Sdfr /* 9489336Sdfr * Now encrypt the timestamp verifier in ecb mode using the session 9499336Sdfr * key. 9509336Sdfr */ 9519336Sdfr#ifdef NFSKERB 9529336Sdfr XXX 9539336Sdfr#endif 9549336Sdfr 9559336Sdfr *verfp++ = ktvout.tv_sec; 9569336Sdfr *verfp++ = ktvout.tv_usec; 9579336Sdfr *verfp = 0; 9589336Sdfr return (0); 9599336Sdfr} 9609336Sdfr 9619336Sdfr/* 9629336Sdfr * Save the current nickname in a hash list entry on the mount point. 9639336Sdfr */ 9649336Sdfrint 9659336Sdfrnfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) 9669336Sdfr register struct nfsmount *nmp; 9679336Sdfr struct ucred *cred; 9689336Sdfr int len; 9699336Sdfr NFSKERBKEY_T key; 9709336Sdfr struct mbuf **mdp; 9719336Sdfr char **dposp; 9729336Sdfr struct mbuf *mrep; 9739336Sdfr{ 9749336Sdfr register struct nfsuid *nuidp; 9759336Sdfr register u_long *tl; 9769336Sdfr register long t1; 9779336Sdfr struct mbuf *md = *mdp; 9789336Sdfr struct timeval ktvin, ktvout; 9799336Sdfr u_long nick; 9809336Sdfr char *dpos = *dposp, *cp2; 9819336Sdfr int deltasec, error = 0; 9829336Sdfr 9839336Sdfr if (len == (3 * NFSX_UNSIGNED)) { 9849336Sdfr nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); 9859336Sdfr ktvin.tv_sec = *tl++; 9869336Sdfr ktvin.tv_usec = *tl++; 9879336Sdfr nick = fxdr_unsigned(u_long, *tl); 9889336Sdfr 9899336Sdfr /* 9909336Sdfr * Decrypt the timestamp in ecb mode. 9919336Sdfr */ 9929336Sdfr#ifdef NFSKERB 9939336Sdfr XXX 9949336Sdfr#endif 9959336Sdfr ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); 9969336Sdfr ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); 9979336Sdfr deltasec = time.tv_sec - ktvout.tv_sec; 9989336Sdfr if (deltasec < 0) 9999336Sdfr deltasec = -deltasec; 10009336Sdfr /* 10019336Sdfr * If ok, add it to the hash list for the mount point. 10029336Sdfr */ 10039336Sdfr if (deltasec <= NFS_KERBCLOCKSKEW) { 10049336Sdfr if (nmp->nm_numuids < nuidhash_max) { 10059336Sdfr nmp->nm_numuids++; 10069336Sdfr nuidp = (struct nfsuid *) 10079336Sdfr malloc(sizeof (struct nfsuid), M_NFSUID, 10089336Sdfr M_WAITOK); 10099336Sdfr } else { 10109336Sdfr nuidp = nmp->nm_uidlruhead.tqh_first; 10119336Sdfr LIST_REMOVE(nuidp, nu_hash); 10129336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, 10139336Sdfr nu_lru); 10149336Sdfr } 10159336Sdfr nuidp->nu_flag = 0; 10169336Sdfr nuidp->nu_cr.cr_uid = cred->cr_uid; 10179336Sdfr nuidp->nu_expire = time.tv_sec + NFS_KERBTTL; 10189336Sdfr nuidp->nu_timestamp = ktvout; 10199336Sdfr nuidp->nu_nickname = nick; 10209336Sdfr bcopy(key, nuidp->nu_key, sizeof (key)); 10219336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, 10229336Sdfr nu_lru); 10239336Sdfr LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid), 10249336Sdfr nuidp, nu_hash); 10259336Sdfr } 10269336Sdfr } else 10279336Sdfr nfsm_adv(nfsm_rndup(len)); 10289336Sdfrnfsmout: 10299336Sdfr *mdp = md; 10309336Sdfr *dposp = dpos; 10319336Sdfr return (error); 10329336Sdfr} 10339336Sdfr 10349336Sdfr/* 10351541Srgrimes * Derefence a server socket structure. If it has no more references and 10361541Srgrimes * is no longer valid, you can throw it away. 10371541Srgrimes */ 10381541Srgrimesvoid 10391541Srgrimesnfsrv_slpderef(slp) 10401541Srgrimes register struct nfssvc_sock *slp; 10411541Srgrimes{ 10421541Srgrimes if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { 10433664Sphk TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 10441541Srgrimes free((caddr_t)slp, M_NFSSVC); 10451541Srgrimes } 10461541Srgrimes} 10471541Srgrimes 10481541Srgrimes/* 10491541Srgrimes * Initialize the data structures for the server. 10501541Srgrimes * Handshake with any new nfsds starting up to avoid any chance of 10511541Srgrimes * corruption. 10521541Srgrimes */ 10531541Srgrimesvoid 10541541Srgrimesnfsrv_init(terminating) 10551541Srgrimes int terminating; 10561541Srgrimes{ 10573664Sphk register struct nfssvc_sock *slp, *nslp; 10581541Srgrimes 10593664Sphk if (nfssvc_sockhead_flag & SLP_INIT) 10601541Srgrimes panic("nfsd init"); 10613664Sphk nfssvc_sockhead_flag |= SLP_INIT; 10621541Srgrimes if (terminating) { 10633664Sphk for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) { 10643664Sphk nslp = slp->ns_chain.tqe_next; 10651541Srgrimes if (slp->ns_flag & SLP_VALID) 10661541Srgrimes nfsrv_zapsock(slp); 10673664Sphk TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 10683664Sphk free((caddr_t)slp, M_NFSSVC); 10691541Srgrimes } 10701541Srgrimes nfsrv_cleancache(); /* And clear out server cache */ 10711541Srgrimes } 10723664Sphk 10733664Sphk TAILQ_INIT(&nfssvc_sockhead); 10743664Sphk nfssvc_sockhead_flag &= ~SLP_INIT; 10753664Sphk if (nfssvc_sockhead_flag & SLP_WANTINIT) { 10763664Sphk nfssvc_sockhead_flag &= ~SLP_WANTINIT; 10773664Sphk wakeup((caddr_t)&nfssvc_sockhead); 10783664Sphk } 10793664Sphk 10803664Sphk TAILQ_INIT(&nfsd_head); 10813664Sphk nfsd_head_flag &= ~NFSD_CHECKSLP; 10823664Sphk 10831541Srgrimes nfs_udpsock = (struct nfssvc_sock *) 10841541Srgrimes malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 10851541Srgrimes bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock)); 10863664Sphk TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); 10873664Sphk TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); 10883664Sphk 10891541Srgrimes nfs_cltpsock = (struct nfssvc_sock *) 10901541Srgrimes malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 10911541Srgrimes bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock)); 10923664Sphk TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); 10933664Sphk TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); 10941541Srgrimes} 10951541Srgrimes 10961541Srgrimes/* 10971541Srgrimes * Add entries to the server monitor log. 10981541Srgrimes */ 10991541Srgrimesstatic void 11009336Sdfrnfsd_rt(sotype, nd, cacherep) 11011541Srgrimes int sotype; 11029336Sdfr register struct nfsrv_descript *nd; 11031541Srgrimes int cacherep; 11041541Srgrimes{ 11051541Srgrimes register struct drt *rt; 11061541Srgrimes 11071541Srgrimes rt = &nfsdrt.drt[nfsdrt.pos]; 11081541Srgrimes if (cacherep == RC_DOIT) 11091541Srgrimes rt->flag = 0; 11101541Srgrimes else if (cacherep == RC_REPLY) 11111541Srgrimes rt->flag = DRT_CACHEREPLY; 11121541Srgrimes else 11131541Srgrimes rt->flag = DRT_CACHEDROP; 11141541Srgrimes if (sotype == SOCK_STREAM) 11151541Srgrimes rt->flag |= DRT_TCP; 11169336Sdfr if (nd->nd_flag & ND_NQNFS) 11171541Srgrimes rt->flag |= DRT_NQNFS; 11189336Sdfr else if (nd->nd_flag & ND_NFSV3) 11199336Sdfr rt->flag |= DRT_NFSV3; 11201541Srgrimes rt->proc = nd->nd_procnum; 11219336Sdfr if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET) 11229336Sdfr rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr; 11231541Srgrimes else 11249336Sdfr rt->ipadr = INADDR_ANY; 11259336Sdfr rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) + 11269336Sdfr (time.tv_usec - nd->nd_starttime.tv_usec); 11271541Srgrimes rt->tstamp = time; 11281541Srgrimes nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; 11291541Srgrimes} 1130