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