nfs_nfsiod.c revision 22521
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 * 3622521Sdyson * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 3721673Sjkh * $FreeBSD: head/sys/nfsclient/nfs_nfsiod.c 22521 1997-02-10 02:22:35Z dyson $ 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#ifndef NFS_NOSERVER 10113416Sphkint nfsd_waiting = 0; 10213416Sphkstatic struct nfsdrt nfsdrt; 10313416Sphkstatic int nfs_numnfsd = 0; 10413416Sphkstatic int notstarted = 1; 10513416Sphkstatic int modify_flag = 0; 10612457Sbdestatic void nfsd_rt __P((int sotype, struct nfsrv_descript *nd, 10712457Sbde int cacherep)); 10812911Sphkstatic int nfssvc_addsock __P((struct file *,struct mbuf *)); 10912911Sphkstatic int nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *)); 1101541Srgrimes/* 1111541Srgrimes * NFS server system calls 1121541Srgrimes * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 1131541Srgrimes */ 1141541Srgrimes 1151541Srgrimes/* 1161541Srgrimes * Get file handle system call 1171541Srgrimes */ 11812274Sbde#ifndef _SYS_SYSPROTO_H_ 1191541Srgrimesstruct getfh_args { 1201541Srgrimes char *fname; 1211541Srgrimes fhandle_t *fhp; 1221541Srgrimes}; 12312274Sbde#endif 1241549Srgrimesint 1251541Srgrimesgetfh(p, uap, retval) 1261541Srgrimes struct proc *p; 1271541Srgrimes register struct getfh_args *uap; 1281541Srgrimes int *retval; 1291541Srgrimes{ 1301541Srgrimes register struct vnode *vp; 1311541Srgrimes fhandle_t fh; 1321541Srgrimes int error; 1331541Srgrimes struct nameidata nd; 1341541Srgrimes 1351541Srgrimes /* 1361541Srgrimes * Must be super user 1371541Srgrimes */ 1383305Sphk error = suser(p->p_ucred, &p->p_acflag); 1393305Sphk if(error) 1401541Srgrimes return (error); 1411541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 1423305Sphk error = namei(&nd); 1433305Sphk if (error) 1441541Srgrimes return (error); 1451541Srgrimes vp = nd.ni_vp; 1461541Srgrimes bzero((caddr_t)&fh, sizeof(fh)); 1471541Srgrimes fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1481541Srgrimes error = VFS_VPTOFH(vp, &fh.fh_fid); 1491541Srgrimes vput(vp); 1501541Srgrimes if (error) 1511541Srgrimes return (error); 1521541Srgrimes error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 1531541Srgrimes return (error); 1541541Srgrimes} 1551541Srgrimes 15613416Sphk#endif /* NFS_NOSERVER */ 1571541Srgrimes/* 1581541Srgrimes * Nfs server psuedo system call for the nfsd's 1591541Srgrimes * Based on the flag value it either: 1601541Srgrimes * - adds a socket to the selection list 1611541Srgrimes * - remains in the kernel as an nfsd 1621541Srgrimes * - remains in the kernel as an nfsiod 1631541Srgrimes */ 16412274Sbde#ifndef _SYS_SYSPROTO_H_ 1651541Srgrimesstruct nfssvc_args { 1661541Srgrimes int flag; 1671541Srgrimes caddr_t argp; 1681541Srgrimes}; 16912274Sbde#endif 1701549Srgrimesint 1711541Srgrimesnfssvc(p, uap, retval) 1721541Srgrimes struct proc *p; 1731541Srgrimes register struct nfssvc_args *uap; 1741541Srgrimes int *retval; 1751541Srgrimes{ 17613416Sphk#ifndef NFS_NOSERVER 1771541Srgrimes struct nameidata nd; 1781541Srgrimes struct file *fp; 1791541Srgrimes struct mbuf *nam; 1801541Srgrimes struct nfsd_args nfsdarg; 1811541Srgrimes struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; 1821541Srgrimes struct nfsd_cargs ncd; 1831541Srgrimes struct nfsd *nfsd; 1841541Srgrimes struct nfssvc_sock *slp; 1853664Sphk struct nfsuid *nuidp; 1861541Srgrimes struct nfsmount *nmp; 18713416Sphk#endif /* NFS_NOSERVER */ 1881541Srgrimes int error; 1891541Srgrimes 1901541Srgrimes /* 1911541Srgrimes * Must be super user 1921541Srgrimes */ 1933305Sphk error = suser(p->p_ucred, &p->p_acflag); 1943305Sphk if(error) 1951541Srgrimes return (error); 1963664Sphk while (nfssvc_sockhead_flag & SLP_INIT) { 1973664Sphk nfssvc_sockhead_flag |= SLP_WANTINIT; 1981541Srgrimes (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); 1991541Srgrimes } 2001541Srgrimes if (uap->flag & NFSSVC_BIOD) 2011541Srgrimes error = nfssvc_iod(p); 20213416Sphk#ifdef NFS_NOSERVER 20313416Sphk else 20413416Sphk error = ENXIO; 20513416Sphk#else /* !NFS_NOSERVER */ 2061541Srgrimes else if (uap->flag & NFSSVC_MNTD) { 2073305Sphk error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); 2083305Sphk if (error) 2091541Srgrimes return (error); 2101541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 2111541Srgrimes ncd.ncd_dirp, p); 2123305Sphk error = namei(&nd); 2133305Sphk if (error) 2141541Srgrimes return (error); 2151541Srgrimes if ((nd.ni_vp->v_flag & VROOT) == 0) 2161541Srgrimes error = EINVAL; 2171541Srgrimes nmp = VFSTONFS(nd.ni_vp->v_mount); 2181541Srgrimes vput(nd.ni_vp); 2191541Srgrimes if (error) 2201541Srgrimes return (error); 2211541Srgrimes if ((nmp->nm_flag & NFSMNT_MNTD) && 2221541Srgrimes (uap->flag & NFSSVC_GOTAUTH) == 0) 2231541Srgrimes return (0); 2241541Srgrimes nmp->nm_flag |= NFSMNT_MNTD; 2251541Srgrimes error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, 2261541Srgrimes uap->argp, p); 2271541Srgrimes } else if (uap->flag & NFSSVC_ADDSOCK) { 2283305Sphk error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); 2293305Sphk if (error) 2301541Srgrimes return (error); 2313305Sphk error = getsock(p->p_fd, nfsdarg.sock, &fp); 2323305Sphk if (error) 2331541Srgrimes return (error); 2341541Srgrimes /* 2351541Srgrimes * Get the client address for connected sockets. 2361541Srgrimes */ 2371541Srgrimes if (nfsdarg.name == NULL || nfsdarg.namelen == 0) 2381541Srgrimes nam = (struct mbuf *)0; 2393305Sphk else { 2403305Sphk error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, 2413305Sphk MT_SONAME); 2423305Sphk if (error) 2433305Sphk return (error); 2443305Sphk } 2451541Srgrimes error = nfssvc_addsock(fp, nam); 2461541Srgrimes } else { 2473305Sphk error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); 2483305Sphk if (error) 2491541Srgrimes return (error); 2503305Sphk if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) && 2519336Sdfr (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { 2529336Sdfr slp = nfsd->nfsd_slp; 2531541Srgrimes 2541541Srgrimes /* 2551541Srgrimes * First check to see if another nfsd has already 2561541Srgrimes * added this credential. 2571541Srgrimes */ 2589336Sdfr for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; 2593664Sphk nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 2609336Sdfr if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid && 2619336Sdfr (!nfsd->nfsd_nd->nd_nam2 || 2629336Sdfr netaddr_match(NU_NETFAM(nuidp), 2639336Sdfr &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) 2641541Srgrimes break; 2651541Srgrimes } 2669336Sdfr if (nuidp) { 2679336Sdfr nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr); 2689336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 2699336Sdfr } else { 2701541Srgrimes /* 2711541Srgrimes * Nope, so we will. 2721541Srgrimes */ 2731541Srgrimes if (slp->ns_numuids < nuidhash_max) { 2741541Srgrimes slp->ns_numuids++; 2751541Srgrimes nuidp = (struct nfsuid *) 2761541Srgrimes malloc(sizeof (struct nfsuid), M_NFSUID, 2771541Srgrimes M_WAITOK); 2781541Srgrimes } else 2791541Srgrimes nuidp = (struct nfsuid *)0; 2801541Srgrimes if ((slp->ns_flag & SLP_VALID) == 0) { 2811541Srgrimes if (nuidp) 2821541Srgrimes free((caddr_t)nuidp, M_NFSUID); 2831541Srgrimes } else { 2841541Srgrimes if (nuidp == (struct nfsuid *)0) { 2853664Sphk nuidp = slp->ns_uidlruhead.tqh_first; 2863664Sphk LIST_REMOVE(nuidp, nu_hash); 2873664Sphk TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, 2883664Sphk nu_lru); 2899336Sdfr if (nuidp->nu_flag & NU_NAM) 2909336Sdfr m_freem(nuidp->nu_nam); 2911541Srgrimes } 2929336Sdfr nuidp->nu_flag = 0; 2931541Srgrimes nuidp->nu_cr = nsd->nsd_cr; 2941541Srgrimes if (nuidp->nu_cr.cr_ngroups > NGROUPS) 2959336Sdfr nuidp->nu_cr.cr_ngroups = NGROUPS; 2961541Srgrimes nuidp->nu_cr.cr_ref = 1; 2979336Sdfr nuidp->nu_timestamp = nsd->nsd_timestamp; 2989336Sdfr nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl; 2999336Sdfr /* 3009336Sdfr * and save the session key in nu_key. 3019336Sdfr */ 3029336Sdfr bcopy(nsd->nsd_key, nuidp->nu_key, 3039336Sdfr sizeof (nsd->nsd_key)); 3049336Sdfr if (nfsd->nfsd_nd->nd_nam2) { 3059336Sdfr struct sockaddr_in *saddr; 3069336Sdfr 3079336Sdfr saddr = mtod(nfsd->nfsd_nd->nd_nam2, 3089336Sdfr struct sockaddr_in *); 3099336Sdfr switch (saddr->sin_family) { 3109336Sdfr case AF_INET: 3119336Sdfr nuidp->nu_flag |= NU_INETADDR; 3129336Sdfr nuidp->nu_inetaddr = 3139336Sdfr saddr->sin_addr.s_addr; 3149336Sdfr break; 3159336Sdfr case AF_ISO: 3169336Sdfr default: 3179336Sdfr nuidp->nu_flag |= NU_NAM; 3189336Sdfr nuidp->nu_nam = m_copym( 3199336Sdfr nfsd->nfsd_nd->nd_nam2, 0, 3209336Sdfr M_COPYALL, M_WAIT); 3219336Sdfr break; 3229336Sdfr }; 3239336Sdfr } 3243664Sphk TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, 3253664Sphk nu_lru); 3263664Sphk LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), 3273664Sphk nuidp, nu_hash); 3289336Sdfr nfsrv_setcred(&nuidp->nu_cr, 3299336Sdfr &nfsd->nfsd_nd->nd_cr); 3309336Sdfr nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; 3311541Srgrimes } 3321541Srgrimes } 3331541Srgrimes } 3341541Srgrimes if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) 3359336Sdfr nfsd->nfsd_flag |= NFSD_AUTHFAIL; 3361541Srgrimes error = nfssvc_nfsd(nsd, uap->argp, p); 3371541Srgrimes } 33813416Sphk#endif /* NFS_NOSERVER */ 3391541Srgrimes if (error == EINTR || error == ERESTART) 3401541Srgrimes error = 0; 3411541Srgrimes return (error); 3421541Srgrimes} 3431541Srgrimes 34413416Sphk#ifndef NFS_NOSERVER 3451541Srgrimes/* 3461541Srgrimes * Adds a socket to the list for servicing by nfsds. 3471541Srgrimes */ 34812911Sphkstatic int 3491541Srgrimesnfssvc_addsock(fp, mynam) 3501541Srgrimes struct file *fp; 3511541Srgrimes struct mbuf *mynam; 3521541Srgrimes{ 3531541Srgrimes register struct mbuf *m; 3541541Srgrimes register int siz; 3551541Srgrimes register struct nfssvc_sock *slp; 3561541Srgrimes register struct socket *so; 3571541Srgrimes struct nfssvc_sock *tslp; 3581541Srgrimes int error, s; 3591541Srgrimes 3601541Srgrimes so = (struct socket *)fp->f_data; 3611541Srgrimes tslp = (struct nfssvc_sock *)0; 3621541Srgrimes /* 3631541Srgrimes * Add it to the list, as required. 3641541Srgrimes */ 3651541Srgrimes if (so->so_proto->pr_protocol == IPPROTO_UDP) { 3661541Srgrimes tslp = nfs_udpsock; 3671541Srgrimes if (tslp->ns_flag & SLP_VALID) { 3681541Srgrimes m_freem(mynam); 3691541Srgrimes return (EPERM); 3701541Srgrimes } 3711541Srgrimes#ifdef ISO 3721541Srgrimes } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) { 3731541Srgrimes tslp = nfs_cltpsock; 3741541Srgrimes if (tslp->ns_flag & SLP_VALID) { 3751541Srgrimes m_freem(mynam); 3761541Srgrimes return (EPERM); 3771541Srgrimes } 3781541Srgrimes#endif /* ISO */ 3791541Srgrimes } 3801541Srgrimes if (so->so_type == SOCK_STREAM) 3811541Srgrimes siz = NFS_MAXPACKET + sizeof (u_long); 3821541Srgrimes else 3831541Srgrimes siz = NFS_MAXPACKET; 3848876Srgrimes error = soreserve(so, siz, siz); 3853305Sphk if (error) { 3861541Srgrimes m_freem(mynam); 3871541Srgrimes return (error); 3881541Srgrimes } 3891541Srgrimes 3901541Srgrimes /* 3911541Srgrimes * Set protocol specific options { for now TCP only } and 3921541Srgrimes * reserve some space. For datagram sockets, this can get called 3931541Srgrimes * repeatedly for the same socket, but that isn't harmful. 3941541Srgrimes */ 3951541Srgrimes if (so->so_type == SOCK_STREAM) { 3961541Srgrimes MGET(m, M_WAIT, MT_SOOPTS); 3971541Srgrimes *mtod(m, int *) = 1; 3981541Srgrimes m->m_len = sizeof(int); 3991541Srgrimes sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 4001541Srgrimes } 4011541Srgrimes if (so->so_proto->pr_domain->dom_family == AF_INET && 4021541Srgrimes so->so_proto->pr_protocol == IPPROTO_TCP) { 4031541Srgrimes MGET(m, M_WAIT, MT_SOOPTS); 4041541Srgrimes *mtod(m, int *) = 1; 4051541Srgrimes m->m_len = sizeof(int); 4061541Srgrimes sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 4071541Srgrimes } 4081541Srgrimes so->so_rcv.sb_flags &= ~SB_NOINTR; 4091541Srgrimes so->so_rcv.sb_timeo = 0; 4101541Srgrimes so->so_snd.sb_flags &= ~SB_NOINTR; 4111541Srgrimes so->so_snd.sb_timeo = 0; 4121541Srgrimes if (tslp) 4131541Srgrimes slp = tslp; 4141541Srgrimes else { 4151541Srgrimes slp = (struct nfssvc_sock *) 4161541Srgrimes malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); 4171541Srgrimes bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); 4183664Sphk TAILQ_INIT(&slp->ns_uidlruhead); 4193664Sphk TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); 4201541Srgrimes } 4211541Srgrimes slp->ns_so = so; 4221541Srgrimes slp->ns_nam = mynam; 4231541Srgrimes fp->f_count++; 4241541Srgrimes slp->ns_fp = fp; 4251541Srgrimes s = splnet(); 4261541Srgrimes so->so_upcallarg = (caddr_t)slp; 4271541Srgrimes so->so_upcall = nfsrv_rcv; 4281541Srgrimes slp->ns_flag = (SLP_VALID | SLP_NEEDQ); 4291541Srgrimes nfsrv_wakenfsd(slp); 4301541Srgrimes splx(s); 4311541Srgrimes return (0); 4321541Srgrimes} 4331541Srgrimes 4341541Srgrimes/* 4351541Srgrimes * Called by nfssvc() for nfsds. Just loops around servicing rpc requests 4361541Srgrimes * until it is killed by a signal. 4371541Srgrimes */ 43812911Sphkstatic int 4391541Srgrimesnfssvc_nfsd(nsd, argp, p) 4401541Srgrimes struct nfsd_srvargs *nsd; 4411541Srgrimes caddr_t argp; 4421541Srgrimes struct proc *p; 4431541Srgrimes{ 4449336Sdfr register struct mbuf *m; 4451541Srgrimes register int siz; 4461541Srgrimes register struct nfssvc_sock *slp; 4471541Srgrimes register struct socket *so; 4481541Srgrimes register int *solockp; 4499336Sdfr struct nfsd *nfsd = nsd->nsd_nfsd; 4509336Sdfr struct nfsrv_descript *nd = NULL; 4519336Sdfr struct mbuf *mreq; 4529336Sdfr int error = 0, cacherep, s, sotype, writes_todo; 4539336Sdfr u_quad_t cur_usec; 4541541Srgrimes 4559336Sdfr#ifndef nolint 4569336Sdfr cacherep = RC_DOIT; 4579336Sdfr writes_todo = 0; 4589336Sdfr#endif 4591541Srgrimes s = splnet(); 4609336Sdfr if (nfsd == (struct nfsd *)0) { 4619336Sdfr nsd->nsd_nfsd = nfsd = (struct nfsd *) 4621541Srgrimes malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK); 4639336Sdfr bzero((caddr_t)nfsd, sizeof (struct nfsd)); 4649336Sdfr nfsd->nfsd_procp = p; 4659336Sdfr TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); 4661541Srgrimes nfs_numnfsd++; 4671541Srgrimes } 4681541Srgrimes /* 4691541Srgrimes * Loop getting rpc requests until SIGKILL. 4701541Srgrimes */ 4711541Srgrimes for (;;) { 4729336Sdfr if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { 4739336Sdfr while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 4743664Sphk (nfsd_head_flag & NFSD_CHECKSLP) == 0) { 4759336Sdfr nfsd->nfsd_flag |= NFSD_WAITING; 4761541Srgrimes nfsd_waiting++; 4779336Sdfr error = tsleep((caddr_t)nfsd, PSOCK | PCATCH, 4789336Sdfr "nfsd", 0); 4791541Srgrimes nfsd_waiting--; 4801541Srgrimes if (error) 4811541Srgrimes goto done; 4821541Srgrimes } 4839336Sdfr if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && 4843664Sphk (nfsd_head_flag & NFSD_CHECKSLP) != 0) { 4853664Sphk for (slp = nfssvc_sockhead.tqh_first; slp != 0; 4863664Sphk slp = slp->ns_chain.tqe_next) { 4871541Srgrimes if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) 4881541Srgrimes == (SLP_VALID | SLP_DOREC)) { 4891541Srgrimes slp->ns_flag &= ~SLP_DOREC; 4901541Srgrimes slp->ns_sref++; 4919336Sdfr nfsd->nfsd_slp = slp; 4921541Srgrimes break; 4931541Srgrimes } 4941541Srgrimes } 4953664Sphk if (slp == 0) 4963664Sphk nfsd_head_flag &= ~NFSD_CHECKSLP; 4971541Srgrimes } 4989336Sdfr if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0) 4991541Srgrimes continue; 5001541Srgrimes if (slp->ns_flag & SLP_VALID) { 5011541Srgrimes if (slp->ns_flag & SLP_DISCONN) 5021541Srgrimes nfsrv_zapsock(slp); 5031541Srgrimes else if (slp->ns_flag & SLP_NEEDQ) { 5041541Srgrimes slp->ns_flag &= ~SLP_NEEDQ; 5051541Srgrimes (void) nfs_sndlock(&slp->ns_solock, 5061541Srgrimes (struct nfsreq *)0); 5071541Srgrimes nfsrv_rcv(slp->ns_so, (caddr_t)slp, 5081541Srgrimes M_WAIT); 5091541Srgrimes nfs_sndunlock(&slp->ns_solock); 5101541Srgrimes } 5119336Sdfr error = nfsrv_dorec(slp, nfsd, &nd); 5129336Sdfr cur_usec = (u_quad_t)time.tv_sec * 1000000 + 5139336Sdfr (u_quad_t)time.tv_usec; 5149336Sdfr if (error && slp->ns_tq.lh_first && 5159336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 5169336Sdfr error = 0; 5179336Sdfr cacherep = RC_DOIT; 5189336Sdfr writes_todo = 1; 5199336Sdfr } else 5209336Sdfr writes_todo = 0; 5219336Sdfr nfsd->nfsd_flag |= NFSD_REQINPROG; 5221541Srgrimes } 5231541Srgrimes } else { 5241541Srgrimes error = 0; 5259336Sdfr slp = nfsd->nfsd_slp; 5261541Srgrimes } 5271541Srgrimes if (error || (slp->ns_flag & SLP_VALID) == 0) { 5289336Sdfr if (nd) { 5299336Sdfr free((caddr_t)nd, M_NFSRVDESC); 5309336Sdfr nd = NULL; 5319336Sdfr } 5329336Sdfr nfsd->nfsd_slp = (struct nfssvc_sock *)0; 5339336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 5341541Srgrimes nfsrv_slpderef(slp); 5351541Srgrimes continue; 5361541Srgrimes } 5371541Srgrimes splx(s); 5381541Srgrimes so = slp->ns_so; 5391541Srgrimes sotype = so->so_type; 5401541Srgrimes if (so->so_proto->pr_flags & PR_CONNREQUIRED) 5411541Srgrimes solockp = &slp->ns_solock; 5421541Srgrimes else 5431541Srgrimes solockp = (int *)0; 5449336Sdfr if (nd) { 5459336Sdfr nd->nd_starttime = time; 5469336Sdfr if (nd->nd_nam2) 5479336Sdfr nd->nd_nam = nd->nd_nam2; 5489336Sdfr else 5499336Sdfr nd->nd_nam = slp->ns_nam; 5501541Srgrimes 5519336Sdfr /* 5529336Sdfr * Check to see if authorization is needed. 5539336Sdfr */ 5549336Sdfr if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { 5559336Sdfr nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; 5569336Sdfr nsd->nsd_haddr = mtod(nd->nd_nam, 5579336Sdfr struct sockaddr_in *)->sin_addr.s_addr; 5589336Sdfr nsd->nsd_authlen = nfsd->nfsd_authlen; 5599336Sdfr nsd->nsd_verflen = nfsd->nfsd_verflen; 5609336Sdfr if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr, 5619336Sdfr nfsd->nfsd_authlen) && 5629336Sdfr !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr, 5639336Sdfr nfsd->nfsd_verflen) && 5649336Sdfr !copyout((caddr_t)nsd, argp, sizeof (*nsd))) 5659336Sdfr return (ENEEDAUTH); 5669336Sdfr cacherep = RC_DROPIT; 5679336Sdfr } else 5689336Sdfr cacherep = nfsrv_getcache(nd, slp, &mreq); 5691541Srgrimes 5709336Sdfr /* 5719336Sdfr * Check for just starting up for NQNFS and send 5729336Sdfr * fake "try again later" replies to the NQNFS clients. 5739336Sdfr */ 5749336Sdfr if (notstarted && nqnfsstarttime <= time.tv_sec) { 5751541Srgrimes if (modify_flag) { 5761541Srgrimes nqnfsstarttime = time.tv_sec + nqsrv_writeslack; 5771541Srgrimes modify_flag = 0; 5781541Srgrimes } else 5791541Srgrimes notstarted = 0; 5809336Sdfr } 5819336Sdfr if (notstarted) { 5829336Sdfr if ((nd->nd_flag & ND_NQNFS) == 0) 5831541Srgrimes cacherep = RC_DROPIT; 5841541Srgrimes else if (nd->nd_procnum != NFSPROC_WRITE) { 5851541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 5861541Srgrimes nd->nd_repstat = NQNFS_TRYLATER; 5871541Srgrimes cacherep = RC_DOIT; 5881541Srgrimes } else 5891541Srgrimes modify_flag = 1; 5909336Sdfr } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { 5919336Sdfr nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; 5921541Srgrimes nd->nd_procnum = NFSPROC_NOOP; 5939336Sdfr nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 5941541Srgrimes cacherep = RC_DOIT; 5959336Sdfr } 5961541Srgrimes } 5971541Srgrimes 5989336Sdfr /* 5999336Sdfr * Loop to get all the write rpc relies that have been 6009336Sdfr * gathered together. 6019336Sdfr */ 6029336Sdfr do { 6039336Sdfr switch (cacherep) { 6049336Sdfr case RC_DOIT: 6059336Sdfr if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && 6069336Sdfr nfsrvw_procrastinate > 0 && !notstarted)) 6079336Sdfr error = nfsrv_writegather(&nd, slp, 6089336Sdfr nfsd->nfsd_procp, &mreq); 6099336Sdfr else 6109336Sdfr error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, 6119336Sdfr slp, nfsd->nfsd_procp, &mreq); 6129336Sdfr if (mreq == NULL) 6139336Sdfr break; 6141541Srgrimes if (error) { 6151541Srgrimes if (nd->nd_procnum != NQNFSPROC_VACATED) 6161541Srgrimes nfsstats.srv_errs++; 6179336Sdfr nfsrv_updatecache(nd, FALSE, mreq); 6189336Sdfr if (nd->nd_nam2) 6199336Sdfr m_freem(nd->nd_nam2); 6201541Srgrimes break; 6211541Srgrimes } 6221541Srgrimes nfsstats.srvrpccnt[nd->nd_procnum]++; 6239336Sdfr nfsrv_updatecache(nd, TRUE, mreq); 6241541Srgrimes nd->nd_mrep = (struct mbuf *)0; 6259336Sdfr case RC_REPLY: 6261541Srgrimes m = mreq; 6271541Srgrimes siz = 0; 6281541Srgrimes while (m) { 6291541Srgrimes siz += m->m_len; 6301541Srgrimes m = m->m_next; 6311541Srgrimes } 6321541Srgrimes if (siz <= 0 || siz > NFS_MAXPACKET) { 6331541Srgrimes printf("mbuf siz=%d\n",siz); 6341541Srgrimes panic("Bad nfs svc reply"); 6351541Srgrimes } 6361541Srgrimes m = mreq; 6371541Srgrimes m->m_pkthdr.len = siz; 6381541Srgrimes m->m_pkthdr.rcvif = (struct ifnet *)0; 6391541Srgrimes /* 6401541Srgrimes * For stream protocols, prepend a Sun RPC 6411541Srgrimes * Record Mark. 6421541Srgrimes */ 6431541Srgrimes if (sotype == SOCK_STREAM) { 6441541Srgrimes M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 6451541Srgrimes *mtod(m, u_long *) = htonl(0x80000000 | siz); 6461541Srgrimes } 6471541Srgrimes if (solockp) 6481541Srgrimes (void) nfs_sndlock(solockp, (struct nfsreq *)0); 6491541Srgrimes if (slp->ns_flag & SLP_VALID) 6509336Sdfr error = nfs_send(so, nd->nd_nam2, m, NULL); 6511541Srgrimes else { 6521541Srgrimes error = EPIPE; 6531541Srgrimes m_freem(m); 6541541Srgrimes } 6551541Srgrimes if (nfsrtton) 6569336Sdfr nfsd_rt(sotype, nd, cacherep); 6579336Sdfr if (nd->nd_nam2) 6589336Sdfr MFREE(nd->nd_nam2, m); 6591541Srgrimes if (nd->nd_mrep) 6601541Srgrimes m_freem(nd->nd_mrep); 6611541Srgrimes if (error == EPIPE) 6621541Srgrimes nfsrv_zapsock(slp); 6631541Srgrimes if (solockp) 6641541Srgrimes nfs_sndunlock(solockp); 6651541Srgrimes if (error == EINTR || error == ERESTART) { 6669336Sdfr free((caddr_t)nd, M_NFSRVDESC); 6671541Srgrimes nfsrv_slpderef(slp); 6681541Srgrimes s = splnet(); 6691541Srgrimes goto done; 6701541Srgrimes } 6711541Srgrimes break; 6729336Sdfr case RC_DROPIT: 6731541Srgrimes if (nfsrtton) 6749336Sdfr nfsd_rt(sotype, nd, cacherep); 6751541Srgrimes m_freem(nd->nd_mrep); 6769336Sdfr m_freem(nd->nd_nam2); 6771541Srgrimes break; 6789336Sdfr }; 6799336Sdfr if (nd) { 6809336Sdfr FREE((caddr_t)nd, M_NFSRVDESC); 6819336Sdfr nd = NULL; 6829336Sdfr } 6839336Sdfr 6849336Sdfr /* 6859336Sdfr * Check to see if there are outstanding writes that 6869336Sdfr * need to be serviced. 6879336Sdfr */ 6889336Sdfr cur_usec = (u_quad_t)time.tv_sec * 1000000 + 6899336Sdfr (u_quad_t)time.tv_usec; 6909336Sdfr s = splsoftclock(); 6919336Sdfr if (slp->ns_tq.lh_first && 6929336Sdfr slp->ns_tq.lh_first->nd_time <= cur_usec) { 6939336Sdfr cacherep = RC_DOIT; 6949336Sdfr writes_todo = 1; 6959336Sdfr } else 6969336Sdfr writes_todo = 0; 6979336Sdfr splx(s); 6989336Sdfr } while (writes_todo); 6991541Srgrimes s = splnet(); 7009336Sdfr if (nfsrv_dorec(slp, nfsd, &nd)) { 7019336Sdfr nfsd->nfsd_flag &= ~NFSD_REQINPROG; 7029336Sdfr nfsd->nfsd_slp = NULL; 7031541Srgrimes nfsrv_slpderef(slp); 7041541Srgrimes } 7051541Srgrimes } 7061541Srgrimesdone: 7079336Sdfr TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); 7081541Srgrimes splx(s); 7099336Sdfr free((caddr_t)nfsd, M_NFSD); 7101541Srgrimes nsd->nsd_nfsd = (struct nfsd *)0; 7111541Srgrimes if (--nfs_numnfsd == 0) 7121541Srgrimes nfsrv_init(TRUE); /* Reinitialize everything */ 7131541Srgrimes return (error); 7141541Srgrimes} 71513416Sphk#endif /* NFS_NOSERVER */ 7161541Srgrimes 71719449Sdfrint nfs_defect = 0; 71819449SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); 71919449Sdfr 7201541Srgrimes/* 7211541Srgrimes * Asynchronous I/O daemons for client nfs. 7221541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache. 7231541Srgrimes * Never returns unless it fails or gets killed. 7241541Srgrimes */ 72512911Sphkstatic int 7261541Srgrimesnfssvc_iod(p) 7271541Srgrimes struct proc *p; 7281541Srgrimes{ 7299336Sdfr register struct buf *bp, *nbp; 7301541Srgrimes register int i, myiod; 7319336Sdfr struct vnode *vp; 73219449Sdfr struct nfsmount *nmp; 7339336Sdfr int error = 0, s; 7341541Srgrimes 7351541Srgrimes /* 7361541Srgrimes * Assign my position or return error if too many already running 7371541Srgrimes */ 7381541Srgrimes myiod = -1; 7391541Srgrimes for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 7401541Srgrimes if (nfs_asyncdaemon[i] == 0) { 7411541Srgrimes nfs_asyncdaemon[i]++; 7421541Srgrimes myiod = i; 7431541Srgrimes break; 7441541Srgrimes } 7451541Srgrimes if (myiod == -1) 7461541Srgrimes return (EBUSY); 7471541Srgrimes nfs_numasync++; 7481541Srgrimes /* 7491541Srgrimes * Just loop around doin our stuff until SIGKILL 7501541Srgrimes */ 7511541Srgrimes for (;;) { 75219449Sdfr while (((nmp = nfs_iodmount[myiod]) == NULL 75319449Sdfr || nmp->nm_bufq.tqh_first == NULL) 75419449Sdfr && error == 0) { 75519449Sdfr if (nmp) 75619449Sdfr nmp->nm_bufqiods--; 7579336Sdfr nfs_iodwant[myiod] = p; 75819449Sdfr nfs_iodmount[myiod] = NULL; 7599336Sdfr error = tsleep((caddr_t)&nfs_iodwant[myiod], 7609336Sdfr PWAIT | PCATCH, "nfsidl", 0); 7619336Sdfr } 76219449Sdfr if (error) { 76319449Sdfr nfs_asyncdaemon[myiod] = 0; 76419449Sdfr if (nmp) nmp->nm_bufqiods--; 76519449Sdfr nfs_iodmount[myiod] = NULL; 76619449Sdfr nfs_numasync--; 76719449Sdfr return (error); 76819449Sdfr } 76919449Sdfr while ((bp = nmp->nm_bufq.tqh_first) != NULL) { 7709336Sdfr /* Take one off the front of the list */ 77119449Sdfr TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); 77219449Sdfr nmp->nm_bufqlen--; 77319449Sdfr if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) { 77419449Sdfr nmp->nm_bufqwant = FALSE; 77519449Sdfr wakeup(&nmp->nm_bufq); 77619449Sdfr } 7779336Sdfr if (bp->b_flags & B_READ) 7789336Sdfr (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); 77919449Sdfr else 7809336Sdfr (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); 78119449Sdfr 78219449Sdfr /* 78319449Sdfr * If there are more than one iod on this mount, then defect 78419449Sdfr * so that the iods can be shared out fairly between the mounts 78519449Sdfr */ 78619449Sdfr if (nfs_defect && nmp->nm_bufqiods > 1) { 78719449Sdfr NFS_DPF(ASYNCIO, 78819449Sdfr ("nfssvc_iod: iod %d defecting from mount %p\n", 78919449Sdfr myiod, nmp)); 79019449Sdfr nfs_iodmount[myiod] = NULL; 79119449Sdfr nmp->nm_bufqiods--; 79219449Sdfr break; 79319449Sdfr } 7949336Sdfr } 7951541Srgrimes } 7961541Srgrimes} 7971541Srgrimes 7981541Srgrimes/* 7991541Srgrimes * Shut down a socket associated with an nfssvc_sock structure. 8001541Srgrimes * Should be called with the send lock set, if required. 8011541Srgrimes * The trick here is to increment the sref at the start, so that the nfsds 8021541Srgrimes * will stop using it and clear ns_flag at the end so that it will not be 8031541Srgrimes * reassigned during cleanup. 8041541Srgrimes */ 80512911Sphkstatic void 8061541Srgrimesnfsrv_zapsock(slp) 8071541Srgrimes register struct nfssvc_sock *slp; 8081541Srgrimes{ 8093664Sphk register struct nfsuid *nuidp, *nnuidp; 8109336Sdfr register struct nfsrv_descript *nwp, *nnwp; 8111541Srgrimes struct socket *so; 8121541Srgrimes struct file *fp; 8131541Srgrimes struct mbuf *m; 8149336Sdfr int s; 8151541Srgrimes 8161541Srgrimes slp->ns_flag &= ~SLP_ALLFLAGS; 8173305Sphk fp = slp->ns_fp; 8183305Sphk if (fp) { 8191541Srgrimes slp->ns_fp = (struct file *)0; 8201541Srgrimes so = slp->ns_so; 8211541Srgrimes so->so_upcall = NULL; 8221541Srgrimes soshutdown(so, 2); 8231541Srgrimes closef(fp, (struct proc *)0); 8241541Srgrimes if (slp->ns_nam) 8251541Srgrimes MFREE(slp->ns_nam, m); 8261541Srgrimes m_freem(slp->ns_raw); 8271541Srgrimes m_freem(slp->ns_rec); 8283664Sphk for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; 8293664Sphk nuidp = nnuidp) { 8303664Sphk nnuidp = nuidp->nu_lru.tqe_next; 8313664Sphk LIST_REMOVE(nuidp, nu_hash); 8323664Sphk TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); 8339336Sdfr if (nuidp->nu_flag & NU_NAM) 8349336Sdfr m_freem(nuidp->nu_nam); 8353664Sphk free((caddr_t)nuidp, M_NFSUID); 8361541Srgrimes } 8379336Sdfr s = splsoftclock(); 8389336Sdfr for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { 8399336Sdfr nnwp = nwp->nd_tq.le_next; 8409336Sdfr LIST_REMOVE(nwp, nd_tq); 8419336Sdfr free((caddr_t)nwp, M_NFSRVDESC); 8429336Sdfr } 8439336Sdfr LIST_INIT(&slp->ns_tq); 8449336Sdfr splx(s); 8451541Srgrimes } 8461541Srgrimes} 8471541Srgrimes 8481541Srgrimes/* 8491541Srgrimes * Get an authorization string for the uid by having the mount_nfs sitting 8501541Srgrimes * on this mount point porpous out of the kernel and do it. 8511541Srgrimes */ 8521549Srgrimesint 8539336Sdfrnfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) 8541541Srgrimes register struct nfsmount *nmp; 8551541Srgrimes struct nfsreq *rep; 8561541Srgrimes struct ucred *cred; 8571541Srgrimes char **auth_str; 8581541Srgrimes int *auth_len; 8599336Sdfr char *verf_str; 8609336Sdfr int *verf_len; 8619336Sdfr NFSKERBKEY_T key; /* return session key */ 8621541Srgrimes{ 8631541Srgrimes int error = 0; 8641541Srgrimes 8651541Srgrimes while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) { 8661541Srgrimes nmp->nm_flag |= NFSMNT_WANTAUTH; 8671541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, 8681541Srgrimes "nfsauth1", 2 * hz); 8693305Sphk error = nfs_sigintr(nmp, rep, rep->r_procp); 8703305Sphk if (error) { 8711541Srgrimes nmp->nm_flag &= ~NFSMNT_WANTAUTH; 8721541Srgrimes return (error); 8731541Srgrimes } 8741541Srgrimes } 8751541Srgrimes nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH); 8761541Srgrimes nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); 8779336Sdfr nmp->nm_authlen = RPCAUTH_MAXSIZ; 8789336Sdfr nmp->nm_verfstr = verf_str; 8799336Sdfr nmp->nm_verflen = *verf_len; 8801541Srgrimes nmp->nm_authuid = cred->cr_uid; 8811541Srgrimes wakeup((caddr_t)&nmp->nm_authstr); 8821541Srgrimes 8831541Srgrimes /* 8841541Srgrimes * And wait for mount_nfs to do its stuff. 8851541Srgrimes */ 8861541Srgrimes while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) { 8871541Srgrimes (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, 8881541Srgrimes "nfsauth2", 2 * hz); 8891541Srgrimes error = nfs_sigintr(nmp, rep, rep->r_procp); 8901541Srgrimes } 8911541Srgrimes if (nmp->nm_flag & NFSMNT_AUTHERR) { 8921541Srgrimes nmp->nm_flag &= ~NFSMNT_AUTHERR; 8931541Srgrimes error = EAUTH; 8941541Srgrimes } 8951541Srgrimes if (error) 8961541Srgrimes free((caddr_t)*auth_str, M_TEMP); 8971541Srgrimes else { 8981541Srgrimes *auth_len = nmp->nm_authlen; 8999336Sdfr *verf_len = nmp->nm_verflen; 9009336Sdfr bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); 9011541Srgrimes } 9021541Srgrimes nmp->nm_flag &= ~NFSMNT_HASAUTH; 9031541Srgrimes nmp->nm_flag |= NFSMNT_WAITAUTH; 9041541Srgrimes if (nmp->nm_flag & NFSMNT_WANTAUTH) { 9051541Srgrimes nmp->nm_flag &= ~NFSMNT_WANTAUTH; 9061541Srgrimes wakeup((caddr_t)&nmp->nm_authtype); 9071541Srgrimes } 9081541Srgrimes return (error); 9091541Srgrimes} 9101541Srgrimes 9111541Srgrimes/* 9129336Sdfr * Get a nickname authenticator and verifier. 9139336Sdfr */ 9149336Sdfrint 9159336Sdfrnfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len) 9169336Sdfr struct nfsmount *nmp; 9179336Sdfr struct ucred *cred; 9189336Sdfr char **auth_str; 9199336Sdfr int *auth_len; 9209336Sdfr char *verf_str; 9219336Sdfr int verf_len; 9229336Sdfr{ 9239336Sdfr register struct nfsuid *nuidp; 9249336Sdfr register u_long *nickp, *verfp; 9259336Sdfr struct timeval ktvin, ktvout; 9269336Sdfr 9279336Sdfr#ifdef DIAGNOSTIC 9289336Sdfr if (verf_len < (4 * NFSX_UNSIGNED)) 9299336Sdfr panic("nfs_getnickauth verf too small"); 9309336Sdfr#endif 9319336Sdfr for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first; 9329336Sdfr nuidp != 0; nuidp = nuidp->nu_hash.le_next) { 9339336Sdfr if (nuidp->nu_cr.cr_uid == cred->cr_uid) 9349336Sdfr break; 9359336Sdfr } 9369336Sdfr if (!nuidp || nuidp->nu_expire < time.tv_sec) 9379336Sdfr return (EACCES); 9389336Sdfr 9399336Sdfr /* 9409336Sdfr * Move to the end of the lru list (end of lru == most recently used). 9419336Sdfr */ 9429336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); 9439336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); 9449336Sdfr 9459336Sdfr nickp = (u_long *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); 9469336Sdfr *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); 9479336Sdfr *nickp = txdr_unsigned(nuidp->nu_nickname); 9489336Sdfr *auth_str = (char *)nickp; 9499336Sdfr *auth_len = 2 * NFSX_UNSIGNED; 9509336Sdfr 9519336Sdfr /* 9529336Sdfr * Now we must encrypt the verifier and package it up. 9539336Sdfr */ 9549336Sdfr verfp = (u_long *)verf_str; 9559336Sdfr *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); 9569336Sdfr if (time.tv_sec > nuidp->nu_timestamp.tv_sec || 9579336Sdfr (time.tv_sec == nuidp->nu_timestamp.tv_sec && 9589336Sdfr time.tv_usec > nuidp->nu_timestamp.tv_usec)) 9599336Sdfr nuidp->nu_timestamp = time; 9609336Sdfr else 9619336Sdfr nuidp->nu_timestamp.tv_usec++; 9629336Sdfr ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); 9639336Sdfr ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); 9649336Sdfr 9659336Sdfr /* 9669336Sdfr * Now encrypt the timestamp verifier in ecb mode using the session 9679336Sdfr * key. 9689336Sdfr */ 9699336Sdfr#ifdef NFSKERB 9709336Sdfr XXX 9719336Sdfr#endif 9729336Sdfr 9739336Sdfr *verfp++ = ktvout.tv_sec; 9749336Sdfr *verfp++ = ktvout.tv_usec; 9759336Sdfr *verfp = 0; 9769336Sdfr return (0); 9779336Sdfr} 9789336Sdfr 9799336Sdfr/* 9809336Sdfr * Save the current nickname in a hash list entry on the mount point. 9819336Sdfr */ 9829336Sdfrint 9839336Sdfrnfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) 9849336Sdfr register struct nfsmount *nmp; 9859336Sdfr struct ucred *cred; 9869336Sdfr int len; 9879336Sdfr NFSKERBKEY_T key; 9889336Sdfr struct mbuf **mdp; 9899336Sdfr char **dposp; 9909336Sdfr struct mbuf *mrep; 9919336Sdfr{ 9929336Sdfr register struct nfsuid *nuidp; 9939336Sdfr register u_long *tl; 9949336Sdfr register long t1; 9959336Sdfr struct mbuf *md = *mdp; 9969336Sdfr struct timeval ktvin, ktvout; 9979336Sdfr u_long nick; 9989336Sdfr char *dpos = *dposp, *cp2; 9999336Sdfr int deltasec, error = 0; 10009336Sdfr 10019336Sdfr if (len == (3 * NFSX_UNSIGNED)) { 10029336Sdfr nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); 10039336Sdfr ktvin.tv_sec = *tl++; 10049336Sdfr ktvin.tv_usec = *tl++; 10059336Sdfr nick = fxdr_unsigned(u_long, *tl); 10069336Sdfr 10079336Sdfr /* 10089336Sdfr * Decrypt the timestamp in ecb mode. 10099336Sdfr */ 10109336Sdfr#ifdef NFSKERB 10119336Sdfr XXX 10129336Sdfr#endif 10139336Sdfr ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); 10149336Sdfr ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); 10159336Sdfr deltasec = time.tv_sec - ktvout.tv_sec; 10169336Sdfr if (deltasec < 0) 10179336Sdfr deltasec = -deltasec; 10189336Sdfr /* 10199336Sdfr * If ok, add it to the hash list for the mount point. 10209336Sdfr */ 10219336Sdfr if (deltasec <= NFS_KERBCLOCKSKEW) { 10229336Sdfr if (nmp->nm_numuids < nuidhash_max) { 10239336Sdfr nmp->nm_numuids++; 10249336Sdfr nuidp = (struct nfsuid *) 10259336Sdfr malloc(sizeof (struct nfsuid), M_NFSUID, 10269336Sdfr M_WAITOK); 10279336Sdfr } else { 10289336Sdfr nuidp = nmp->nm_uidlruhead.tqh_first; 10299336Sdfr LIST_REMOVE(nuidp, nu_hash); 10309336Sdfr TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, 10319336Sdfr nu_lru); 10329336Sdfr } 10339336Sdfr nuidp->nu_flag = 0; 10349336Sdfr nuidp->nu_cr.cr_uid = cred->cr_uid; 10359336Sdfr nuidp->nu_expire = time.tv_sec + NFS_KERBTTL; 10369336Sdfr nuidp->nu_timestamp = ktvout; 10379336Sdfr nuidp->nu_nickname = nick; 10389336Sdfr bcopy(key, nuidp->nu_key, sizeof (key)); 10399336Sdfr TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, 10409336Sdfr nu_lru); 10419336Sdfr LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid), 10429336Sdfr nuidp, nu_hash); 10439336Sdfr } 10449336Sdfr } else 10459336Sdfr nfsm_adv(nfsm_rndup(len)); 10469336Sdfrnfsmout: 10479336Sdfr *mdp = md; 10489336Sdfr *dposp = dpos; 10499336Sdfr return (error); 10509336Sdfr} 10519336Sdfr 105213416Sphk#ifndef NFS_NOSERVER 105322521Sdyson 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