xref: /netbsd-src/sys/nfs/nfs_syscalls.c (revision ce2c90c7c172d95d2402a5b3d96d8f8e6d138a21)
1 /*	$NetBSD: nfs_syscalls.c,v 1.97 2006/10/12 01:32:47 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *	@(#)nfs_syscalls.c	8.5 (Berkeley) 3/30/95
35  */
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.97 2006/10/12 01:32:47 christos Exp $");
39 
40 #include "fs_nfs.h"
41 #include "opt_nfs.h"
42 #include "opt_nfsserver.h"
43 #include "opt_iso.h"
44 #include "opt_inet.h"
45 #include "opt_compat_netbsd.h"
46 
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/file.h>
51 #include <sys/stat.h>
52 #include <sys/vnode.h>
53 #include <sys/mount.h>
54 #include <sys/proc.h>
55 #include <sys/uio.h>
56 #include <sys/malloc.h>
57 #include <sys/buf.h>
58 #include <sys/mbuf.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61 #include <sys/signalvar.h>
62 #include <sys/domain.h>
63 #include <sys/protosw.h>
64 #include <sys/namei.h>
65 #include <sys/syslog.h>
66 #include <sys/filedesc.h>
67 #include <sys/kthread.h>
68 #include <sys/kauth.h>
69 
70 #include <sys/sa.h>
71 #include <sys/syscallargs.h>
72 
73 #include <netinet/in.h>
74 #include <netinet/tcp.h>
75 #ifdef ISO
76 #include <netiso/iso.h>
77 #endif
78 #include <nfs/xdr_subs.h>
79 #include <nfs/rpcv2.h>
80 #include <nfs/nfsproto.h>
81 #include <nfs/nfs.h>
82 #include <nfs/nfsm_subs.h>
83 #include <nfs/nfsrvcache.h>
84 #include <nfs/nfsmount.h>
85 #include <nfs/nfsnode.h>
86 #include <nfs/nqnfs.h>
87 #include <nfs/nfsrtt.h>
88 #include <nfs/nfs_var.h>
89 
90 /* Global defs. */
91 extern int32_t (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *,
92 						struct nfssvc_sock *,
93 						struct lwp *, struct mbuf **));
94 extern time_t nqnfsstarttime;
95 extern int nfsrvw_procrastinate;
96 
97 struct nfssvc_sock *nfs_udpsock;
98 #ifdef ISO
99 struct nfssvc_sock *nfs_cltpsock;
100 #endif
101 #ifdef INET6
102 struct nfssvc_sock *nfs_udp6sock;
103 #endif
104 int nuidhash_max = NFS_MAXUIDHASH;
105 int nfsd_waiting = 0;
106 #ifdef NFSSERVER
107 static int nfs_numnfsd = 0;
108 static int notstarted = 1;
109 static int modify_flag = 0;
110 static struct nfsdrt nfsdrt;
111 #endif
112 
113 #ifdef NFSSERVER
114 struct simplelock nfsd_slock = SIMPLELOCK_INITIALIZER;
115 struct nfssvc_sockhead nfssvc_sockhead;
116 struct nfssvc_sockhead nfssvc_sockpending;
117 struct nfsdhead nfsd_head;
118 struct nfsdidlehead nfsd_idle_head;
119 
120 int nfssvc_sockhead_flag;
121 int nfsd_head_flag;
122 #endif
123 
124 MALLOC_DEFINE(M_NFSUID, "NFS uid", "Nfs uid mapping structure");
125 
126 #ifdef NFS
127 struct nfs_iod nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
128 int nfs_niothreads = -1; /* == "0, and has never been set" */
129 #endif
130 
131 #ifdef NFSSERVER
132 static struct nfssvc_sock *nfsrv_sockalloc __P((void));
133 static void nfsrv_sockfree __P((struct nfssvc_sock *));
134 static void nfsd_rt __P((int, struct nfsrv_descript *, int));
135 #endif
136 
137 /*
138  * NFS server system calls
139  */
140 
141 
142 /*
143  * Nfs server pseudo system call for the nfsd's
144  * Based on the flag value it either:
145  * - adds a socket to the selection list
146  * - remains in the kernel as an nfsd
147  * - remains in the kernel as an nfsiod
148  */
149 int
150 sys_nfssvc(struct lwp *l, void *v, register_t *retval __unused)
151 {
152 	struct sys_nfssvc_args /* {
153 		syscallarg(int) flag;
154 		syscallarg(caddr_t) argp;
155 	} */ *uap = v;
156 	int error;
157 #ifdef NFS
158 	struct nameidata nd;
159 	struct nfsmount *nmp;
160 	struct nfsd_cargs ncd;
161 #endif
162 #ifdef NFSSERVER
163 	int s;
164 	struct file *fp;
165 	struct mbuf *nam;
166 	struct nfsd_args nfsdarg;
167 	struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
168 	struct nfsd *nfsd;
169 	struct nfssvc_sock *slp;
170 	struct nfsuid *nuidp;
171 #endif
172 
173 	/*
174 	 * Must be super user
175 	 */
176 	error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
177 	    &l->l_acflag);
178 	if (error)
179 		return (error);
180 
181 	/* Initialize NFS server / client shared data. */
182 	nfs_init();
183 
184 #ifdef NFSSERVER
185 	s = splsoftnet();
186 	simple_lock(&nfsd_slock);
187 	while (nfssvc_sockhead_flag & SLP_INIT) {
188 		nfssvc_sockhead_flag |= SLP_WANTINIT;
189 		(void) ltsleep(&nfssvc_sockhead, PSOCK, "nfsd init", 0,
190 		    &nfsd_slock);
191 	}
192 	simple_unlock(&nfsd_slock);
193 	splx(s);
194 #endif
195 	if (SCARG(uap, flag) & NFSSVC_BIOD) {
196 #if defined(NFS) && defined(COMPAT_14)
197 		error = nfssvc_iod(l);
198 #else
199 		error = ENOSYS;
200 #endif
201 	} else if (SCARG(uap, flag) & NFSSVC_MNTD) {
202 #ifndef NFS
203 		error = ENOSYS;
204 #else
205 		error = copyin(SCARG(uap, argp), (caddr_t)&ncd, sizeof (ncd));
206 		if (error)
207 			return (error);
208 		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
209 			ncd.ncd_dirp, l);
210 		error = namei(&nd);
211 		if (error)
212 			return (error);
213 		if ((nd.ni_vp->v_flag & VROOT) == 0)
214 			error = EINVAL;
215 		nmp = VFSTONFS(nd.ni_vp->v_mount);
216 		vput(nd.ni_vp);
217 		if (error)
218 			return (error);
219 		if ((nmp->nm_iflag & NFSMNT_MNTD) &&
220 			(SCARG(uap, flag) & NFSSVC_GOTAUTH) == 0)
221 			return (0);
222 		nmp->nm_iflag |= NFSMNT_MNTD;
223 		error = nqnfs_clientd(nmp, l->l_cred, &ncd, SCARG(uap, flag),
224 			SCARG(uap, argp), l);
225 #endif /* NFS */
226 	} else if (SCARG(uap, flag) & NFSSVC_ADDSOCK) {
227 #ifndef NFSSERVER
228 		error = ENOSYS;
229 #else
230 		error = copyin(SCARG(uap, argp), (caddr_t)&nfsdarg,
231 		    sizeof(nfsdarg));
232 		if (error)
233 			return (error);
234 		/* getsock() will use the descriptor for us */
235 		error = getsock(l->l_proc->p_fd, nfsdarg.sock, &fp);
236 		if (error)
237 			return (error);
238 		/*
239 		 * Get the client address for connected sockets.
240 		 */
241 		if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
242 			nam = (struct mbuf *)0;
243 		else {
244 			error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
245 				MT_SONAME);
246 			if (error) {
247 				FILE_UNUSE(fp, NULL);
248 				return (error);
249 			}
250 		}
251 		error = nfssvc_addsock(fp, nam);
252 		FILE_UNUSE(fp, NULL);
253 #endif /* !NFSSERVER */
254 	} else if (SCARG(uap, flag) & NFSSVC_SETEXPORTSLIST) {
255 #ifndef NFSSERVER
256 		error = ENOSYS;
257 #else
258 		struct export_args *args;
259 		struct mountd_exports_list mel;
260 
261 		error = copyin(SCARG(uap, argp), &mel, sizeof(mel));
262 		if (error != 0)
263 			return error;
264 
265 		args = (struct export_args *)malloc(mel.mel_nexports *
266 		    sizeof(struct export_args), M_TEMP, M_WAITOK);
267 		error = copyin(mel.mel_exports, args, mel.mel_nexports *
268 		    sizeof(struct export_args));
269 		if (error != 0) {
270 			free(args, M_TEMP);
271 			return error;
272 		}
273 		mel.mel_exports = args;
274 
275 		error = mountd_set_exports_list(&mel, l);
276 
277 		free(args, M_TEMP);
278 #endif /* !NFSSERVER */
279 	} else {
280 #ifndef NFSSERVER
281 		error = ENOSYS;
282 #else
283 		error = copyin(SCARG(uap, argp), (caddr_t)nsd, sizeof (*nsd));
284 		if (error)
285 			return (error);
286 		if ((SCARG(uap, flag) & NFSSVC_AUTHIN) &&
287 		    ((nfsd = nsd->nsd_nfsd)) != NULL &&
288 		    (nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
289 			slp = nfsd->nfsd_slp;
290 
291 			/*
292 			 * First check to see if another nfsd has already
293 			 * added this credential.
294 			 */
295 			LIST_FOREACH(nuidp, NUIDHASH(slp, nsd->nsd_cr.cr_uid),
296 			    nu_hash) {
297 				if (kauth_cred_geteuid(nuidp->nu_cr) ==
298 				    nsd->nsd_cr.cr_uid &&
299 				    (!nfsd->nfsd_nd->nd_nam2 ||
300 				     netaddr_match(NU_NETFAM(nuidp),
301 				     &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
302 					break;
303 			}
304 			if (nuidp) {
305 			    kauth_cred_hold(nuidp->nu_cr);
306 			    nfsd->nfsd_nd->nd_cr = nuidp->nu_cr;
307 			    nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
308 			} else {
309 			    /*
310 			     * Nope, so we will.
311 			     */
312 			    if (slp->ns_numuids < nuidhash_max) {
313 				slp->ns_numuids++;
314 				nuidp = (struct nfsuid *)
315 				   malloc(sizeof (struct nfsuid), M_NFSUID,
316 					M_WAITOK);
317 			    } else
318 				nuidp = (struct nfsuid *)0;
319 			    if ((slp->ns_flag & SLP_VALID) == 0) {
320 				if (nuidp)
321 				    free((caddr_t)nuidp, M_NFSUID);
322 			    } else {
323 				if (nuidp == (struct nfsuid *)0) {
324 				    nuidp = TAILQ_FIRST(&slp->ns_uidlruhead);
325 				    LIST_REMOVE(nuidp, nu_hash);
326 				    TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
327 					nu_lru);
328 				    if (nuidp->nu_flag & NU_NAM)
329 					m_freem(nuidp->nu_nam);
330 			        }
331 				nuidp->nu_flag = 0;
332 				kauth_cred_uucvt(nuidp->nu_cr, &nsd->nsd_cr);
333 				nuidp->nu_timestamp = nsd->nsd_timestamp;
334 				nuidp->nu_expire = time_second + nsd->nsd_ttl;
335 				/*
336 				 * and save the session key in nu_key.
337 				 */
338 				memcpy(nuidp->nu_key, nsd->nsd_key,
339 				    sizeof(nsd->nsd_key));
340 				if (nfsd->nfsd_nd->nd_nam2) {
341 				    struct sockaddr_in *saddr;
342 
343 				    saddr = mtod(nfsd->nfsd_nd->nd_nam2,
344 					 struct sockaddr_in *);
345 				    switch (saddr->sin_family) {
346 				    case AF_INET:
347 					nuidp->nu_flag |= NU_INETADDR;
348 					nuidp->nu_inetaddr =
349 					     saddr->sin_addr.s_addr;
350 					break;
351 				    case AF_ISO:
352 				    default:
353 					nuidp->nu_flag |= NU_NAM;
354 					nuidp->nu_nam = m_copym(
355 					    nfsd->nfsd_nd->nd_nam2, 0,
356 					     M_COPYALL, M_WAIT);
357 					break;
358 				    };
359 				}
360 				TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
361 					nu_lru);
362 				LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
363 					nuidp, nu_hash);
364 				kauth_cred_hold(nuidp->nu_cr);
365 				nfsd->nfsd_nd->nd_cr = nuidp->nu_cr;
366 				nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
367 			    }
368 			}
369 		}
370 		if ((SCARG(uap, flag) & NFSSVC_AUTHINFAIL) &&
371 		    (nfsd = nsd->nsd_nfsd))
372 			nfsd->nfsd_flag |= NFSD_AUTHFAIL;
373 		error = nfssvc_nfsd(nsd, SCARG(uap, argp), l);
374 #endif /* !NFSSERVER */
375 	}
376 	if (error == EINTR || error == ERESTART)
377 		error = 0;
378 	return (error);
379 }
380 
381 #ifdef NFSSERVER
382 MALLOC_DEFINE(M_NFSD, "NFS daemon", "Nfs server daemon structure");
383 MALLOC_DEFINE(M_NFSSVC, "NFS srvsock", "Nfs server structure");
384 
385 static struct nfssvc_sock *
386 nfsrv_sockalloc()
387 {
388 	struct nfssvc_sock *slp;
389 	int s;
390 
391 	slp = (struct nfssvc_sock *)
392 	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
393 	memset(slp, 0, sizeof (struct nfssvc_sock));
394 	simple_lock_init(&slp->ns_lock);
395 	TAILQ_INIT(&slp->ns_uidlruhead);
396 	LIST_INIT(&slp->ns_tq);
397 	SIMPLEQ_INIT(&slp->ns_sendq);
398 	s = splsoftnet();
399 	simple_lock(&nfsd_slock);
400 	TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
401 	simple_unlock(&nfsd_slock);
402 	splx(s);
403 
404 	return slp;
405 }
406 
407 static void
408 nfsrv_sockfree(struct nfssvc_sock *slp)
409 {
410 
411 	KASSERT(slp->ns_so == NULL);
412 	KASSERT(slp->ns_fp == NULL);
413 	KASSERT((slp->ns_flag & SLP_VALID) == 0);
414 	free(slp, M_NFSSVC);
415 }
416 
417 /*
418  * Adds a socket to the list for servicing by nfsds.
419  */
420 int
421 nfssvc_addsock(fp, mynam)
422 	struct file *fp;
423 	struct mbuf *mynam;
424 {
425 	struct mbuf *m;
426 	int siz;
427 	struct nfssvc_sock *slp;
428 	struct socket *so;
429 	struct nfssvc_sock *tslp;
430 	int error, s;
431 
432 	so = (struct socket *)fp->f_data;
433 	tslp = (struct nfssvc_sock *)0;
434 	/*
435 	 * Add it to the list, as required.
436 	 */
437 	if (so->so_proto->pr_protocol == IPPROTO_UDP) {
438 #ifdef INET6
439 		if (so->so_proto->pr_domain->dom_family == AF_INET6)
440 			tslp = nfs_udp6sock;
441 		else
442 #endif
443 		tslp = nfs_udpsock;
444 		if (tslp->ns_flag & SLP_VALID) {
445 			m_freem(mynam);
446 			return (EPERM);
447 		}
448 #ifdef ISO
449 	} else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) {
450 		tslp = nfs_cltpsock;
451 		if (tslp->ns_flag & SLP_VALID) {
452 			m_freem(mynam);
453 			return (EPERM);
454 		}
455 #endif /* ISO */
456 	}
457 	if (so->so_type == SOCK_STREAM)
458 		siz = NFS_MAXPACKET + sizeof (u_long);
459 	else
460 		siz = NFS_MAXPACKET;
461 	error = soreserve(so, siz, siz);
462 	if (error) {
463 		m_freem(mynam);
464 		return (error);
465 	}
466 
467 	/*
468 	 * Set protocol specific options { for now TCP only } and
469 	 * reserve some space. For datagram sockets, this can get called
470 	 * repeatedly for the same socket, but that isn't harmful.
471 	 */
472 	if (so->so_type == SOCK_STREAM) {
473 		m = m_get(M_WAIT, MT_SOOPTS);
474 		MCLAIM(m, &nfs_mowner);
475 		*mtod(m, int32_t *) = 1;
476 		m->m_len = sizeof(int32_t);
477 		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
478 	}
479 	if ((so->so_proto->pr_domain->dom_family == AF_INET
480 #ifdef INET6
481 	    || so->so_proto->pr_domain->dom_family == AF_INET6
482 #endif
483 	    ) &&
484 	    so->so_proto->pr_protocol == IPPROTO_TCP) {
485 		m = m_get(M_WAIT, MT_SOOPTS);
486 		MCLAIM(m, &nfs_mowner);
487 		*mtod(m, int32_t *) = 1;
488 		m->m_len = sizeof(int32_t);
489 		sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
490 	}
491 	so->so_rcv.sb_flags &= ~SB_NOINTR;
492 	so->so_rcv.sb_timeo = 0;
493 	so->so_snd.sb_flags &= ~SB_NOINTR;
494 	so->so_snd.sb_timeo = 0;
495 	if (tslp)
496 		slp = tslp;
497 	else {
498 		slp = nfsrv_sockalloc();
499 	}
500 	slp->ns_so = so;
501 	slp->ns_nam = mynam;
502 	fp->f_count++;
503 	slp->ns_fp = fp;
504 	s = splsoftnet();
505 	so->so_upcallarg = (caddr_t)slp;
506 	so->so_upcall = nfsrv_rcv;
507 	so->so_rcv.sb_flags |= SB_UPCALL;
508 	slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
509 	nfsrv_wakenfsd(slp);
510 	splx(s);
511 	return (0);
512 }
513 
514 /*
515  * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
516  * until it is killed by a signal.
517  */
518 int
519 nfssvc_nfsd(nsd, argp, l)
520 	struct nfsd_srvargs *nsd;
521 	caddr_t argp;
522 	struct lwp *l;
523 {
524 	struct timeval tv;
525 	struct mbuf *m;
526 	struct nfssvc_sock *slp;
527 	struct nfsd *nfsd = nsd->nsd_nfsd;
528 	struct nfsrv_descript *nd = NULL;
529 	struct mbuf *mreq;
530 	u_quad_t cur_usec;
531 	int error = 0, cacherep, s, siz, sotype, writes_todo;
532 	struct proc *p = l->l_proc;
533 
534 #ifndef nolint
535 	cacherep = RC_DOIT;
536 	writes_todo = 0;
537 #endif
538 	s = splsoftnet();
539 	if (nfsd == (struct nfsd *)0) {
540 		nsd->nsd_nfsd = nfsd = (struct nfsd *)
541 			malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
542 		memset((caddr_t)nfsd, 0, sizeof (struct nfsd));
543 		nfsd->nfsd_procp = p;
544 		simple_lock(&nfsd_slock);
545 		TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
546 		nfs_numnfsd++;
547 		simple_unlock(&nfsd_slock);
548 	}
549 	PHOLD(l);
550 	/*
551 	 * Loop getting rpc requests until SIGKILL.
552 	 */
553 	for (;;) {
554 		if (nfsd->nfsd_slp == NULL) {
555 			simple_lock(&nfsd_slock);
556 			while (nfsd->nfsd_slp == NULL &&
557 			    (nfsd_head_flag & NFSD_CHECKSLP) == 0) {
558 				SLIST_INSERT_HEAD(&nfsd_idle_head, nfsd,
559 				    nfsd_idle);
560 				nfsd_waiting++;
561 				error = ltsleep(nfsd, PSOCK | PCATCH, "nfsd",
562 				    0, &nfsd_slock);
563 				nfsd_waiting--;
564 				if (error) {
565 					slp = nfsd->nfsd_slp;
566 					nfsd->nfsd_slp = NULL;
567 					if (!slp)
568 						SLIST_REMOVE(&nfsd_idle_head,
569 						    nfsd, nfsd, nfsd_idle);
570 					simple_unlock(&nfsd_slock);
571 					if (slp) {
572 						nfsrv_wakenfsd(slp);
573 						nfsrv_slpderef(slp);
574 					}
575 					goto done;
576 				}
577 			}
578 			if (nfsd->nfsd_slp == NULL &&
579 			    (nfsd_head_flag & NFSD_CHECKSLP) != 0) {
580 				slp = TAILQ_FIRST(&nfssvc_sockpending);
581 				if (slp) {
582 					KASSERT((slp->ns_flag &
583 					    (SLP_VALID | SLP_DOREC))
584 					    == (SLP_VALID | SLP_DOREC));
585 					TAILQ_REMOVE(&nfssvc_sockpending, slp,
586 					    ns_pending);
587 					slp->ns_flag &= ~SLP_DOREC;
588 					slp->ns_sref++;
589 					nfsd->nfsd_slp = slp;
590 				} else
591 					nfsd_head_flag &= ~NFSD_CHECKSLP;
592 			}
593 			simple_unlock(&nfsd_slock);
594 			if ((slp = nfsd->nfsd_slp) == NULL)
595 				continue;
596 			if (slp->ns_flag & SLP_VALID) {
597 				if (slp->ns_flag & SLP_DISCONN)
598 					nfsrv_zapsock(slp);
599 				else if ((slp->ns_flag & SLP_NEEDQ) != 0) {
600 					nfsrv_rcv(slp->ns_so, (void *)slp,
601 					    M_WAIT);
602 				}
603 				error = nfsrv_dorec(slp, nfsd, &nd);
604 				getmicrotime(&tv);
605 				cur_usec = (u_quad_t)tv.tv_sec * 1000000 +
606 					(u_quad_t)tv.tv_usec;
607 				if (error && LIST_FIRST(&slp->ns_tq) &&
608 				    LIST_FIRST(&slp->ns_tq)->nd_time <=
609 				    cur_usec) {
610 					error = 0;
611 					cacherep = RC_DOIT;
612 					writes_todo = 1;
613 				} else
614 					writes_todo = 0;
615 				if (error == 0 && slp->ns_rec != NULL) {
616 					nfsrv_wakenfsd(slp);
617 				}
618 			}
619 		} else {
620 			error = 0;
621 			slp = nfsd->nfsd_slp;
622 		}
623 		if (error || (slp->ns_flag & SLP_VALID) == 0) {
624 			if (nd) {
625 				nfsdreq_free(nd);
626 				nd = NULL;
627 			}
628 			nfsd->nfsd_slp = NULL;
629 			nfsrv_slpderef(slp);
630 			continue;
631 		}
632 		splx(s);
633 		sotype = slp->ns_so->so_type;
634 		if (nd) {
635 			getmicrotime(&nd->nd_starttime);
636 			if (nd->nd_nam2)
637 				nd->nd_nam = nd->nd_nam2;
638 			else
639 				nd->nd_nam = slp->ns_nam;
640 
641 			/*
642 			 * Check to see if authorization is needed.
643 			 */
644 			if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
645 				nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
646 				nsd->nsd_haddr = mtod(nd->nd_nam,
647 				    struct sockaddr_in *)->sin_addr.s_addr;
648 				nsd->nsd_authlen = nfsd->nfsd_authlen;
649 				nsd->nsd_verflen = nfsd->nfsd_verflen;
650 				if (!copyout(nfsd->nfsd_authstr,
651 				    nsd->nsd_authstr, nfsd->nfsd_authlen) &&
652 				    !copyout(nfsd->nfsd_verfstr,
653 				    nsd->nsd_verfstr, nfsd->nfsd_verflen) &&
654 				    !copyout(nsd, argp, sizeof (*nsd))) {
655 					PRELE(l);
656 					return (ENEEDAUTH);
657 				}
658 				cacherep = RC_DROPIT;
659 			} else
660 				cacherep = nfsrv_getcache(nd, slp, &mreq);
661 
662 			/*
663 			 * Check for just starting up for NQNFS and send
664 			 * fake "try again later" replies to the NQNFS clients.
665 			 */
666 			if (notstarted && nqnfsstarttime <= time_second) {
667 				if (modify_flag) {
668 					nqnfsstarttime =
669 					    time_second + nqsrv_writeslack;
670 					modify_flag = 0;
671 				} else
672 					notstarted = 0;
673 			}
674 			if (notstarted) {
675 				if ((nd->nd_flag & ND_NQNFS) == 0)
676 					cacherep = RC_DROPIT;
677 				else if (nd->nd_procnum != NFSPROC_WRITE) {
678 					nd->nd_procnum = NFSPROC_NOOP;
679 					nd->nd_repstat = NQNFS_TRYLATER;
680 					cacherep = RC_DOIT;
681 				} else
682 					modify_flag = 1;
683 			} else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
684 				nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
685 				nd->nd_procnum = NFSPROC_NOOP;
686 				nd->nd_repstat =
687 				    (NFSERR_AUTHERR | AUTH_TOOWEAK);
688 				cacherep = RC_DOIT;
689 			}
690 		}
691 
692 		/*
693 		 * Loop to get all the write rpc relies that have been
694 		 * gathered together.
695 		 */
696 		do {
697 #ifdef DIAGNOSTIC
698 			int lockcount;
699 #endif
700 			switch (cacherep) {
701 			case RC_DOIT:
702 #ifdef DIAGNOSTIC
703 				/*
704 				 * NFS server procs should neither release
705 				 * locks already held, nor leave things
706 				 * locked.  Catch this sooner, rather than
707 				 * later (when we try to relock something we
708 				 * already have locked).  Careful inspection
709 				 * of the failing routine usually turns up the
710 				 * lock leak.. once we know what it is..
711 				 */
712 				lockcount = l->l_locks;
713 #endif
714 				mreq = NULL;
715 				netexport_rdlock();
716 				if (writes_todo || nd == NULL ||
717 				     (!(nd->nd_flag & ND_NFSV3) &&
718 				     nd->nd_procnum == NFSPROC_WRITE &&
719 				     nfsrvw_procrastinate > 0 && !notstarted))
720 					error = nfsrv_writegather(&nd, slp,
721 					    l, &mreq);
722 				else
723 					error =
724 					    (*(nfsrv3_procs[nd->nd_procnum]))
725 					    (nd, slp, l, &mreq);
726 				netexport_rdunlock();
727 #ifdef DIAGNOSTIC
728 				if (l->l_locks != lockcount) {
729 					/*
730 					 * If you see this panic, audit
731 					 * nfsrv3_procs[nd->nd_procnum] for
732 					 * vnode locking errors (usually, it's
733 					 * due to forgetting to vput()
734 					 * something).
735 					 */
736 #ifdef DEBUG
737 					extern void printlockedvnodes(void);
738 					printlockedvnodes();
739 #endif
740 					printf("nfsd: locking botch in op %d"
741 					    " (before %d, after %d)\n",
742 					    nd ? nd->nd_procnum : -1,
743 					    lockcount, l->l_locks);
744 				}
745 #endif
746 				if (mreq == NULL) {
747 					if (nd != NULL) {
748 						if (nd->nd_nam2)
749 							m_free(nd->nd_nam2);
750 						if (nd->nd_mrep)
751 							m_freem(nd->nd_mrep);
752 					}
753 					break;
754 				}
755 				if (error) {
756 					if (nd->nd_procnum != NQNFSPROC_VACATED)
757 						nfsstats.srv_errs++;
758 					nfsrv_updatecache(nd, FALSE, mreq);
759 					if (nd->nd_nam2)
760 						m_freem(nd->nd_nam2);
761 					break;
762 				}
763 				nfsstats.srvrpccnt[nd->nd_procnum]++;
764 				nfsrv_updatecache(nd, TRUE, mreq);
765 				nd->nd_mrep = (struct mbuf *)0;
766 			case RC_REPLY:
767 				m = mreq;
768 				siz = 0;
769 				while (m) {
770 					siz += m->m_len;
771 					m = m->m_next;
772 				}
773 				if (siz <= 0 || siz > NFS_MAXPACKET) {
774 					printf("mbuf siz=%d\n",siz);
775 					panic("Bad nfs svc reply");
776 				}
777 				m = mreq;
778 				m->m_pkthdr.len = siz;
779 				m->m_pkthdr.rcvif = (struct ifnet *)0;
780 				/*
781 				 * For stream protocols, prepend a Sun RPC
782 				 * Record Mark.
783 				 */
784 				if (sotype == SOCK_STREAM) {
785 					M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
786 					*mtod(m, u_int32_t *) =
787 					    htonl(0x80000000 | siz);
788 				}
789 				nd->nd_mreq = m;
790 				if (nfsrtton) {
791 					nfsd_rt(slp->ns_so->so_type, nd,
792 					    cacherep);
793 				}
794 				s = splsoftnet();
795 				error = nfsdsock_sendreply(slp, nd);
796 				nd = NULL;
797 				if (error == EPIPE)
798 					nfsrv_zapsock(slp);
799 				if (error == EINTR || error == ERESTART) {
800 					nfsrv_slpderef(slp);
801 					goto done;
802 				}
803 				splx(s);
804 				break;
805 			case RC_DROPIT:
806 				if (nfsrtton)
807 					nfsd_rt(sotype, nd, cacherep);
808 				m_freem(nd->nd_mrep);
809 				m_freem(nd->nd_nam2);
810 				break;
811 			}
812 			if (nd) {
813 				nfsdreq_free(nd);
814 				nd = NULL;
815 			}
816 
817 			/*
818 			 * Check to see if there are outstanding writes that
819 			 * need to be serviced.
820 			 */
821 			getmicrotime(&tv);
822 			cur_usec = (u_quad_t)tv.tv_sec * 1000000 +
823 			    (u_quad_t)tv.tv_usec;
824 			s = splsoftclock();
825 			if (LIST_FIRST(&slp->ns_tq) &&
826 			    LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec) {
827 				cacherep = RC_DOIT;
828 				writes_todo = 1;
829 			} else
830 				writes_todo = 0;
831 			splx(s);
832 		} while (writes_todo);
833 		s = splsoftnet();
834 		if (nfsrv_dorec(slp, nfsd, &nd)) {
835 			nfsd->nfsd_slp = NULL;
836 			nfsrv_slpderef(slp);
837 		}
838 	}
839 done:
840 	PRELE(l);
841 	simple_lock(&nfsd_slock);
842 	TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
843 	simple_unlock(&nfsd_slock);
844 	splx(s);
845 	free((caddr_t)nfsd, M_NFSD);
846 	nsd->nsd_nfsd = (struct nfsd *)0;
847 	if (--nfs_numnfsd == 0)
848 		nfsrv_init(TRUE);	/* Reinitialize everything */
849 	return (error);
850 }
851 
852 /*
853  * Shut down a socket associated with an nfssvc_sock structure.
854  * Should be called with the send lock set, if required.
855  * The trick here is to increment the sref at the start, so that the nfsds
856  * will stop using it and clear ns_flag at the end so that it will not be
857  * reassigned during cleanup.
858  *
859  * called at splsoftnet.
860  */
861 void
862 nfsrv_zapsock(slp)
863 	struct nfssvc_sock *slp;
864 {
865 	struct nfsuid *nuidp, *nnuidp;
866 	struct nfsrv_descript *nwp, *nnwp;
867 	struct socket *so;
868 	int s;
869 
870 	if (nfsdsock_drain(slp)) {
871 		return;
872 	}
873 	simple_lock(&nfsd_slock);
874 	if (slp->ns_flag & SLP_DOREC) {
875 		TAILQ_REMOVE(&nfssvc_sockpending, slp, ns_pending);
876 	}
877 	simple_unlock(&nfsd_slock);
878 
879 	so = slp->ns_so;
880 	KASSERT(so != NULL);
881 	so->so_upcall = NULL;
882 	so->so_upcallarg = NULL;
883 	so->so_rcv.sb_flags &= ~SB_UPCALL;
884 	soshutdown(so, SHUT_RDWR);
885 
886 	if (slp->ns_nam)
887 		m_free(slp->ns_nam);
888 	m_freem(slp->ns_raw);
889 	m_freem(slp->ns_rec);
890 	for (nuidp = TAILQ_FIRST(&slp->ns_uidlruhead); nuidp != 0;
891 	    nuidp = nnuidp) {
892 		nnuidp = TAILQ_NEXT(nuidp, nu_lru);
893 		LIST_REMOVE(nuidp, nu_hash);
894 		TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
895 		if (nuidp->nu_flag & NU_NAM)
896 			m_freem(nuidp->nu_nam);
897 		free((caddr_t)nuidp, M_NFSUID);
898 	}
899 	s = splsoftclock();
900 	for (nwp = LIST_FIRST(&slp->ns_tq); nwp; nwp = nnwp) {
901 		nnwp = LIST_NEXT(nwp, nd_tq);
902 		LIST_REMOVE(nwp, nd_tq);
903 		nfsdreq_free(nwp);
904 	}
905 	splx(s);
906 }
907 
908 /*
909  * Derefence a server socket structure. If it has no more references and
910  * is no longer valid, you can throw it away.
911  */
912 void
913 nfsrv_slpderef(slp)
914 	struct nfssvc_sock *slp;
915 {
916 	LOCK_ASSERT(!simple_lock_held(&nfsd_slock));
917 
918 	if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
919 		struct file *fp;
920 		int s = splsoftnet();
921 		simple_lock(&nfsd_slock);
922 		TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
923 		simple_unlock(&nfsd_slock);
924 		splx(s);
925 
926 		fp = slp->ns_fp;
927 		if (fp != NULL) {
928 			slp->ns_fp = NULL;
929 			KASSERT(fp != NULL);
930 			KASSERT(fp->f_data == slp->ns_so);
931 			simple_lock(&fp->f_slock);
932 			FILE_USE(fp);
933 			closef(fp, (struct lwp *)0);
934 			slp->ns_so = NULL;
935 		}
936 
937 		nfsrv_sockfree(slp);
938 	}
939 }
940 
941 /*
942  * Initialize the data structures for the server.
943  * Handshake with any new nfsds starting up to avoid any chance of
944  * corruption.
945  */
946 void
947 nfsrv_init(terminating)
948 	int terminating;
949 {
950 	struct nfssvc_sock *slp;
951 	int s;
952 
953 	s = splsoftnet();
954 	simple_lock(&nfsd_slock);
955 	if (nfssvc_sockhead_flag & SLP_INIT)
956 		panic("nfsd init");
957 	nfssvc_sockhead_flag |= SLP_INIT;
958 
959 	if (terminating) {
960 		while ((slp = TAILQ_FIRST(&nfssvc_sockhead)) != NULL) {
961 			simple_unlock(&nfsd_slock);
962 			KASSERT(slp->ns_sref == 0);
963 			slp->ns_sref++;
964 			nfsrv_zapsock(slp);
965 			nfsrv_slpderef(slp);
966 			simple_lock(&nfsd_slock);
967 		}
968 		simple_unlock(&nfsd_slock);
969 		splx(s);
970 		nfsrv_cleancache();	/* And clear out server cache */
971 	} else {
972 		simple_unlock(&nfsd_slock);
973 		splx(s);
974 		nfs_pub.np_valid = 0;
975 	}
976 
977 	TAILQ_INIT(&nfssvc_sockhead);
978 	TAILQ_INIT(&nfssvc_sockpending);
979 	nfssvc_sockhead_flag &= ~SLP_INIT;
980 
981 	TAILQ_INIT(&nfsd_head);
982 	SLIST_INIT(&nfsd_idle_head);
983 	nfsd_head_flag &= ~NFSD_CHECKSLP;
984 
985 	nfs_udpsock = nfsrv_sockalloc();
986 
987 #ifdef INET6
988 	nfs_udp6sock = nfsrv_sockalloc();
989 #endif
990 
991 #ifdef ISO
992 	nfs_cltpsock = nfsrv_sockalloc();
993 #endif
994 
995 	simple_lock(&nfsd_slock);
996 	if (nfssvc_sockhead_flag & SLP_WANTINIT) {
997 		nfssvc_sockhead_flag &= ~SLP_WANTINIT;
998 		wakeup(&nfssvc_sockhead);
999 	}
1000 	simple_unlock(&nfsd_slock);
1001 	splx(s);
1002 }
1003 
1004 /*
1005  * Add entries to the server monitor log.
1006  */
1007 static void
1008 nfsd_rt(sotype, nd, cacherep)
1009 	int sotype;
1010 	struct nfsrv_descript *nd;
1011 	int cacherep;
1012 {
1013 	struct timeval tv;
1014 	struct drt *rt;
1015 
1016 	rt = &nfsdrt.drt[nfsdrt.pos];
1017 	if (cacherep == RC_DOIT)
1018 		rt->flag = 0;
1019 	else if (cacherep == RC_REPLY)
1020 		rt->flag = DRT_CACHEREPLY;
1021 	else
1022 		rt->flag = DRT_CACHEDROP;
1023 	if (sotype == SOCK_STREAM)
1024 		rt->flag |= DRT_TCP;
1025 	if (nd->nd_flag & ND_NQNFS)
1026 		rt->flag |= DRT_NQNFS;
1027 	else if (nd->nd_flag & ND_NFSV3)
1028 		rt->flag |= DRT_NFSV3;
1029 	rt->proc = nd->nd_procnum;
1030 	if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET)
1031 	    rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr;
1032 	else
1033 	    rt->ipadr = INADDR_ANY;
1034 	getmicrotime(&tv);
1035 	rt->resptime = ((tv.tv_sec - nd->nd_starttime.tv_sec) * 1000000) +
1036 		(tv.tv_usec - nd->nd_starttime.tv_usec);
1037 	rt->tstamp = tv;
1038 	nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
1039 }
1040 #endif /* NFSSERVER */
1041 
1042 #ifdef NFS
1043 
1044 int nfs_defect = 0;
1045 /*
1046  * Asynchronous I/O threads for client nfs.
1047  * They do read-ahead and write-behind operations on the block I/O cache.
1048  * Never returns unless it fails or gets killed.
1049  */
1050 
1051 int
1052 nfssvc_iod(l)
1053 	struct lwp *l;
1054 {
1055 	struct buf *bp;
1056 	int i;
1057 	struct nfs_iod *myiod;
1058 	struct nfsmount *nmp;
1059 	int error = 0;
1060 	struct proc *p = l->l_proc;
1061 
1062 	/*
1063 	 * Assign my position or return error if too many already running
1064 	 */
1065 	myiod = NULL;
1066 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1067 		if (nfs_asyncdaemon[i].nid_proc == NULL) {
1068 			myiod = &nfs_asyncdaemon[i];
1069 			break;
1070 		}
1071 	if (myiod == NULL)
1072 		return (EBUSY);
1073 	myiod->nid_proc = p;
1074 	nfs_numasync++;
1075 	PHOLD(l);
1076 	/*
1077 	 * Just loop around doing our stuff until SIGKILL
1078 	 */
1079 	for (;;) {
1080 		while (/*CONSTCOND*/ TRUE) {
1081 			simple_lock(&myiod->nid_slock);
1082 			nmp = myiod->nid_mount;
1083 			if (nmp) {
1084 				simple_lock(&nmp->nm_slock);
1085 				if (!TAILQ_EMPTY(&nmp->nm_bufq)) {
1086 					simple_unlock(&myiod->nid_slock);
1087 					break;
1088 				}
1089 				nmp->nm_bufqiods--;
1090 				simple_unlock(&nmp->nm_slock);
1091 			}
1092 			myiod->nid_want = p;
1093 			myiod->nid_mount = NULL;
1094 			error = ltsleep(&myiod->nid_want,
1095 			    PWAIT | PCATCH | PNORELOCK, "nfsidl", 0,
1096 			    &myiod->nid_slock);
1097 			if (error)
1098 				goto quit;
1099 		}
1100 
1101 		while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) {
1102 			/* Take one off the front of the list */
1103 			TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
1104 			nmp->nm_bufqlen--;
1105 			if (nmp->nm_bufqwant &&
1106 			    nmp->nm_bufqlen < 2 * nfs_numasync) {
1107 				nmp->nm_bufqwant = FALSE;
1108 				wakeup(&nmp->nm_bufq);
1109 			}
1110 			simple_unlock(&nmp->nm_slock);
1111 			(void)nfs_doio(bp);
1112 			simple_lock(&nmp->nm_slock);
1113 			/*
1114 			 * If there are more than one iod on this mount,
1115 			 * then defect so that the iods can be shared out
1116 			 * fairly between the mounts
1117 			 */
1118 			if (nfs_defect && nmp->nm_bufqiods > 1) {
1119 				myiod->nid_mount = NULL;
1120 				nmp->nm_bufqiods--;
1121 				break;
1122 			}
1123 		}
1124 		simple_unlock(&nmp->nm_slock);
1125 	}
1126 quit:
1127 	PRELE(l);
1128 	if (nmp)
1129 		nmp->nm_bufqiods--;
1130 	myiod->nid_want = NULL;
1131 	myiod->nid_mount = NULL;
1132 	myiod->nid_proc = NULL;
1133 	nfs_numasync--;
1134 
1135 	return error;
1136 }
1137 
1138 void
1139 nfs_iodinit()
1140 {
1141 	int i;
1142 
1143 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1144 		simple_lock_init(&nfs_asyncdaemon[i].nid_slock);
1145 }
1146 
1147 void
1148 start_nfsio(void *arg __unused)
1149 {
1150 	nfssvc_iod(curlwp);
1151 
1152 	kthread_exit(0);
1153 }
1154 
1155 void
1156 nfs_getset_niothreads(set)
1157 	int set;
1158 {
1159 	int i, have, start;
1160 
1161 	for (have = 0, i = 0; i < NFS_MAXASYNCDAEMON; i++)
1162 		if (nfs_asyncdaemon[i].nid_proc != NULL)
1163 			have++;
1164 
1165 	if (set) {
1166 		/* clamp to sane range */
1167 		nfs_niothreads = max(0, min(nfs_niothreads, NFS_MAXASYNCDAEMON));
1168 
1169 		start = nfs_niothreads - have;
1170 
1171 		while (start > 0) {
1172 			kthread_create1(start_nfsio, NULL, NULL, "nfsio");
1173 			start--;
1174 		}
1175 
1176 		for (i = 0; (start < 0) && (i < NFS_MAXASYNCDAEMON); i++)
1177 			if (nfs_asyncdaemon[i].nid_proc != NULL) {
1178 				psignal(nfs_asyncdaemon[i].nid_proc, SIGKILL);
1179 				start++;
1180 			}
1181 	} else {
1182 		if (nfs_niothreads >= 0)
1183 			nfs_niothreads = have;
1184 	}
1185 }
1186 
1187 /*
1188  * Get an authorization string for the uid by having the mount_nfs sitting
1189  * on this mount point porpous out of the kernel and do it.
1190  */
1191 int
1192 nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
1193 	struct nfsmount *nmp;
1194 	struct nfsreq *rep;
1195 	kauth_cred_t cred;
1196 	char **auth_str;
1197 	int *auth_len;
1198 	char *verf_str;
1199 	int *verf_len;
1200 	NFSKERBKEY_T key;		/* return session key */
1201 {
1202 	int error = 0;
1203 
1204 	while ((nmp->nm_iflag & NFSMNT_WAITAUTH) == 0) {
1205 		nmp->nm_iflag |= NFSMNT_WANTAUTH;
1206 		(void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
1207 			"nfsauth1", 2 * hz);
1208 		error = nfs_sigintr(nmp, rep, rep->r_lwp);
1209 		if (error) {
1210 			nmp->nm_iflag &= ~NFSMNT_WANTAUTH;
1211 			return (error);
1212 		}
1213 	}
1214 	nmp->nm_iflag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
1215 	nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
1216 	nmp->nm_authlen = RPCAUTH_MAXSIZ;
1217 	nmp->nm_verfstr = verf_str;
1218 	nmp->nm_verflen = *verf_len;
1219 	nmp->nm_authuid = kauth_cred_geteuid(cred);
1220 	wakeup((caddr_t)&nmp->nm_authstr);
1221 
1222 	/*
1223 	 * And wait for mount_nfs to do its stuff.
1224 	 */
1225 	while ((nmp->nm_iflag & NFSMNT_HASAUTH) == 0 && error == 0) {
1226 		(void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
1227 			"nfsauth2", 2 * hz);
1228 		error = nfs_sigintr(nmp, rep, rep->r_lwp);
1229 	}
1230 	if (nmp->nm_iflag & NFSMNT_AUTHERR) {
1231 		nmp->nm_iflag &= ~NFSMNT_AUTHERR;
1232 		error = EAUTH;
1233 	}
1234 	if (error)
1235 		free((caddr_t)*auth_str, M_TEMP);
1236 	else {
1237 		*auth_len = nmp->nm_authlen;
1238 		*verf_len = nmp->nm_verflen;
1239 		memcpy(key, nmp->nm_key, sizeof (NFSKERBKEY_T));
1240 	}
1241 	nmp->nm_iflag &= ~NFSMNT_HASAUTH;
1242 	nmp->nm_iflag |= NFSMNT_WAITAUTH;
1243 	if (nmp->nm_iflag & NFSMNT_WANTAUTH) {
1244 		nmp->nm_iflag &= ~NFSMNT_WANTAUTH;
1245 		wakeup((caddr_t)&nmp->nm_authtype);
1246 	}
1247 	return (error);
1248 }
1249 
1250 /*
1251  * Get a nickname authenticator and verifier.
1252  */
1253 int
1254 nfs_getnickauth(
1255     struct nfsmount *nmp,
1256     kauth_cred_t cred,
1257     char **auth_str,
1258     int *auth_len,
1259     char *verf_str,
1260     int verf_len __unused
1261 )
1262 {
1263 	struct timeval ktvin, ktvout, tv;
1264 	struct nfsuid *nuidp;
1265 	u_int32_t *nickp, *verfp;
1266 
1267 	memset(&ktvout, 0, sizeof ktvout);	/* XXX gcc */
1268 
1269 #ifdef DIAGNOSTIC
1270 	if (verf_len < (4 * NFSX_UNSIGNED))
1271 		panic("nfs_getnickauth verf too small");
1272 #endif
1273 	LIST_FOREACH(nuidp, NMUIDHASH(nmp, kauth_cred_geteuid(cred)), nu_hash) {
1274 		if (kauth_cred_geteuid(nuidp->nu_cr) == kauth_cred_geteuid(cred))
1275 			break;
1276 	}
1277 	if (!nuidp || nuidp->nu_expire < time_second)
1278 		return (EACCES);
1279 
1280 	/*
1281 	 * Move to the end of the lru list (end of lru == most recently used).
1282 	 */
1283 	TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
1284 	TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
1285 
1286 	nickp = (u_int32_t *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
1287 	*nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
1288 	*nickp = txdr_unsigned(nuidp->nu_nickname);
1289 	*auth_str = (char *)nickp;
1290 	*auth_len = 2 * NFSX_UNSIGNED;
1291 
1292 	/*
1293 	 * Now we must encrypt the verifier and package it up.
1294 	 */
1295 	verfp = (u_int32_t *)verf_str;
1296 	*verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
1297 	getmicrotime(&tv);
1298 	if (tv.tv_sec > nuidp->nu_timestamp.tv_sec ||
1299 	    (tv.tv_sec == nuidp->nu_timestamp.tv_sec &&
1300 	     tv.tv_usec > nuidp->nu_timestamp.tv_usec))
1301 		nuidp->nu_timestamp = tv;
1302 	else
1303 		nuidp->nu_timestamp.tv_usec++;
1304 	ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
1305 	ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
1306 
1307 	/*
1308 	 * Now encrypt the timestamp verifier in ecb mode using the session
1309 	 * key.
1310 	 */
1311 #ifdef NFSKERB
1312 	XXX
1313 #endif
1314 
1315 	*verfp++ = ktvout.tv_sec;
1316 	*verfp++ = ktvout.tv_usec;
1317 	*verfp = 0;
1318 	return (0);
1319 }
1320 
1321 /*
1322  * Save the current nickname in a hash list entry on the mount point.
1323  */
1324 int
1325 nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
1326 	struct nfsmount *nmp;
1327 	kauth_cred_t cred;
1328 	int len;
1329 	NFSKERBKEY_T key;
1330 	struct mbuf **mdp;
1331 	char **dposp;
1332 	struct mbuf *mrep;
1333 {
1334 	struct nfsuid *nuidp;
1335 	u_int32_t *tl;
1336 	int32_t t1;
1337 	struct mbuf *md = *mdp;
1338 	struct timeval ktvin, ktvout;
1339 	u_int32_t nick;
1340 	char *dpos = *dposp, *cp2;
1341 	int deltasec, error = 0;
1342 
1343 	memset(&ktvout, 0, sizeof ktvout);	 /* XXX gcc */
1344 
1345 	if (len == (3 * NFSX_UNSIGNED)) {
1346 		nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1347 		ktvin.tv_sec = *tl++;
1348 		ktvin.tv_usec = *tl++;
1349 		nick = fxdr_unsigned(u_int32_t, *tl);
1350 
1351 		/*
1352 		 * Decrypt the timestamp in ecb mode.
1353 		 */
1354 #ifdef NFSKERB
1355 		XXX
1356 #endif
1357 		ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
1358 		ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
1359 		deltasec = time_second - ktvout.tv_sec;
1360 		if (deltasec < 0)
1361 			deltasec = -deltasec;
1362 		/*
1363 		 * If ok, add it to the hash list for the mount point.
1364 		 */
1365 		if (deltasec <= NFS_KERBCLOCKSKEW) {
1366 			if (nmp->nm_numuids < nuidhash_max) {
1367 				nmp->nm_numuids++;
1368 				nuidp = (struct nfsuid *)
1369 				   malloc(sizeof (struct nfsuid), M_NFSUID,
1370 					M_WAITOK);
1371 			} else {
1372 				nuidp = TAILQ_FIRST(&nmp->nm_uidlruhead);
1373 				LIST_REMOVE(nuidp, nu_hash);
1374 				TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
1375 					nu_lru);
1376 			}
1377 			nuidp->nu_flag = 0;
1378 			kauth_cred_seteuid(nuidp->nu_cr, kauth_cred_geteuid(cred));
1379 			nuidp->nu_expire = time_second + NFS_KERBTTL;
1380 			nuidp->nu_timestamp = ktvout;
1381 			nuidp->nu_nickname = nick;
1382 			memcpy(nuidp->nu_key, key, sizeof (NFSKERBKEY_T));
1383 			TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
1384 				nu_lru);
1385 			LIST_INSERT_HEAD(NMUIDHASH(nmp, kauth_cred_geteuid(cred)),
1386 				nuidp, nu_hash);
1387 		}
1388 	} else
1389 		nfsm_adv(nfsm_rndup(len));
1390 nfsmout:
1391 	*mdp = md;
1392 	*dposp = dpos;
1393 	return (error);
1394 }
1395 #endif /* NFS */
1396