nfs_nfsiod.c revision 19449
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 3719449Sdfr * $Id: nfs_syscalls.c,v 1.14 1996/04/30 23:26:52 bde Exp $ 381541Srgrimes */ 391541Srgrimes 401541Srgrimes#include <sys/param.h> 411541Srgrimes#include <sys/systm.h> 4212274Sbde#include <sys/sysproto.h> 431541Srgrimes#include <sys/kernel.h> 4419449Sdfr#include <sys/sysctl.h> 451541Srgrimes#include <sys/file.h> 4615480Sbde#include <sys/filedesc.h> 471541Srgrimes#include <sys/stat.h> 481541Srgrimes#include <sys/vnode.h> 491541Srgrimes#include <sys/mount.h> 501541Srgrimes#include <sys/proc.h> 511541Srgrimes#include <sys/uio.h> 521541Srgrimes#include <sys/malloc.h> 531541Srgrimes#include <sys/buf.h> 541541Srgrimes#include <sys/mbuf.h> 551541Srgrimes#include <sys/socket.h> 561541Srgrimes#include <sys/socketvar.h> 571541Srgrimes#include <sys/domain.h> 581541Srgrimes#include <sys/protosw.h> 591541Srgrimes#include <sys/namei.h> 601541Srgrimes#include <sys/syslog.h> 611541Srgrimes 621541Srgrimes#include <netinet/in.h> 631541Srgrimes#include <netinet/tcp.h> 641541Srgrimes#ifdef ISO 651541Srgrimes#include <netiso/iso.h> 661541Srgrimes#endif 679336Sdfr#include <nfs/xdr_subs.h> 681541Srgrimes#include <nfs/rpcv2.h> 699336Sdfr#include <nfs/nfsproto.h> 701541Srgrimes#include <nfs/nfs.h> 719336Sdfr#include <nfs/nfsm_subs.h> 721541Srgrimes#include <nfs/nfsrvcache.h> 731541Srgrimes#include <nfs/nfsmount.h> 741541Srgrimes#include <nfs/nfsnode.h> 751541Srgrimes#include <nfs/nqnfs.h> 761541Srgrimes#include <nfs/nfsrtt.h> 771541Srgrimes 781541Srgrimes/* Global defs. */ 7912457Sbdeextern int (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *nd, 8012457Sbde struct nfssvc_sock *slp, 8112457Sbde struct proc *procp, 8212457Sbde struct mbuf **mreqp)); 831541Srgrimesextern int nfs_numasync; 841541Srgrimesextern time_t nqnfsstarttime; 851541Srgrimesextern int nqsrv_writeslack; 861541Srgrimesextern int nfsrtton; 879336Sdfrextern struct nfsstats nfsstats; 889336Sdfrextern int nfsrvw_procrastinate; 891541Srgrimesstruct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; 9012911Sphkstatic int nuidhash_max = NFS_MAXUIDHASH; 911541Srgrimes 9212911Sphkstatic void nfsrv_zapsock __P((struct nfssvc_sock *slp)); 9313416Sphkstatic int nfssvc_iod __P((struct proc *)); 9412457Sbde 951541Srgrimes#define TRUE 1 961541Srgrimes#define FALSE 0 971541Srgrimes 981541Srgrimesstatic int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 9912457Sbde 10013416Sphk 10113416Sphk#ifndef NFS_NOSERVER 10213416Sphkint nfsd_waiting = 0; 10313416Sphkstatic struct nfsdrt nfsdrt; 10413416Sphkstatic int nfs_numnfsd = 0; 10513416Sphkstatic int notstarted = 1; 10613416Sphkstatic int modify_flag = 0; 10712457Sbdestatic void nfsd_rt __P((int sotype, struct nfsrv_descript *nd, 10812457Sbde int cacherep)); 10912911Sphkstatic int nfssvc_addsock __P((struct file *,struct mbuf *)); 11012911Sphkstatic int nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *)); 1111541Srgrimes/* 1121541Srgrimes * NFS server system calls 1131541Srgrimes * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 1141541Srgrimes */ 1151541Srgrimes 1161541Srgrimes/* 1171541Srgrimes * Get file handle system call 1181541Srgrimes */ 11912274Sbde#ifndef _SYS_SYSPROTO_H_ 1201541Srgrimesstruct getfh_args { 1211541Srgrimes char *fname; 1221541Srgrimes fhandle_t *fhp; 1231541Srgrimes}; 12412274Sbde#endif 1251549Srgrimesint 1261541Srgrimesgetfh(p, uap, retval) 1271541Srgrimes struct proc *p; 1281541Srgrimes register struct getfh_args *uap; 1291541Srgrimes int *retval; 1301541Srgrimes{ 1311541Srgrimes register struct vnode *vp; 1321541Srgrimes fhandle_t fh; 1331541Srgrimes int error; 1341541Srgrimes struct nameidata nd; 1351541Srgrimes 1361541Srgrimes /* 1371541Srgrimes * Must be super user 1381541Srgrimes */ 1393305Sphk error = suser(p->p_ucred, &p->p_acflag); 1403305Sphk if(error) 1411541Srgrimes return (error); 1421541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 1433305Sphk error = namei(&nd); 1443305Sphk if (error) 1451541Srgrimes return (error); 1461541Srgrimes vp = nd.ni_vp; 1471541Srgrimes bzero((caddr_t)&fh, sizeof(fh)); 1481541Srgrimes fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1491541Srgrimes error = VFS_VPTOFH(vp, &fh.fh_fid); 1501541Srgrimes vput(vp); 1511541Srgrimes if (error) 1521541Srgrimes return (error); 1531541Srgrimes error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 1541541Srgrimes return (error); 1551541Srgrimes} 1561541Srgrimes 15713416Sphk#endif /* NFS_NOSERVER */ 1581541Srgrimes/* 1591541Srgrimes * Nfs server psuedo system call for the nfsd's 1601541Srgrimes * Based on the flag value it either: 1611541Srgrimes * - adds a socket to the selection list 1621541Srgrimes * - remains in the kernel as an nfsd 1631541Srgrimes * - remains in the kernel as an nfsiod 1641541Srgrimes */ 16512274Sbde#ifndef _SYS_SYSPROTO_H_ 1661541Srgrimesstruct nfssvc_args { 1671541Srgrimes int flag; 1681541Srgrimes caddr_t argp; 1691541Srgrimes}; 17012274Sbde#endif 1711549Srgrimesint 1721541Srgrimesnfssvc(p, uap, retval) 1731541Srgrimes struct proc *p; 1741541Srgrimes register struct nfssvc_args *uap; 1751541Srgrimes int *retval; 1761541Srgrimes{ 17713416Sphk#ifndef NFS_NOSERVER 1781541Srgrimes struct nameidata nd; 1791541Srgrimes struct file *fp; 1801541Srgrimes struct mbuf *nam; 1811541Srgrimes struct nfsd_args nfsdarg; 1821541Srgrimes struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; 1831541Srgrimes struct nfsd_cargs ncd; 1841541Srgrimes struct nfsd *nfsd; 1851541Srgrimes struct nfssvc_sock *slp; 1863664Sphk struct nfsuid *nuidp; 1871541Srgrimes struct nfsmount *nmp; 18813416Sphk#endif /* NFS_NOSERVER */ 1891541Srgrimes int error; 1901541Srgrimes 1911541Srgrimes /* 1921541Srgrimes * Must be super user 1931541Srgrimes */ 1943305Sphk error = suser(p->p_ucred, &p->p_acflag); 1953305Sphk if(error) 1961541Srgrimes return (error); 1973664Sphk while (nfssvc_sockhead_flag & SLP_INIT) { 1983664Sphk nfssvc_sockhead_flag |= SLP_WANTINIT; 1991541Srgrimes (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); 2001541Srgrimes } 2011541Srgrimes if (uap->flag & NFSSVC_BIOD) 2021541Srgrimes error = nfssvc_iod(p); 20313416Sphk#ifdef NFS_NOSERVER 20413416Sphk else 20513416Sphk error = ENXIO; 20613416Sphk#else /* !NFS_NOSERVER */ 2071541Srgrimes else if (uap->flag & NFSSVC_MNTD) { 2083305Sphk error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); 2093305Sphk if (error) 2101541Srgrimes return (error); 2111541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 2121541Srgrimes ncd.ncd_dirp, p); 2133305Sphk error = namei(&nd); 2143305Sphk if (error) 2151541Srgrimes return (error); 2161541Srgrimes if ((nd.ni_vp->v_flag & VROOT) == 0) 2171541Srgrimes error = EINVAL; 2181541Srgrimes nmp = VFSTONFS(nd.ni_vp->v_mount); 2191541Srgrimes vput(nd.ni_vp); 2201541Srgrimes if (error) 2211541Srgrimes return (error); 2221541Srgrimes if ((nmp->nm_flag & NFSMNT_MNTD) && 2231541Srgrimes (uap->flag & NFSSVC_GOTAUTH) == 0) 2241541Srgrimes return (0); 2251541Srgrimes nmp->nm_flag |= NFSMNT_MNTD; 2261541Srgrimes error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, 2271541Srgrimes uap->argp, p); 2281541Srgrimes } else if (uap->flag & NFSSVC_ADDSOCK) { 2293305Sphk error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); 2303305Sphk if (error) 2311541Srgrimes return (error); 2323305Sphk error = getsock(p->p_fd, nfsdarg.sock, &fp); 2333305Sphk if (error) 2341541Srgrimes return (error); 2351541Srgrimes /* 2361541Srgrimes * Get the client address for connected sockets. 2371541Srgrimes */ 2381541Srgrimes if (nfsdarg.name == NULL || nfsdarg.namelen == 0) 2391541Srgrimes nam = (struct mbuf *)0; 2403305Sphk else { 2413305Sphk error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, 2423305Sphk MT_SONAME); 2433305Sphk if (error) 2443305Sphk return (error); 2453305Sphk } 2461541Srgrimes error = nfssvc_addsock(fp, nam); 2471541Srgrimes } else { 2483305Sphk error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); 2493305Sphk if (error) 2501541Srgrimes return (error); 2513305Sphk if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) && 2529336Sdfr (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { 2539336Sdfr slp = nfsd->nfsd_slp; 2541541Srgrimes 2551541Srgrimes /* 2561541Srgrimes * First check to see if another nfsd has already 2571541Srgrimes * added this credential. 2581541Srgrimes */ 2599336Sdfr for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; 2603664Sphk nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 2619336Sdfr if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid && 2629336Sdfr (!nfsd->nfsd_nd->nd_nam2 || 2639336Sdfr netaddr_match(NU_NETFAM(nuidp), 2649336Sdfr &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) 2651541Srgrimes break; 2661541Srgrimes } 2679336Sdfr if (nuidp) { 2689336Sdfr nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr); 2699336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 2709336Sdfr } else { 2711541Srgrimes /* 2721541Srgrimes * Nope, so we will. 2731541Srgrimes */ 2741541Srgrimes if (slp->ns_numuids < nuidhash_max) { 2751541Srgrimes slp->ns_numuids++; 2761541Srgrimes nuidp = (struct nfsuid *) 2771541Srgrimes malloc(sizeof (struct nfsuid), M_NFSUID, 2781541Srgrimes M_WAITOK); 2791541Srgrimes } else 2801541Srgrimes nuidp = (struct nfsuid *)0; 2811541Srgrimes if ((slp->ns_flag & SLP_VALID) == 0) { 2821541Srgrimes if (nuidp) 2831541Srgrimes free((caddr_t)nuidp, M_NFSUID); 2841541Srgrimes } else { 2851541Srgrimes if (nuidp == (struct nfsuid *)0) { 2863664Sphk nuidp = slp->ns_uidlruhead.tqh_first; 2873664Sphk LIST_REMOVE(nuidp, nu_hash); 2883664Sphk TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, 2893664Sphk nu_lru); 2909336Sdfr if (nuidp->nu_flag & NU_NAM) 2919336Sdfr m_freem(nuidp->nu_nam); 2921541Srgrimes } 2939336Sdfr nuidp->nu_flag = 0; 2941541Srgrimes nuidp->nu_cr = nsd->nsd_cr; 2951541Srgrimes if (nuidp->nu_cr.cr_ngroups > NGROUPS) 2969336Sdfr nuidp->nu_cr.cr_ngroups = NGROUPS; 2971541Srgrimes nuidp->nu_cr.cr_ref = 1; 2989336Sdfr nuidp->nu_timestamp = nsd->nsd_timestamp; 2999336Sdfr nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl; 3009336Sdfr /* 3019336Sdfr * and save the session key in nu_key. 3029336Sdfr */ 3039336Sdfr bcopy(nsd->nsd_key, nuidp->nu_key, 3049336Sdfr sizeof (nsd->nsd_key)); 3059336Sdfr if (nfsd->nfsd_nd->nd_nam2) { 3069336Sdfr struct sockaddr_in *saddr; 3079336Sdfr 3089336Sdfr saddr = mtod(nfsd->nfsd_nd->nd_nam2, 3099336Sdfr struct sockaddr_in *); 3109336Sdfr switch (saddr->sin_family) { 3119336Sdfr case AF_INET: 3129336Sdfr nuidp->nu_flag |= NU_INETADDR; 3139336Sdfr nuidp->nu_inetaddr = 3149336Sdfr saddr->sin_addr.s_addr; 3159336Sdfr break; 3169336Sdfr case AF_ISO: 3179336Sdfr default: 3189336Sdfr nuidp->nu_flag |= NU_NAM; 3199336Sdfr nuidp->nu_nam = m_copym( 3209336Sdfr nfsd->nfsd_nd->nd_nam2, 0, 3219336Sdfr M_COPYALL, M_WAIT); 3229336Sdfr break; 3239336Sdfr }; 3249336Sdfr } 3253664Sphk TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, 3263664Sphk nu_lru); 3273664Sphk LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), 3283664Sphk nuidp, nu_hash); 3299336Sdfr nfsrv_setcred(&nuidp->nu_cr, 3309336Sdfr &nfsd->nfsd_nd->nd_cr); 3319336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 3321541Srgrimes } 3331541Srgrimes } 3341541Srgrimes } 3351541Srgrimes if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) 3369336Sdfr nfsd->nfsd_flag |= NFSD_AUTHFAIL; 3371541Srgrimes error = nfssvc_nfsd(nsd, uap->argp, p); 3381541Srgrimes } 33913416Sphk#endif /* NFS_NOSERVER */ 3401541Srgrimes if (error == EINTR || error == ERESTART) 3411541Srgrimes error = 0; 3421541Srgrimes return (error); 3431541Srgrimes} 3441541Srgrimes 34513416Sphk#ifndef NFS_NOSERVER 3461541Srgrimes/* 3471541Srgrimes * Adds a socket to the list for servicing by nfsds. 3481541Srgrimes */ 34912911Sphkstatic int 3501541Srgrimesnfssvc_addsock(fp, mynam) 3511541Srgrimes struct file *fp; 3521541Srgrimes struct mbuf *mynam; 3531541Srgrimes{ 3541541Srgrimes register struct mbuf *m; 3551541Srgrimes register int siz; 3561541Srgrimes register struct nfssvc_sock *slp; 3571541Srgrimes register struct socket *so; 3581541Srgrimes struct nfssvc_sock *tslp; 3591541Srgrimes int error, s; 3601541Srgrimes 3611541Srgrimes so = (struct socket *)fp->f_data; 3621541Srgrimes tslp = (struct nfssvc_sock *)0; 3631541Srgrimes /* 3641541Srgrimes * Add it to the list, as required. 3651541Srgrimes */ 3661541Srgrimes if (so->so_proto->pr_protocol == IPPROTO_UDP) { 3671541Srgrimes tslp = nfs_udpsock; 3681541Srgrimes if (tslp->ns_flag & SLP_VALID) { 3691541Srgrimes m_freem(mynam); 3701541Srgrimes return (EPERM); 3711541Srgrimes } 3721541Srgrimes#ifdef ISO 3731541Srgrimes } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) { 3741541Srgrimes tslp = nfs_cltpsock; 3751541Srgrimes if (tslp->ns_flag & SLP_VALID) { 3761541Srgrimes m_freem(mynam); 3771541Srgrimes return (EPERM); 3781541Srgrimes } 3791541Srgrimes#endif /* ISO */ 3801541Srgrimes } 3811541Srgrimes if (so->so_type == SOCK_STREAM) 3821541Srgrimes siz = NFS_MAXPACKET + sizeof (u_long); 3831541Srgrimes else 3841541Srgrimes siz = NFS_MAXPACKET; 3858876Srgrimes error = soreserve(so, siz, siz); 3863305Sphk if (error) { 3871541Srgrimes m_freem(mynam); 3881541Srgrimes return (error); 3891541Srgrimes } 3901541Srgrimes 3911541Srgrimes /* 3921541Srgrimes * Set protocol specific options { for now TCP only } and 3931541Srgrimes * reserve some space. For datagram sockets, this can get called 3941541Srgrimes * repeatedly for the same socket, but that isn't harmful. 3951541Srgrimes */ 3961541Srgrimes if (so->so_type == SOCK_STREAM) { 3971541Srgrimes MGET(m, M_WAIT, MT_SOOPTS); 3981541Srgrimes *mtod(m, int *) = 1; 3991541Srgrimes m->m_len = sizeof(int); 4001541Srgrimes sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 4011541Srgrimes } 4021541Srgrimes if (so->so_proto->pr_domain->dom_family == AF_INET && 4031541Srgrimes so->so_proto->pr_protocol == IPPROTO_TCP) { 4041541Srgrimes MGET(m, M_WAIT, MT_SOOPTS); 4051541Srgrimes *mtod(m, int *) = 1; 4061541Srgrimes m->m_len = sizeof(int); 4071541Srgrimes sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 4081541Srgrimes } 4091541Srgrimes so->so_rcv.sb_flags &= ~SB_NOINTR; 4101541Srgrimes so->so_rcv.sb_timeo = 0; 4111541Srgrimes so->so_snd.sb_flags &= ~SB_NOINTR; 4121541Srgrimes so->so_snd.sb_timeo = 0; 4131541Srgrimes if (tslp) 4141541Srgrimes slp = tslp; 4151541Srgrimes else { 4161541Srgrimes slp = (struct nfssvc_sock *) 4171541Srgrimes malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 4181541Srgrimes bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); 4193664Sphk TAILQ_INIT(&slp->ns_uidlruhead); 4203664Sphk TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); 4211541Srgrimes } 4221541Srgrimes slp->ns_so = so; 4231541Srgrimes slp->ns_nam = mynam; 4241541Srgrimes fp->f_count++; 4251541Srgrimes slp->ns_fp = fp; 4261541Srgrimes s = splnet(); 4271541Srgrimes so->so_upcallarg = (caddr_t)slp; 4281541Srgrimes so->so_upcall = nfsrv_rcv; 4291541Srgrimes slp->ns_flag = (SLP_VALID | SLP_NEEDQ); 4301541Srgrimes nfsrv_wakenfsd(slp); 4311541Srgrimes splx(s); 4321541Srgrimes return (0); 4331541Srgrimes} 4341541Srgrimes 4351541Srgrimes/* 4361541Srgrimes * Called by nfssvc() for nfsds. Just loops around servicing rpc requests 4371541Srgrimes * until it is killed by a signal. 4381541Srgrimes */ 43912911Sphkstatic int 4401541Srgrimesnfssvc_nfsd(nsd, argp, p) 4411541Srgrimes struct nfsd_srvargs *nsd; 4421541Srgrimes caddr_t argp; 4431541Srgrimes struct proc *p; 4441541Srgrimes{ 4459336Sdfr register struct mbuf *m; 4461541Srgrimes register int siz; 4471541Srgrimes register struct nfssvc_sock *slp; 4481541Srgrimes register struct socket *so; 4491541Srgrimes register int *solockp; 4509336Sdfr struct nfsd *nfsd = nsd->nsd_nfsd; 4519336Sdfr struct nfsrv_descript *nd = NULL; 4529336Sdfr struct mbuf *mreq; 4539336Sdfr int error = 0, cacherep, s, sotype, writes_todo; 4549336Sdfr u_quad_t cur_usec; 4551541Srgrimes 4569336Sdfr#ifndef nolint 4579336Sdfr cacherep = RC_DOIT; 4589336Sdfr writes_todo = 0; 4599336Sdfr#endif 4601541Srgrimes s = splnet(); 4619336Sdfr if (nfsd == (struct nfsd *)0) { 4629336Sdfr nsd->nsd_nfsd = nfsd = (struct nfsd *) 4631541Srgrimes malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK); 4649336Sdfr bzero((caddr_t)nfsd, sizeof (struct nfsd)); 4659336Sdfr nfsd->nfsd_procp = p; 4669336Sdfr TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); 4671541Srgrimes nfs_numnfsd++; 4681541Srgrimes } 4691541Srgrimes /* 4701541Srgrimes * Loop getting rpc requests until SIGKILL. 4711541Srgrimes */ 4721541Srgrimes for (;;) { 4739336Sdfr if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { 4749336Sdfr while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 4753664Sphk (nfsd_head_flag & NFSD_CHECKSLP) == 0) { 4769336Sdfr nfsd->nfsd_flag |= NFSD_WAITING; 4771541Srgrimes nfsd_waiting++; 4789336Sdfr error = tsleep((caddr_t)nfsd, PSOCK | PCATCH, 4799336Sdfr "nfsd", 0); 4801541Srgrimes nfsd_waiting--; 4811541Srgrimes if (error) 4821541Srgrimes goto done; 4831541Srgrimes } 4849336Sdfr if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 4853664Sphk (nfsd_head_flag & NFSD_CHECKSLP) != 0) { 4863664Sphk for (slp = nfssvc_sockhead.tqh_first; slp != 0; 4873664Sphk slp = slp->ns_chain.tqe_next) { 4881541Srgrimes if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) 4891541Srgrimes == (SLP_VALID | SLP_DOREC)) { 4901541Srgrimes slp->ns_flag &= ~SLP_DOREC; 4911541Srgrimes slp->ns_sref++; 4929336Sdfr nfsd->nfsd_slp = slp; 4931541Srgrimes break; 4941541Srgrimes } 4951541Srgrimes } 4963664Sphk if (slp == 0) 4973664Sphk nfsd_head_flag &= ~NFSD_CHECKSLP; 4981541Srgrimes } 4999336Sdfr if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0) 5001541Srgrimes continue; 5011541Srgrimes if (slp->ns_flag & SLP_VALID) { 5021541Srgrimes if (slp->ns_flag & SLP_DISCONN) 5031541Srgrimes nfsrv_zapsock(slp); 5041541Srgrimes else if (slp->ns_flag & SLP_NEEDQ) { 5051541Srgrimes slp->ns_flag &= ~SLP_NEEDQ; 5061541Srgrimes (void) nfs_sndlock(&slp->ns_solock, 5071541Srgrimes (struct nfsreq *)0); 5081541Srgrimes nfsrv_rcv(slp->ns_so, (caddr_t)slp, 5091541Srgrimes M_WAIT); 5101541Srgrimes nfs_sndunlock(&slp->ns_solock); 5111541Srgrimes } 5129336Sdfr error = nfsrv_dorec(slp, nfsd, &nd); 5139336Sdfr cur_usec = (u_quad_t)time.tv_sec * 1000000 + 5149336Sdfr (u_quad_t)time.tv_usec; 5159336Sdfr if (error && slp->ns_tq.lh_first && 5169336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 5179336Sdfr error = 0; 5189336Sdfr cacherep = RC_DOIT; 5199336Sdfr writes_todo = 1; 5209336Sdfr } else 5219336Sdfr writes_todo = 0; 5229336Sdfr nfsd->nfsd_flag |= NFSD_REQINPROG; 5231541Srgrimes } 5241541Srgrimes } else { 5251541Srgrimes error = 0; 5269336Sdfr slp = nfsd->nfsd_slp; 5271541Srgrimes } 5281541Srgrimes if (error || (slp->ns_flag & SLP_VALID) == 0) { 5299336Sdfr if (nd) { 5309336Sdfr free((caddr_t)nd, M_NFSRVDESC); 5319336Sdfr nd = NULL; 5329336Sdfr } 5339336Sdfr nfsd->nfsd_slp = (struct nfssvc_sock *)0; 5349336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 5351541Srgrimes nfsrv_slpderef(slp); 5361541Srgrimes continue; 5371541Srgrimes } 5381541Srgrimes splx(s); 5391541Srgrimes so = slp->ns_so; 5401541Srgrimes sotype = so->so_type; 5411541Srgrimes if (so->so_proto->pr_flags & PR_CONNREQUIRED) 5421541Srgrimes solockp = &slp->ns_solock; 5431541Srgrimes else 5441541Srgrimes solockp = (int *)0; 5459336Sdfr if (nd) { 5469336Sdfr nd->nd_starttime = time; 5479336Sdfr if (nd->nd_nam2) 5489336Sdfr nd->nd_nam = nd->nd_nam2; 5499336Sdfr else 5509336Sdfr nd->nd_nam = slp->ns_nam; 5511541Srgrimes 5529336Sdfr /* 5539336Sdfr * Check to see if authorization is needed. 5549336Sdfr */ 5559336Sdfr if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { 5569336Sdfr nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; 5579336Sdfr nsd->nsd_haddr = mtod(nd->nd_nam, 5589336Sdfr struct sockaddr_in *)->sin_addr.s_addr; 5599336Sdfr nsd->nsd_authlen = nfsd->nfsd_authlen; 5609336Sdfr nsd->nsd_verflen = nfsd->nfsd_verflen; 5619336Sdfr if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr, 5629336Sdfr nfsd->nfsd_authlen) && 5639336Sdfr !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr, 5649336Sdfr nfsd->nfsd_verflen) && 5659336Sdfr !copyout((caddr_t)nsd, argp, sizeof (*nsd))) 5669336Sdfr return (ENEEDAUTH); 5679336Sdfr cacherep = RC_DROPIT; 5689336Sdfr } else 5699336Sdfr cacherep = nfsrv_getcache(nd, slp, &mreq); 5701541Srgrimes 5719336Sdfr /* 5729336Sdfr * Check for just starting up for NQNFS and send 5739336Sdfr * fake "try again later" replies to the NQNFS clients. 5749336Sdfr */ 5759336Sdfr if (notstarted && nqnfsstarttime <= time.tv_sec) { 5761541Srgrimes if (modify_flag) { 5771541Srgrimes nqnfsstarttime = time.tv_sec + nqsrv_writeslack; 5781541Srgrimes modify_flag = 0; 5791541Srgrimes } else 5801541Srgrimes notstarted = 0; 5819336Sdfr } 5829336Sdfr if (notstarted) { 5839336Sdfr if ((nd->nd_flag & ND_NQNFS) == 0) 5841541Srgrimes cacherep = RC_DROPIT; 5851541Srgrimes else if (nd->nd_procnum != NFSPROC_WRITE) { 5861541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 5871541Srgrimes nd->nd_repstat = NQNFS_TRYLATER; 5881541Srgrimes cacherep = RC_DOIT; 5891541Srgrimes } else 5901541Srgrimes modify_flag = 1; 5919336Sdfr } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { 5929336Sdfr nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; 5931541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 5949336Sdfr nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 5951541Srgrimes cacherep = RC_DOIT; 5969336Sdfr } 5971541Srgrimes } 5981541Srgrimes 5999336Sdfr /* 6009336Sdfr * Loop to get all the write rpc relies that have been 6019336Sdfr * gathered together. 6029336Sdfr */ 6039336Sdfr do { 6049336Sdfr switch (cacherep) { 6059336Sdfr case RC_DOIT: 6069336Sdfr if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && 6079336Sdfr nfsrvw_procrastinate > 0 && !notstarted)) 6089336Sdfr error = nfsrv_writegather(&nd, slp, 6099336Sdfr nfsd->nfsd_procp, &mreq); 6109336Sdfr else 6119336Sdfr error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, 6129336Sdfr slp, nfsd->nfsd_procp, &mreq); 6139336Sdfr if (mreq == NULL) 6149336Sdfr break; 6151541Srgrimes if (error) { 6161541Srgrimes if (nd->nd_procnum != NQNFSPROC_VACATED) 6171541Srgrimes nfsstats.srv_errs++; 6189336Sdfr nfsrv_updatecache(nd, FALSE, mreq); 6199336Sdfr if (nd->nd_nam2) 6209336Sdfr m_freem(nd->nd_nam2); 6211541Srgrimes break; 6221541Srgrimes } 6231541Srgrimes nfsstats.srvrpccnt[nd->nd_procnum]++; 6249336Sdfr nfsrv_updatecache(nd, TRUE, mreq); 6251541Srgrimes nd->nd_mrep = (struct mbuf *)0; 6269336Sdfr case RC_REPLY: 6271541Srgrimes m = mreq; 6281541Srgrimes siz = 0; 6291541Srgrimes while (m) { 6301541Srgrimes siz += m->m_len; 6311541Srgrimes m = m->m_next; 6321541Srgrimes } 6331541Srgrimes if (siz <= 0 || siz > NFS_MAXPACKET) { 6341541Srgrimes printf("mbuf siz=%d\n",siz); 6351541Srgrimes panic("Bad nfs svc reply"); 6361541Srgrimes } 6371541Srgrimes m = mreq; 6381541Srgrimes m->m_pkthdr.len = siz; 6391541Srgrimes m->m_pkthdr.rcvif = (struct ifnet *)0; 6401541Srgrimes /* 6411541Srgrimes * For stream protocols, prepend a Sun RPC 6421541Srgrimes * Record Mark. 6431541Srgrimes */ 6441541Srgrimes if (sotype == SOCK_STREAM) { 6451541Srgrimes M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 6461541Srgrimes *mtod(m, u_long *) = htonl(0x80000000 | siz); 6471541Srgrimes } 6481541Srgrimes if (solockp) 6491541Srgrimes (void) nfs_sndlock(solockp, (struct nfsreq *)0); 6501541Srgrimes if (slp->ns_flag & SLP_VALID) 6519336Sdfr error = nfs_send(so, nd->nd_nam2, m, NULL); 6521541Srgrimes else { 6531541Srgrimes error = EPIPE; 6541541Srgrimes m_freem(m); 6551541Srgrimes } 6561541Srgrimes if (nfsrtton) 6579336Sdfr nfsd_rt(sotype, nd, cacherep); 6589336Sdfr if (nd->nd_nam2) 6599336Sdfr MFREE(nd->nd_nam2, m); 6601541Srgrimes if (nd->nd_mrep) 6611541Srgrimes m_freem(nd->nd_mrep); 6621541Srgrimes if (error == EPIPE) 6631541Srgrimes nfsrv_zapsock(slp); 6641541Srgrimes if (solockp) 6651541Srgrimes nfs_sndunlock(solockp); 6661541Srgrimes if (error == EINTR || error == ERESTART) { 6679336Sdfr free((caddr_t)nd, M_NFSRVDESC); 6681541Srgrimes nfsrv_slpderef(slp); 6691541Srgrimes s = splnet(); 6701541Srgrimes goto done; 6711541Srgrimes } 6721541Srgrimes break; 6739336Sdfr case RC_DROPIT: 6741541Srgrimes if (nfsrtton) 6759336Sdfr nfsd_rt(sotype, nd, cacherep); 6761541Srgrimes m_freem(nd->nd_mrep); 6779336Sdfr m_freem(nd->nd_nam2); 6781541Srgrimes break; 6799336Sdfr }; 6809336Sdfr if (nd) { 6819336Sdfr FREE((caddr_t)nd, M_NFSRVDESC); 6829336Sdfr nd = NULL; 6839336Sdfr } 6849336Sdfr 6859336Sdfr /* 6869336Sdfr * Check to see if there are outstanding writes that 6879336Sdfr * need to be serviced. 6889336Sdfr */ 6899336Sdfr cur_usec = (u_quad_t)time.tv_sec * 1000000 + 6909336Sdfr (u_quad_t)time.tv_usec; 6919336Sdfr s = splsoftclock(); 6929336Sdfr if (slp->ns_tq.lh_first && 6939336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 6949336Sdfr cacherep = RC_DOIT; 6959336Sdfr writes_todo = 1; 6969336Sdfr } else 6979336Sdfr writes_todo = 0; 6989336Sdfr splx(s); 6999336Sdfr } while (writes_todo); 7001541Srgrimes s = splnet(); 7019336Sdfr if (nfsrv_dorec(slp, nfsd, &nd)) { 7029336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 7039336Sdfr nfsd->nfsd_slp = NULL; 7041541Srgrimes nfsrv_slpderef(slp); 7051541Srgrimes } 7061541Srgrimes } 7071541Srgrimesdone: 7089336Sdfr TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); 7091541Srgrimes splx(s); 7109336Sdfr free((caddr_t)nfsd, M_NFSD); 7111541Srgrimes nsd->nsd_nfsd = (struct nfsd *)0; 7121541Srgrimes if (--nfs_numnfsd == 0) 7131541Srgrimes nfsrv_init(TRUE); /* Reinitialize everything */ 7141541Srgrimes return (error); 7151541Srgrimes} 71613416Sphk#endif /* NFS_NOSERVER */ 7171541Srgrimes 71819449Sdfrint nfs_defect = 0; 71919449SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); 72019449Sdfr 7211541Srgrimes/* 7221541Srgrimes * Asynchronous I/O daemons for client nfs. 7231541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache. 7241541Srgrimes * Never returns unless it fails or gets killed. 7251541Srgrimes */ 72612911Sphkstatic int 7271541Srgrimesnfssvc_iod(p) 7281541Srgrimes struct proc *p; 7291541Srgrimes{ 7309336Sdfr register struct buf *bp, *nbp; 7311541Srgrimes register int i, myiod; 7329336Sdfr struct vnode *vp; 73319449Sdfr struct nfsmount *nmp; 7349336Sdfr int error = 0, s; 7351541Srgrimes 7361541Srgrimes /* 7371541Srgrimes * Assign my position or return error if too many already running 7381541Srgrimes */ 7391541Srgrimes myiod = -1; 7401541Srgrimes for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 7411541Srgrimes if (nfs_asyncdaemon[i] == 0) { 7421541Srgrimes nfs_asyncdaemon[i]++; 7431541Srgrimes myiod = i; 7441541Srgrimes break; 7451541Srgrimes } 7461541Srgrimes if (myiod == -1) 7471541Srgrimes return (EBUSY); 7481541Srgrimes nfs_numasync++; 7491541Srgrimes /* 7501541Srgrimes * Just loop around doin our stuff until SIGKILL 7511541Srgrimes */ 7521541Srgrimes for (;;) { 75319449Sdfr while (((nmp = nfs_iodmount[myiod]) == NULL 75419449Sdfr || nmp->nm_bufq.tqh_first == NULL) 75519449Sdfr && error == 0) { 75619449Sdfr if (nmp) 75719449Sdfr nmp->nm_bufqiods--; 7589336Sdfr nfs_iodwant[myiod] = p; 75919449Sdfr nfs_iodmount[myiod] = NULL; 7609336Sdfr error = tsleep((caddr_t)&nfs_iodwant[myiod], 7619336Sdfr PWAIT | PCATCH, "nfsidl", 0); 7629336Sdfr } 76319449Sdfr if (error) { 76419449Sdfr nfs_asyncdaemon[myiod] = 0; 76519449Sdfr if (nmp) nmp->nm_bufqiods--; 76619449Sdfr nfs_iodmount[myiod] = NULL; 76719449Sdfr nfs_numasync--; 76819449Sdfr return (error); 76919449Sdfr } 77019449Sdfr while ((bp = nmp->nm_bufq.tqh_first) != NULL) { 7719336Sdfr /* Take one off the front of the list */ 77219449Sdfr TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); 77319449Sdfr nmp->nm_bufqlen--; 77419449Sdfr if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) { 77519449Sdfr nmp->nm_bufqwant = FALSE; 77619449Sdfr wakeup(&nmp->nm_bufq); 77719449Sdfr } 7789336Sdfr if (bp->b_flags & B_READ) 7799336Sdfr (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); 78019449Sdfr else 7819336Sdfr (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); 78219449Sdfr 78319449Sdfr /* 78419449Sdfr * If there are more than one iod on this mount, then defect 78519449Sdfr * so that the iods can be shared out fairly between the mounts 78619449Sdfr */ 78719449Sdfr if (nfs_defect && nmp->nm_bufqiods > 1) { 78819449Sdfr NFS_DPF(ASYNCIO, 78919449Sdfr ("nfssvc_iod: iod %d defecting from mount %p\n", 79019449Sdfr myiod, nmp)); 79119449Sdfr nfs_iodmount[myiod] = NULL; 79219449Sdfr nmp->nm_bufqiods--; 79319449Sdfr break; 79419449Sdfr } 7959336Sdfr } 7961541Srgrimes } 7971541Srgrimes} 7981541Srgrimes 7991541Srgrimes/* 8001541Srgrimes * Shut down a socket associated with an nfssvc_sock structure. 8011541Srgrimes * Should be called with the send lock set, if required. 8021541Srgrimes * The trick here is to increment the sref at the start, so that the nfsds 8031541Srgrimes * will stop using it and clear ns_flag at the end so that it will not be 8041541Srgrimes * reassigned during cleanup. 8051541Srgrimes */ 80612911Sphkstatic void 8071541Srgrimesnfsrv_zapsock(slp) 8081541Srgrimes register struct nfssvc_sock *slp; 8091541Srgrimes{ 8103664Sphk register struct nfsuid *nuidp, *nnuidp; 8119336Sdfr register struct nfsrv_descript *nwp, *nnwp; 8121541Srgrimes struct socket *so; 8131541Srgrimes struct file *fp; 8141541Srgrimes struct mbuf *m; 8159336Sdfr int s; 8161541Srgrimes 8171541Srgrimes slp->ns_flag &= ~SLP_ALLFLAGS; 8183305Sphk fp = slp->ns_fp; 8193305Sphk if (fp) { 8201541Srgrimes slp->ns_fp = (struct file *)0; 8211541Srgrimes so = slp->ns_so; 8221541Srgrimes so->so_upcall = NULL; 8231541Srgrimes soshutdown(so, 2); 8241541Srgrimes closef(fp, (struct proc *)0); 8251541Srgrimes if (slp->ns_nam) 8261541Srgrimes MFREE(slp->ns_nam, m); 8271541Srgrimes m_freem(slp->ns_raw); 8281541Srgrimes m_freem(slp->ns_rec); 8293664Sphk for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; 8303664Sphk nuidp = nnuidp) { 8313664Sphk nnuidp = nuidp->nu_lru.tqe_next; 8323664Sphk LIST_REMOVE(nuidp, nu_hash); 8333664Sphk TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); 8349336Sdfr if (nuidp->nu_flag & NU_NAM) 8359336Sdfr m_freem(nuidp->nu_nam); 8363664Sphk free((caddr_t)nuidp, M_NFSUID); 8371541Srgrimes } 8389336Sdfr s = splsoftclock(); 8399336Sdfr for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { 8409336Sdfr nnwp = nwp->nd_tq.le_next; 8419336Sdfr LIST_REMOVE(nwp, nd_tq); 8429336Sdfr free((caddr_t)nwp, M_NFSRVDESC); 8439336Sdfr } 8449336Sdfr LIST_INIT(&slp->ns_tq); 8459336Sdfr splx(s); 8461541Srgrimes } 8471541Srgrimes} 8481541Srgrimes 8491541Srgrimes/* 8501541Srgrimes * Get an authorization string for the uid by having the mount_nfs sitting 8511541Srgrimes * on this mount point porpous out of the kernel and do it. 8521541Srgrimes */ 8531549Srgrimesint 8549336Sdfrnfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) 8551541Srgrimes register struct nfsmount *nmp; 8561541Srgrimes struct nfsreq *rep; 8571541Srgrimes struct ucred *cred; 8581541Srgrimes char **auth_str; 8591541Srgrimes int *auth_len; 8609336Sdfr char *verf_str; 8619336Sdfr int *verf_len; 8629336Sdfr NFSKERBKEY_T key; /* return session key */ 8631541Srgrimes{ 8641541Srgrimes int error = 0; 8651541Srgrimes 8661541Srgrimes while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) { 8671541Srgrimes nmp->nm_flag |= NFSMNT_WANTAUTH; 8681541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, 8691541Srgrimes "nfsauth1", 2 * hz); 8703305Sphk error = nfs_sigintr(nmp, rep, rep->r_procp); 8713305Sphk if (error) { 8721541Srgrimes nmp->nm_flag &= ~NFSMNT_WANTAUTH; 8731541Srgrimes return (error); 8741541Srgrimes } 8751541Srgrimes } 8761541Srgrimes nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH); 8771541Srgrimes nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); 8789336Sdfr nmp->nm_authlen = RPCAUTH_MAXSIZ; 8799336Sdfr nmp->nm_verfstr = verf_str; 8809336Sdfr nmp->nm_verflen = *verf_len; 8811541Srgrimes nmp->nm_authuid = cred->cr_uid; 8821541Srgrimes wakeup((caddr_t)&nmp->nm_authstr); 8831541Srgrimes 8841541Srgrimes /* 8851541Srgrimes * And wait for mount_nfs to do its stuff. 8861541Srgrimes */ 8871541Srgrimes while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) { 8881541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, 8891541Srgrimes "nfsauth2", 2 * hz); 8901541Srgrimes error = nfs_sigintr(nmp, rep, rep->r_procp); 8911541Srgrimes } 8921541Srgrimes if (nmp->nm_flag & NFSMNT_AUTHERR) { 8931541Srgrimes nmp->nm_flag &= ~NFSMNT_AUTHERR; 8941541Srgrimes error = EAUTH; 8951541Srgrimes } 8961541Srgrimes if (error) 8971541Srgrimes free((caddr_t)*auth_str, M_TEMP); 8981541Srgrimes else { 8991541Srgrimes *auth_len = nmp->nm_authlen; 9009336Sdfr *verf_len = nmp->nm_verflen; 9019336Sdfr bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); 9021541Srgrimes } 9031541Srgrimes nmp->nm_flag &= ~NFSMNT_HASAUTH; 9041541Srgrimes nmp->nm_flag |= NFSMNT_WAITAUTH; 9051541Srgrimes if (nmp->nm_flag & NFSMNT_WANTAUTH) { 9061541Srgrimes nmp->nm_flag &= ~NFSMNT_WANTAUTH; 9071541Srgrimes wakeup((caddr_t)&nmp->nm_authtype); 9081541Srgrimes } 9091541Srgrimes return (error); 9101541Srgrimes} 9111541Srgrimes 9121541Srgrimes/* 9139336Sdfr * Get a nickname authenticator and verifier. 9149336Sdfr */ 9159336Sdfrint 9169336Sdfrnfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len) 9179336Sdfr struct nfsmount *nmp; 9189336Sdfr struct ucred *cred; 9199336Sdfr char **auth_str; 9209336Sdfr int *auth_len; 9219336Sdfr char *verf_str; 9229336Sdfr int verf_len; 9239336Sdfr{ 9249336Sdfr register struct nfsuid *nuidp; 9259336Sdfr register u_long *nickp, *verfp; 9269336Sdfr struct timeval ktvin, ktvout; 9279336Sdfr 9289336Sdfr#ifdef DIAGNOSTIC 9299336Sdfr if (verf_len < (4 * NFSX_UNSIGNED)) 9309336Sdfr panic("nfs_getnickauth verf too small"); 9319336Sdfr#endif 9329336Sdfr for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first; 9339336Sdfr nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 9349336Sdfr if (nuidp->nu_cr.cr_uid == cred->cr_uid) 9359336Sdfr break; 9369336Sdfr } 9379336Sdfr if (!nuidp || nuidp->nu_expire < time.tv_sec) 9389336Sdfr return (EACCES); 9399336Sdfr 9409336Sdfr /* 9419336Sdfr * Move to the end of the lru list (end of lru == most recently used). 9429336Sdfr */ 9439336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); 9449336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); 9459336Sdfr 9469336Sdfr nickp = (u_long *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); 9479336Sdfr *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); 9489336Sdfr *nickp = txdr_unsigned(nuidp->nu_nickname); 9499336Sdfr *auth_str = (char *)nickp; 9509336Sdfr *auth_len = 2 * NFSX_UNSIGNED; 9519336Sdfr 9529336Sdfr /* 9539336Sdfr * Now we must encrypt the verifier and package it up. 9549336Sdfr */ 9559336Sdfr verfp = (u_long *)verf_str; 9569336Sdfr *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); 9579336Sdfr if (time.tv_sec > nuidp->nu_timestamp.tv_sec || 9589336Sdfr (time.tv_sec == nuidp->nu_timestamp.tv_sec && 9599336Sdfr time.tv_usec > nuidp->nu_timestamp.tv_usec)) 9609336Sdfr nuidp->nu_timestamp = time; 9619336Sdfr else 9629336Sdfr nuidp->nu_timestamp.tv_usec++; 9639336Sdfr ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); 9649336Sdfr ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); 9659336Sdfr 9669336Sdfr /* 9679336Sdfr * Now encrypt the timestamp verifier in ecb mode using the session 9689336Sdfr * key. 9699336Sdfr */ 9709336Sdfr#ifdef NFSKERB 9719336Sdfr XXX 9729336Sdfr#endif 9739336Sdfr 9749336Sdfr *verfp++ = ktvout.tv_sec; 9759336Sdfr *verfp++ = ktvout.tv_usec; 9769336Sdfr *verfp = 0; 9779336Sdfr return (0); 9789336Sdfr} 9799336Sdfr 9809336Sdfr/* 9819336Sdfr * Save the current nickname in a hash list entry on the mount point. 9829336Sdfr */ 9839336Sdfrint 9849336Sdfrnfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) 9859336Sdfr register struct nfsmount *nmp; 9869336Sdfr struct ucred *cred; 9879336Sdfr int len; 9889336Sdfr NFSKERBKEY_T key; 9899336Sdfr struct mbuf **mdp; 9909336Sdfr char **dposp; 9919336Sdfr struct mbuf *mrep; 9929336Sdfr{ 9939336Sdfr register struct nfsuid *nuidp; 9949336Sdfr register u_long *tl; 9959336Sdfr register long t1; 9969336Sdfr struct mbuf *md = *mdp; 9979336Sdfr struct timeval ktvin, ktvout; 9989336Sdfr u_long nick; 9999336Sdfr char *dpos = *dposp, *cp2; 10009336Sdfr int deltasec, error = 0; 10019336Sdfr 10029336Sdfr if (len == (3 * NFSX_UNSIGNED)) { 10039336Sdfr nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); 10049336Sdfr ktvin.tv_sec = *tl++; 10059336Sdfr ktvin.tv_usec = *tl++; 10069336Sdfr nick = fxdr_unsigned(u_long, *tl); 10079336Sdfr 10089336Sdfr /* 10099336Sdfr * Decrypt the timestamp in ecb mode. 10109336Sdfr */ 10119336Sdfr#ifdef NFSKERB 10129336Sdfr XXX 10139336Sdfr#endif 10149336Sdfr ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); 10159336Sdfr ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); 10169336Sdfr deltasec = time.tv_sec - ktvout.tv_sec; 10179336Sdfr if (deltasec < 0) 10189336Sdfr deltasec = -deltasec; 10199336Sdfr /* 10209336Sdfr * If ok, add it to the hash list for the mount point. 10219336Sdfr */ 10229336Sdfr if (deltasec <= NFS_KERBCLOCKSKEW) { 10239336Sdfr if (nmp->nm_numuids < nuidhash_max) { 10249336Sdfr nmp->nm_numuids++; 10259336Sdfr nuidp = (struct nfsuid *) 10269336Sdfr malloc(sizeof (struct nfsuid), M_NFSUID, 10279336Sdfr M_WAITOK); 10289336Sdfr } else { 10299336Sdfr nuidp = nmp->nm_uidlruhead.tqh_first; 10309336Sdfr LIST_REMOVE(nuidp, nu_hash); 10319336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, 10329336Sdfr nu_lru); 10339336Sdfr } 10349336Sdfr nuidp->nu_flag = 0; 10359336Sdfr nuidp->nu_cr.cr_uid = cred->cr_uid; 10369336Sdfr nuidp->nu_expire = time.tv_sec + NFS_KERBTTL; 10379336Sdfr nuidp->nu_timestamp = ktvout; 10389336Sdfr nuidp->nu_nickname = nick; 10399336Sdfr bcopy(key, nuidp->nu_key, sizeof (key)); 10409336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, 10419336Sdfr nu_lru); 10429336Sdfr LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid), 10439336Sdfr nuidp, nu_hash); 10449336Sdfr } 10459336Sdfr } else 10469336Sdfr nfsm_adv(nfsm_rndup(len)); 10479336Sdfrnfsmout: 10489336Sdfr *mdp = md; 10499336Sdfr *dposp = dpos; 10509336Sdfr return (error); 10519336Sdfr} 10529336Sdfr 105313416Sphk#ifndef NFS_NOSERVER 10549336Sdfr/* 10551541Srgrimes * Derefence a server socket structure. If it has no more references and 10561541Srgrimes * is no longer valid, you can throw it away. 10571541Srgrimes */ 10581541Srgrimesvoid 10591541Srgrimesnfsrv_slpderef(slp) 10601541Srgrimes register struct nfssvc_sock *slp; 10611541Srgrimes{ 10621541Srgrimes if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { 10633664Sphk TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 10641541Srgrimes free((caddr_t)slp, M_NFSSVC); 10651541Srgrimes } 10661541Srgrimes} 10671541Srgrimes 10681541Srgrimes/* 10691541Srgrimes * Initialize the data structures for the server. 10701541Srgrimes * Handshake with any new nfsds starting up to avoid any chance of 10711541Srgrimes * corruption. 10721541Srgrimes */ 10731541Srgrimesvoid 10741541Srgrimesnfsrv_init(terminating) 10751541Srgrimes int terminating; 10761541Srgrimes{ 10773664Sphk register struct nfssvc_sock *slp, *nslp; 10781541Srgrimes 10793664Sphk if (nfssvc_sockhead_flag & SLP_INIT) 10801541Srgrimes panic("nfsd init"); 10813664Sphk nfssvc_sockhead_flag |= SLP_INIT; 10821541Srgrimes if (terminating) { 10833664Sphk for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) { 10843664Sphk nslp = slp->ns_chain.tqe_next; 10851541Srgrimes if (slp->ns_flag & SLP_VALID) 10861541Srgrimes nfsrv_zapsock(slp); 10873664Sphk TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); 10883664Sphk free((caddr_t)slp, M_NFSSVC); 10891541Srgrimes } 10901541Srgrimes nfsrv_cleancache(); /* And clear out server cache */ 10911541Srgrimes } 10923664Sphk 10933664Sphk TAILQ_INIT(&nfssvc_sockhead); 10943664Sphk nfssvc_sockhead_flag &= ~SLP_INIT; 10953664Sphk if (nfssvc_sockhead_flag & SLP_WANTINIT) { 10963664Sphk nfssvc_sockhead_flag &= ~SLP_WANTINIT; 10973664Sphk wakeup((caddr_t)&nfssvc_sockhead); 10983664Sphk } 10993664Sphk 11003664Sphk TAILQ_INIT(&nfsd_head); 11013664Sphk nfsd_head_flag &= ~NFSD_CHECKSLP; 11023664Sphk 11031541Srgrimes nfs_udpsock = (struct nfssvc_sock *) 11041541Srgrimes malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 11051541Srgrimes bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock)); 11063664Sphk TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); 11073664Sphk TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); 11083664Sphk 11091541Srgrimes nfs_cltpsock = (struct nfssvc_sock *) 11101541Srgrimes malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 11111541Srgrimes bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock)); 11123664Sphk TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); 11133664Sphk TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); 11141541Srgrimes} 11151541Srgrimes 11161541Srgrimes/* 11171541Srgrimes * Add entries to the server monitor log. 11181541Srgrimes */ 11191541Srgrimesstatic void 11209336Sdfrnfsd_rt(sotype, nd, cacherep) 11211541Srgrimes int sotype; 11229336Sdfr register struct nfsrv_descript *nd; 11231541Srgrimes int cacherep; 11241541Srgrimes{ 11251541Srgrimes register struct drt *rt; 11261541Srgrimes 11271541Srgrimes rt = &nfsdrt.drt[nfsdrt.pos]; 11281541Srgrimes if (cacherep == RC_DOIT) 11291541Srgrimes rt->flag = 0; 11301541Srgrimes else if (cacherep == RC_REPLY) 11311541Srgrimes rt->flag = DRT_CACHEREPLY; 11321541Srgrimes else 11331541Srgrimes rt->flag = DRT_CACHEDROP; 11341541Srgrimes if (sotype == SOCK_STREAM) 11351541Srgrimes rt->flag |= DRT_TCP; 11369336Sdfr if (nd->nd_flag & ND_NQNFS) 11371541Srgrimes rt->flag |= DRT_NQNFS; 11389336Sdfr else if (nd->nd_flag & ND_NFSV3) 11399336Sdfr rt->flag |= DRT_NFSV3; 11401541Srgrimes rt->proc = nd->nd_procnum; 11419336Sdfr if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET) 11429336Sdfr rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr; 11431541Srgrimes else 11449336Sdfr rt->ipadr = INADDR_ANY; 11459336Sdfr rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) + 11469336Sdfr (time.tv_usec - nd->nd_starttime.tv_usec); 11471541Srgrimes rt->tstamp = time; 11481541Srgrimes nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; 11491541Srgrimes} 115013416Sphk#endif /* NFS_NOSERVER */ 1151