xref: /netbsd-src/sys/nfs/nfs_iod.c (revision 93c8adad8ba08d05dc17712928abc394061254a5)
1*93c8adadSchristos /*	$NetBSD: nfs_iod.c,v 1.9 2023/03/21 15:47:46 christos Exp $	*/
292ce8c6aSad 
392ce8c6aSad /*
492ce8c6aSad  * Copyright (c) 1989, 1993
592ce8c6aSad  *	The Regents of the University of California.  All rights reserved.
692ce8c6aSad  *
792ce8c6aSad  * This code is derived from software contributed to Berkeley by
892ce8c6aSad  * Rick Macklem at The University of Guelph.
992ce8c6aSad  *
1092ce8c6aSad  * Redistribution and use in source and binary forms, with or without
1192ce8c6aSad  * modification, are permitted provided that the following conditions
1292ce8c6aSad  * are met:
1392ce8c6aSad  * 1. Redistributions of source code must retain the above copyright
1492ce8c6aSad  *    notice, this list of conditions and the following disclaimer.
1592ce8c6aSad  * 2. Redistributions in binary form must reproduce the above copyright
1692ce8c6aSad  *    notice, this list of conditions and the following disclaimer in the
1792ce8c6aSad  *    documentation and/or other materials provided with the distribution.
1892ce8c6aSad  * 3. Neither the name of the University nor the names of its contributors
1992ce8c6aSad  *    may be used to endorse or promote products derived from this software
2092ce8c6aSad  *    without specific prior written permission.
2192ce8c6aSad  *
2292ce8c6aSad  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2392ce8c6aSad  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2492ce8c6aSad  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2592ce8c6aSad  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2692ce8c6aSad  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2792ce8c6aSad  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2892ce8c6aSad  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2992ce8c6aSad  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3092ce8c6aSad  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3192ce8c6aSad  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3292ce8c6aSad  * SUCH DAMAGE.
3392ce8c6aSad  *
3492ce8c6aSad  *	@(#)nfs_syscalls.c	8.5 (Berkeley) 3/30/95
3592ce8c6aSad  */
3692ce8c6aSad 
3792ce8c6aSad #include <sys/cdefs.h>
38*93c8adadSchristos __KERNEL_RCSID(0, "$NetBSD: nfs_iod.c,v 1.9 2023/03/21 15:47:46 christos Exp $");
3992ce8c6aSad 
4092ce8c6aSad #include <sys/param.h>
4192ce8c6aSad #include <sys/systm.h>
4292ce8c6aSad #include <sys/kernel.h>
4392ce8c6aSad #include <sys/file.h>
4492ce8c6aSad #include <sys/stat.h>
4592ce8c6aSad #include <sys/vnode.h>
4692ce8c6aSad #include <sys/mount.h>
4792ce8c6aSad #include <sys/proc.h>
4892ce8c6aSad #include <sys/uio.h>
4992ce8c6aSad #include <sys/malloc.h>
5092ce8c6aSad #include <sys/kmem.h>
5192ce8c6aSad #include <sys/buf.h>
5292ce8c6aSad #include <sys/mbuf.h>
5392ce8c6aSad #include <sys/socket.h>
5492ce8c6aSad #include <sys/socketvar.h>
5592ce8c6aSad #include <sys/signalvar.h>
5692ce8c6aSad #include <sys/domain.h>
5792ce8c6aSad #include <sys/protosw.h>
5892ce8c6aSad #include <sys/namei.h>
5992ce8c6aSad #include <sys/syslog.h>
6092ce8c6aSad #include <sys/filedesc.h>
6192ce8c6aSad #include <sys/kthread.h>
6292ce8c6aSad #include <sys/kauth.h>
6392ce8c6aSad #include <sys/syscallargs.h>
6492ce8c6aSad 
6592ce8c6aSad #include <netinet/in.h>
6692ce8c6aSad #include <netinet/tcp.h>
6792ce8c6aSad #include <nfs/xdr_subs.h>
6892ce8c6aSad #include <nfs/rpcv2.h>
6992ce8c6aSad #include <nfs/nfsproto.h>
7092ce8c6aSad #include <nfs/nfs.h>
7192ce8c6aSad #include <nfs/nfsm_subs.h>
7292ce8c6aSad #include <nfs/nfsrvcache.h>
7392ce8c6aSad #include <nfs/nfsmount.h>
7492ce8c6aSad #include <nfs/nfsnode.h>
7592ce8c6aSad #include <nfs/nfsrtt.h>
7692ce8c6aSad #include <nfs/nfs_var.h>
7792ce8c6aSad 
783506b644Schristos extern int nuidhash_max;
7992ce8c6aSad 
8092ce8c6aSad /*
8192ce8c6aSad  * locking order:
8292ce8c6aSad  *	nfs_iodlist_lock -> nid_lock -> nm_lock
8392ce8c6aSad  */
8492ce8c6aSad kmutex_t nfs_iodlist_lock;
8592ce8c6aSad struct nfs_iodlist nfs_iodlist_idle;
8692ce8c6aSad struct nfs_iodlist nfs_iodlist_all;
8792ce8c6aSad int nfs_niothreads = -1; /* == "0, and has never been set" */
8892ce8c6aSad int nfs_defect = 0;
8992ce8c6aSad 
9092ce8c6aSad /*
9192ce8c6aSad  * Asynchronous I/O threads for client nfs.
9292ce8c6aSad  * They do read-ahead and write-behind operations on the block I/O cache.
9392ce8c6aSad  * Never returns unless it fails or gets killed.
9492ce8c6aSad  */
9592ce8c6aSad 
9692ce8c6aSad static void
nfssvc_iod(void * arg)9792ce8c6aSad nfssvc_iod(void *arg)
9892ce8c6aSad {
9992ce8c6aSad 	struct buf *bp;
10092ce8c6aSad 	struct nfs_iod *myiod;
10192ce8c6aSad 	struct nfsmount *nmp;
10292ce8c6aSad 
10392ce8c6aSad 	myiod = kmem_alloc(sizeof(*myiod), KM_SLEEP);
10492ce8c6aSad 	mutex_init(&myiod->nid_lock, MUTEX_DEFAULT, IPL_NONE);
10592ce8c6aSad 	cv_init(&myiod->nid_cv, "nfsiod");
10692ce8c6aSad 	myiod->nid_exiting = false;
10792ce8c6aSad 	myiod->nid_mount = NULL;
10892ce8c6aSad 	mutex_enter(&nfs_iodlist_lock);
10992ce8c6aSad 	LIST_INSERT_HEAD(&nfs_iodlist_all, myiod, nid_all);
11092ce8c6aSad 	mutex_exit(&nfs_iodlist_lock);
11192ce8c6aSad 
11292ce8c6aSad 	for (;;) {
11392ce8c6aSad 		mutex_enter(&nfs_iodlist_lock);
11492ce8c6aSad 		LIST_INSERT_HEAD(&nfs_iodlist_idle, myiod, nid_idle);
11592ce8c6aSad 		mutex_exit(&nfs_iodlist_lock);
11692ce8c6aSad 
11792ce8c6aSad 		mutex_enter(&myiod->nid_lock);
11892ce8c6aSad 		while (/*CONSTCOND*/ true) {
11992ce8c6aSad 			nmp = myiod->nid_mount;
12092ce8c6aSad 			if (nmp) {
12192ce8c6aSad 				myiod->nid_mount = NULL;
12292ce8c6aSad 				break;
12392ce8c6aSad 			}
12492ce8c6aSad 			if (__predict_false(myiod->nid_exiting)) {
12592ce8c6aSad 				/*
12692ce8c6aSad 				 * drop nid_lock to preserve locking order.
12792ce8c6aSad 				 */
12892ce8c6aSad 				mutex_exit(&myiod->nid_lock);
12992ce8c6aSad 				mutex_enter(&nfs_iodlist_lock);
13092ce8c6aSad 				mutex_enter(&myiod->nid_lock);
13192ce8c6aSad 				/*
13292ce8c6aSad 				 * recheck nid_mount because nfs_asyncio can
13392ce8c6aSad 				 * pick us in the meantime as we are still on
13492ce8c6aSad 				 * nfs_iodlist_lock.
13592ce8c6aSad 				 */
13692ce8c6aSad 				if (myiod->nid_mount != NULL) {
13792ce8c6aSad 					mutex_exit(&nfs_iodlist_lock);
13892ce8c6aSad 					continue;
13992ce8c6aSad 				}
14092ce8c6aSad 				LIST_REMOVE(myiod, nid_idle);
14192ce8c6aSad 				mutex_exit(&nfs_iodlist_lock);
14292ce8c6aSad 				goto quit;
14392ce8c6aSad 			}
14492ce8c6aSad 			cv_wait(&myiod->nid_cv, &myiod->nid_lock);
14592ce8c6aSad 		}
14692ce8c6aSad 		mutex_exit(&myiod->nid_lock);
14792ce8c6aSad 
14892ce8c6aSad 		mutex_enter(&nmp->nm_lock);
14992ce8c6aSad 		while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) {
15092ce8c6aSad 			/* Take one off the front of the list */
15192ce8c6aSad 			TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
15292ce8c6aSad 			nmp->nm_bufqlen--;
15392ce8c6aSad 			if (nmp->nm_bufqlen < 2 * nmp->nm_bufqiods) {
15492ce8c6aSad 				cv_broadcast(&nmp->nm_aiocv);
15592ce8c6aSad 			}
15692ce8c6aSad 			mutex_exit(&nmp->nm_lock);
15792ce8c6aSad 			KERNEL_LOCK(1, curlwp);
15892ce8c6aSad 			(void)nfs_doio(bp);
15992ce8c6aSad 			KERNEL_UNLOCK_LAST(curlwp);
16092ce8c6aSad 			mutex_enter(&nmp->nm_lock);
16192ce8c6aSad 			/*
16292ce8c6aSad 			 * If there are more than one iod on this mount,
16392ce8c6aSad 			 * then defect so that the iods can be shared out
16492ce8c6aSad 			 * fairly between the mounts
16592ce8c6aSad 			 */
16692ce8c6aSad 			if (nfs_defect && nmp->nm_bufqiods > 1) {
16792ce8c6aSad 				break;
16892ce8c6aSad 			}
16992ce8c6aSad 		}
17092ce8c6aSad 		KASSERT(nmp->nm_bufqiods > 0);
17192ce8c6aSad 		nmp->nm_bufqiods--;
17292ce8c6aSad 		mutex_exit(&nmp->nm_lock);
17392ce8c6aSad 	}
17492ce8c6aSad quit:
17592ce8c6aSad 	KASSERT(myiod->nid_mount == NULL);
17692ce8c6aSad 	mutex_exit(&myiod->nid_lock);
17792ce8c6aSad 
17892ce8c6aSad 	cv_destroy(&myiod->nid_cv);
17992ce8c6aSad 	mutex_destroy(&myiod->nid_lock);
18092ce8c6aSad 	kmem_free(myiod, sizeof(*myiod));
18192ce8c6aSad 
18292ce8c6aSad 	kthread_exit(0);
18392ce8c6aSad }
18492ce8c6aSad 
18592ce8c6aSad void
nfs_iodinit(void)18692ce8c6aSad nfs_iodinit(void)
18792ce8c6aSad {
18892ce8c6aSad 
18992ce8c6aSad 	mutex_init(&nfs_iodlist_lock, MUTEX_DEFAULT, IPL_NONE);
19092ce8c6aSad 	LIST_INIT(&nfs_iodlist_all);
19192ce8c6aSad 	LIST_INIT(&nfs_iodlist_idle);
19292ce8c6aSad }
19392ce8c6aSad 
19492ce8c6aSad void
nfs_iodfini(void)19592ce8c6aSad nfs_iodfini(void)
19692ce8c6aSad {
197b083a17fSmartin 	int error __diagused;
19892ce8c6aSad 
19992ce8c6aSad 	error = nfs_set_niothreads(0);
20092ce8c6aSad 	KASSERT(error == 0);
20192ce8c6aSad 	mutex_destroy(&nfs_iodlist_lock);
20292ce8c6aSad }
20392ce8c6aSad 
20492ce8c6aSad int
nfs_iodbusy(struct nfsmount * nmp)20545ab7f23Smanu nfs_iodbusy(struct nfsmount *nmp)
20645ab7f23Smanu {
20745ab7f23Smanu 	struct nfs_iod *iod;
20845ab7f23Smanu 	int ret = 0;
20945ab7f23Smanu 
21045ab7f23Smanu 	mutex_enter(&nfs_iodlist_lock);
21145ab7f23Smanu 	LIST_FOREACH(iod, &nfs_iodlist_all, nid_all) {
21245ab7f23Smanu 		if (iod->nid_mount == nmp)
21345ab7f23Smanu 			ret++;
21445ab7f23Smanu 	}
21545ab7f23Smanu 	mutex_exit(&nfs_iodlist_lock);
21645ab7f23Smanu 
21745ab7f23Smanu 	return ret;
21845ab7f23Smanu }
21945ab7f23Smanu 
22045ab7f23Smanu int
nfs_set_niothreads(int newval)22192ce8c6aSad nfs_set_niothreads(int newval)
22292ce8c6aSad {
22392ce8c6aSad 	struct nfs_iod *nid;
22492ce8c6aSad 	int error = 0;
22592ce8c6aSad         int hold_count;
22692ce8c6aSad 
22792ce8c6aSad 	KERNEL_UNLOCK_ALL(curlwp, &hold_count);
22892ce8c6aSad 
22992ce8c6aSad 	mutex_enter(&nfs_iodlist_lock);
23092ce8c6aSad 	/* clamp to sane range */
231d1579b2dSriastradh 	nfs_niothreads = uimax(0, uimin(newval, NFS_MAXASYNCDAEMON));
23292ce8c6aSad 
23392ce8c6aSad 	while (nfs_numasync != nfs_niothreads && error == 0) {
23492ce8c6aSad 		while (nfs_numasync < nfs_niothreads) {
23592ce8c6aSad 
23692ce8c6aSad 			/*
23792ce8c6aSad 			 * kthread_create can wait for pagedaemon and
23892ce8c6aSad 			 * pagedaemon can wait for nfsiod which needs to acquire
23992ce8c6aSad 			 * nfs_iodlist_lock.
24092ce8c6aSad 			 */
24192ce8c6aSad 
24292ce8c6aSad 			mutex_exit(&nfs_iodlist_lock);
24392ce8c6aSad 			error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
24492ce8c6aSad 			    nfssvc_iod, NULL, NULL, "nfsio");
24592ce8c6aSad 			mutex_enter(&nfs_iodlist_lock);
24692ce8c6aSad 			if (error) {
24792ce8c6aSad 				/* give up */
24892ce8c6aSad 				nfs_niothreads = nfs_numasync;
24992ce8c6aSad 				break;
25092ce8c6aSad 			}
25192ce8c6aSad 			nfs_numasync++;
25292ce8c6aSad 		}
25392ce8c6aSad 		while (nfs_numasync > nfs_niothreads) {
25492ce8c6aSad 			nid = LIST_FIRST(&nfs_iodlist_all);
25592ce8c6aSad 			if (nid == NULL) {
25692ce8c6aSad 				/* iod has not started yet. */
25792ce8c6aSad 				kpause("nfsiorm", false, hz, &nfs_iodlist_lock);
25892ce8c6aSad 				continue;
25992ce8c6aSad 			}
26092ce8c6aSad 			LIST_REMOVE(nid, nid_all);
26192ce8c6aSad 			mutex_enter(&nid->nid_lock);
26292ce8c6aSad 			KASSERT(!nid->nid_exiting);
26392ce8c6aSad 			nid->nid_exiting = true;
26492ce8c6aSad 			cv_signal(&nid->nid_cv);
26592ce8c6aSad 			mutex_exit(&nid->nid_lock);
26692ce8c6aSad 			nfs_numasync--;
26792ce8c6aSad 		}
26892ce8c6aSad 	}
26992ce8c6aSad 	mutex_exit(&nfs_iodlist_lock);
27092ce8c6aSad 
27192ce8c6aSad 	KERNEL_LOCK(hold_count, curlwp);
27292ce8c6aSad 	return error;
27392ce8c6aSad }
27492ce8c6aSad 
27592ce8c6aSad /*
27692ce8c6aSad  * Get an authorization string for the uid by having the mount_nfs sitting
27792ce8c6aSad  * on this mount point porpous out of the kernel and do it.
27892ce8c6aSad  */
27992ce8c6aSad int
nfs_getauth(struct nfsmount * nmp,struct nfsreq * rep,kauth_cred_t cred,char ** auth_str,int * auth_len,char * verf_str,int * verf_len,NFSKERBKEY_T key)28082357f6dSdsl nfs_getauth(struct nfsmount *nmp, struct nfsreq *rep, kauth_cred_t cred, char **auth_str, int *auth_len, char *verf_str, int *verf_len, NFSKERBKEY_T key)
28182357f6dSdsl 	/* key:		 return session key */
28292ce8c6aSad {
28392ce8c6aSad 	int error = 0;
28492ce8c6aSad 
28592ce8c6aSad 	while ((nmp->nm_iflag & NFSMNT_WAITAUTH) == 0) {
28692ce8c6aSad 		nmp->nm_iflag |= NFSMNT_WANTAUTH;
28792ce8c6aSad 		(void) tsleep((void *)&nmp->nm_authtype, PSOCK,
28892ce8c6aSad 			"nfsauth1", 2 * hz);
28992ce8c6aSad 		error = nfs_sigintr(nmp, rep, rep->r_lwp);
29092ce8c6aSad 		if (error) {
29192ce8c6aSad 			nmp->nm_iflag &= ~NFSMNT_WANTAUTH;
29292ce8c6aSad 			return (error);
29392ce8c6aSad 		}
29492ce8c6aSad 	}
29592ce8c6aSad 	nmp->nm_iflag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
29692ce8c6aSad 	nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
29792ce8c6aSad 	nmp->nm_authlen = RPCAUTH_MAXSIZ;
29892ce8c6aSad 	nmp->nm_verfstr = verf_str;
29992ce8c6aSad 	nmp->nm_verflen = *verf_len;
30092ce8c6aSad 	nmp->nm_authuid = kauth_cred_geteuid(cred);
30192ce8c6aSad 	wakeup((void *)&nmp->nm_authstr);
30292ce8c6aSad 
30392ce8c6aSad 	/*
30492ce8c6aSad 	 * And wait for mount_nfs to do its stuff.
30592ce8c6aSad 	 */
30692ce8c6aSad 	while ((nmp->nm_iflag & NFSMNT_HASAUTH) == 0 && error == 0) {
30792ce8c6aSad 		(void) tsleep((void *)&nmp->nm_authlen, PSOCK,
30892ce8c6aSad 			"nfsauth2", 2 * hz);
30992ce8c6aSad 		error = nfs_sigintr(nmp, rep, rep->r_lwp);
31092ce8c6aSad 	}
31192ce8c6aSad 	if (nmp->nm_iflag & NFSMNT_AUTHERR) {
31292ce8c6aSad 		nmp->nm_iflag &= ~NFSMNT_AUTHERR;
31392ce8c6aSad 		error = EAUTH;
31492ce8c6aSad 	}
31592ce8c6aSad 	if (error)
31692ce8c6aSad 		free((void *)*auth_str, M_TEMP);
31792ce8c6aSad 	else {
31892ce8c6aSad 		*auth_len = nmp->nm_authlen;
31992ce8c6aSad 		*verf_len = nmp->nm_verflen;
32092ce8c6aSad 		memcpy(key, nmp->nm_key, sizeof (NFSKERBKEY_T));
32192ce8c6aSad 	}
32292ce8c6aSad 	nmp->nm_iflag &= ~NFSMNT_HASAUTH;
32392ce8c6aSad 	nmp->nm_iflag |= NFSMNT_WAITAUTH;
32492ce8c6aSad 	if (nmp->nm_iflag & NFSMNT_WANTAUTH) {
32592ce8c6aSad 		nmp->nm_iflag &= ~NFSMNT_WANTAUTH;
32692ce8c6aSad 		wakeup((void *)&nmp->nm_authtype);
32792ce8c6aSad 	}
32892ce8c6aSad 	return (error);
32992ce8c6aSad }
33092ce8c6aSad 
33192ce8c6aSad /*
33292ce8c6aSad  * Get a nickname authenticator and verifier.
33392ce8c6aSad  */
33492ce8c6aSad int
nfs_getnickauth(struct nfsmount * nmp,kauth_cred_t cred,char ** auth_str,int * auth_len,char * verf_str,int verf_len)33592ce8c6aSad nfs_getnickauth(struct nfsmount *nmp, kauth_cred_t cred, char **auth_str,
33692ce8c6aSad     int *auth_len, char *verf_str, int verf_len)
33792ce8c6aSad {
338cbb31ed1Smartin #ifdef NFSKERB
339cbb31ed1Smartin 	struct timeval ktvin;
340cbb31ed1Smartin #endif
341cbb31ed1Smartin 	struct timeval ktvout, tv;
34292ce8c6aSad 	struct nfsuid *nuidp;
34392ce8c6aSad 	u_int32_t *nickp, *verfp;
34492ce8c6aSad 
34592ce8c6aSad 	memset(&ktvout, 0, sizeof ktvout);	/* XXX gcc */
34692ce8c6aSad 
34792ce8c6aSad #ifdef DIAGNOSTIC
34892ce8c6aSad 	if (verf_len < (4 * NFSX_UNSIGNED))
34992ce8c6aSad 		panic("nfs_getnickauth verf too small");
35092ce8c6aSad #endif
35192ce8c6aSad 	LIST_FOREACH(nuidp, NMUIDHASH(nmp, kauth_cred_geteuid(cred)), nu_hash) {
35292ce8c6aSad 		if (kauth_cred_geteuid(nuidp->nu_cr) == kauth_cred_geteuid(cred))
35392ce8c6aSad 			break;
35492ce8c6aSad 	}
35592ce8c6aSad 	if (!nuidp || nuidp->nu_expire < time_second)
35692ce8c6aSad 		return (EACCES);
35792ce8c6aSad 
35892ce8c6aSad 	/*
35992ce8c6aSad 	 * Move to the end of the lru list (end of lru == most recently used).
36092ce8c6aSad 	 */
36192ce8c6aSad 	TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
36292ce8c6aSad 	TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
36392ce8c6aSad 
36492ce8c6aSad 	nickp = (u_int32_t *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
36592ce8c6aSad 	*nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
36692ce8c6aSad 	*nickp = txdr_unsigned(nuidp->nu_nickname);
36792ce8c6aSad 	*auth_str = (char *)nickp;
36892ce8c6aSad 	*auth_len = 2 * NFSX_UNSIGNED;
36992ce8c6aSad 
37092ce8c6aSad 	/*
37192ce8c6aSad 	 * Now we must encrypt the verifier and package it up.
37292ce8c6aSad 	 */
37392ce8c6aSad 	verfp = (u_int32_t *)verf_str;
37492ce8c6aSad 	*verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
37592ce8c6aSad 	getmicrotime(&tv);
37692ce8c6aSad 	if (tv.tv_sec > nuidp->nu_timestamp.tv_sec ||
37792ce8c6aSad 	    (tv.tv_sec == nuidp->nu_timestamp.tv_sec &&
37892ce8c6aSad 	     tv.tv_usec > nuidp->nu_timestamp.tv_usec))
37992ce8c6aSad 		nuidp->nu_timestamp = tv;
38092ce8c6aSad 	else
38192ce8c6aSad 		nuidp->nu_timestamp.tv_usec++;
382cbb31ed1Smartin #ifdef NFSKERB
38392ce8c6aSad 	ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
38492ce8c6aSad 	ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
38592ce8c6aSad 
38692ce8c6aSad 	/*
38792ce8c6aSad 	 * Now encrypt the timestamp verifier in ecb mode using the session
38892ce8c6aSad 	 * key.
38992ce8c6aSad 	 */
39092ce8c6aSad 	XXX
39192ce8c6aSad #endif
39292ce8c6aSad 
39392ce8c6aSad 	*verfp++ = ktvout.tv_sec;
39492ce8c6aSad 	*verfp++ = ktvout.tv_usec;
39592ce8c6aSad 	*verfp = 0;
39692ce8c6aSad 	return (0);
39792ce8c6aSad }
39892ce8c6aSad 
39992ce8c6aSad /*
40092ce8c6aSad  * Save the current nickname in a hash list entry on the mount point.
40192ce8c6aSad  */
40292ce8c6aSad int
nfs_savenickauth(struct nfsmount * nmp,kauth_cred_t cred,int len,NFSKERBKEY_T key,struct mbuf ** mdp,char ** dposp,struct mbuf * mrep)403454af1c0Sdsl nfs_savenickauth(struct nfsmount *nmp, kauth_cred_t cred, int len, NFSKERBKEY_T key, struct mbuf **mdp, char **dposp, struct mbuf *mrep)
40492ce8c6aSad {
40592ce8c6aSad 	struct nfsuid *nuidp;
40692ce8c6aSad 	u_int32_t *tl;
40792ce8c6aSad 	int32_t t1;
40892ce8c6aSad 	struct mbuf *md = *mdp;
40992ce8c6aSad 	struct timeval ktvin, ktvout;
41092ce8c6aSad 	u_int32_t nick;
41192ce8c6aSad 	char *dpos = *dposp, *cp2;
412*93c8adadSchristos 	time_t deltasec;
413*93c8adadSchristos 	int error = 0;
41492ce8c6aSad 
41592ce8c6aSad 	memset(&ktvout, 0, sizeof ktvout);	 /* XXX gcc */
41692ce8c6aSad 
41792ce8c6aSad 	if (len == (3 * NFSX_UNSIGNED)) {
41892ce8c6aSad 		nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
41992ce8c6aSad 		ktvin.tv_sec = *tl++;
42092ce8c6aSad 		ktvin.tv_usec = *tl++;
42192ce8c6aSad 		nick = fxdr_unsigned(u_int32_t, *tl);
42292ce8c6aSad 
42392ce8c6aSad 		/*
42492ce8c6aSad 		 * Decrypt the timestamp in ecb mode.
42592ce8c6aSad 		 */
42692ce8c6aSad #ifdef NFSKERB
42792ce8c6aSad 		XXX
428cbb31ed1Smartin #else
429cbb31ed1Smartin 		(void)ktvin.tv_sec;
43092ce8c6aSad #endif
43192ce8c6aSad 		ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
43292ce8c6aSad 		ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
43392ce8c6aSad 		deltasec = time_second - ktvout.tv_sec;
43492ce8c6aSad 		if (deltasec < 0)
43592ce8c6aSad 			deltasec = -deltasec;
43692ce8c6aSad 		/*
43792ce8c6aSad 		 * If ok, add it to the hash list for the mount point.
43892ce8c6aSad 		 */
43992ce8c6aSad 		if (deltasec <= NFS_KERBCLOCKSKEW) {
44092ce8c6aSad 			if (nmp->nm_numuids < nuidhash_max) {
44192ce8c6aSad 				nmp->nm_numuids++;
44292ce8c6aSad 				nuidp = kmem_alloc(sizeof(*nuidp), KM_SLEEP);
44392ce8c6aSad 			} else {
44492ce8c6aSad 				nuidp = TAILQ_FIRST(&nmp->nm_uidlruhead);
44592ce8c6aSad 				LIST_REMOVE(nuidp, nu_hash);
44692ce8c6aSad 				TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
44792ce8c6aSad 					nu_lru);
44892ce8c6aSad 			}
44992ce8c6aSad 			nuidp->nu_flag = 0;
45092ce8c6aSad 			kauth_cred_seteuid(nuidp->nu_cr, kauth_cred_geteuid(cred));
45192ce8c6aSad 			nuidp->nu_expire = time_second + NFS_KERBTTL;
45292ce8c6aSad 			nuidp->nu_timestamp = ktvout;
45392ce8c6aSad 			nuidp->nu_nickname = nick;
45492ce8c6aSad 			memcpy(nuidp->nu_key, key, sizeof (NFSKERBKEY_T));
45592ce8c6aSad 			TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
45692ce8c6aSad 				nu_lru);
45792ce8c6aSad 			LIST_INSERT_HEAD(NMUIDHASH(nmp, kauth_cred_geteuid(cred)),
45892ce8c6aSad 				nuidp, nu_hash);
45992ce8c6aSad 		}
46092ce8c6aSad 	} else
46192ce8c6aSad 		nfsm_adv(nfsm_rndup(len));
46292ce8c6aSad nfsmout:
46392ce8c6aSad 	*mdp = md;
46492ce8c6aSad 	*dposp = dpos;
46592ce8c6aSad 	return (error);
46692ce8c6aSad }
467