2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95
37 * $FreeBSD: src/sys/nfs/nfs_syscalls.c,v 1.58.2.1 2000/11/26 02:30:06 dillon Exp $
38 * $DragonFly: src/sys/vfs/nfs/nfs_syscalls.c,v 1.31 2008/01/05 14:02:41 swildner Exp $
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/sysproto.h>
44 #include <sys/kernel.h>
45 #include <sys/sysctl.h>
47 #include <sys/filedesc.h>
48 #include <sys/vnode.h>
49 #include <sys/malloc.h>
50 #include <sys/mount.h>
55 #include <sys/resourcevar.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <sys/domain.h>
59 #include <sys/protosw.h>
60 #include <sys/nlookup.h>
61 #include <sys/mutex.h>
62 #include <vm/vm_zone.h>
64 #include <sys/mutex2.h>
66 #include <netinet/in.h>
67 #include <netinet/tcp.h>
72 #include "nfsm_subs.h"
73 #include "nfsrvcache.h"
78 #include <sys/thread2.h>
80 static MALLOC_DEFINE(M_NFSSVC
, "NFS srvsock", "Nfs server structure");
82 static int nuidhash_max
= NFS_MAXUIDHASH
;
85 static void nfsrv_zapsock (struct nfssvc_sock
*slp
);
91 SYSCTL_DECL(_vfs_nfs
);
95 static struct nfsdrt nfsdrt
;
96 static int nfs_numnfsd
= 0;
97 static void nfsd_rt (int sotype
, struct nfsrv_descript
*nd
,
99 static int nfssvc_addsock (struct file
*, struct sockaddr
*,
101 static int nfssvc_nfsd (struct nfsd_srvargs
*,caddr_t
,struct thread
*);
103 static int nfs_privport
= 0;
104 SYSCTL_INT(_vfs_nfs
, NFS_NFSPRIVPORT
, nfs_privport
, CTLFLAG_RW
, &nfs_privport
, 0, "");
105 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, gatherdelay
, CTLFLAG_RW
, &nfsrvw_procrastinate
, 0, "");
106 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, gatherdelay_v3
, CTLFLAG_RW
, &nfsrvw_procrastinate_v3
, 0, "");
107 int nfs_soreserve
= NFS_MAXPACKET
* NFS_MAXASYNCBIO
;
108 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, soreserve
, CTLFLAG_RW
, &nfs_soreserve
, 0, "");
111 * NFS server system calls
114 #endif /* NFS_NOSERVER */
116 * nfssvc_args(int flag, caddr_t argp)
118 * Nfs server psuedo system call for the nfsd's
119 * Based on the flag value it either:
120 * - adds a socket to the selection list
121 * - remains in the kernel as an nfsd
122 * - remains in the kernel as an nfsiod
125 sys_nfssvc(struct nfssvc_args
*uap
)
128 struct nlookupdata nd
;
130 struct sockaddr
*nam
;
131 struct nfsd_args nfsdarg
;
132 struct nfsd_srvargs nfsd_srvargs
, *nsd
= &nfsd_srvargs
;
133 struct nfsd_cargs ncd
;
135 struct nfssvc_sock
*slp
;
136 struct nfsuid
*nuidp
;
137 struct nfsmount
*nmp
;
139 #endif /* NFS_NOSERVER */
141 struct thread
*td
= curthread
;
146 error
= priv_check(td
, PRIV_ROOT
);
149 KKASSERT(td
->td_proc
); /* for ucred and p_fd */
150 while (nfssvc_sockhead_flag
& SLP_INIT
) {
151 nfssvc_sockhead_flag
|= SLP_WANTINIT
;
152 (void) tsleep((caddr_t
)&nfssvc_sockhead
, 0, "nfsd init", 0);
154 if (uap
->flag
& NFSSVC_BIOD
)
155 error
= ENXIO
; /* no longer need nfsiod's */
159 #else /* !NFS_NOSERVER */
160 else if (uap
->flag
& NFSSVC_MNTD
) {
161 error
= copyin(uap
->argp
, (caddr_t
)&ncd
, sizeof (ncd
));
165 error
= nlookup_init(&nd
, ncd
.ncd_dirp
, UIO_USERSPACE
,
168 error
= nlookup(&nd
);
170 error
= cache_vget(&nd
.nl_nch
, nd
.nl_cred
, LK_EXCLUSIVE
, &vp
);
175 if ((vp
->v_flag
& VROOT
) == 0)
177 nmp
= VFSTONFS(vp
->v_mount
);
181 if ((nmp
->nm_state
& NFSSTA_MNTD
) &&
182 (uap
->flag
& NFSSVC_GOTAUTH
) == 0)
184 nmp
->nm_state
|= NFSSTA_MNTD
;
185 error
= nfs_clientd(nmp
, td
->td_proc
->p_ucred
, &ncd
, uap
->flag
,
187 } else if (uap
->flag
& NFSSVC_ADDSOCK
) {
188 error
= copyin(uap
->argp
, (caddr_t
)&nfsdarg
, sizeof(nfsdarg
));
191 error
= holdsock(td
->td_proc
->p_fd
, nfsdarg
.sock
, &fp
);
195 * Get the client address for connected sockets.
197 if (nfsdarg
.name
== NULL
|| nfsdarg
.namelen
== 0)
200 error
= getsockaddr(&nam
, nfsdarg
.name
,
207 error
= nfssvc_addsock(fp
, nam
, td
);
210 error
= copyin(uap
->argp
, (caddr_t
)nsd
, sizeof (*nsd
));
213 if ((uap
->flag
& NFSSVC_AUTHIN
) &&
214 ((nfsd
= nsd
->nsd_nfsd
)) != NULL
&&
215 (nfsd
->nfsd_slp
->ns_flag
& SLP_VALID
)) {
216 slp
= nfsd
->nfsd_slp
;
219 * First check to see if another nfsd has already
220 * added this credential.
222 for (nuidp
= NUIDHASH(slp
,nsd
->nsd_cr
.cr_uid
)->lh_first
;
223 nuidp
!= 0; nuidp
= nuidp
->nu_hash
.le_next
) {
224 if (nuidp
->nu_cr
.cr_uid
== nsd
->nsd_cr
.cr_uid
&&
225 (!nfsd
->nfsd_nd
->nd_nam2
||
226 netaddr_match(NU_NETFAM(nuidp
),
227 &nuidp
->nu_haddr
, nfsd
->nfsd_nd
->nd_nam2
)))
231 nfsrv_setcred(&nuidp
->nu_cr
,&nfsd
->nfsd_nd
->nd_cr
);
232 nfsd
->nfsd_nd
->nd_flag
|= ND_KERBFULL
;
237 if (slp
->ns_numuids
< nuidhash_max
) {
239 nuidp
= (struct nfsuid
*)
240 kmalloc(sizeof (struct nfsuid
), M_NFSUID
,
244 if ((slp
->ns_flag
& SLP_VALID
) == 0) {
246 kfree((caddr_t
)nuidp
, M_NFSUID
);
249 nuidp
= TAILQ_FIRST(&slp
->ns_uidlruhead
);
250 LIST_REMOVE(nuidp
, nu_hash
);
251 TAILQ_REMOVE(&slp
->ns_uidlruhead
, nuidp
,
253 if (nuidp
->nu_flag
& NU_NAM
)
254 FREE(nuidp
->nu_nam
, M_SONAME
);
257 nuidp
->nu_cr
= nsd
->nsd_cr
;
258 if (nuidp
->nu_cr
.cr_ngroups
> NGROUPS
)
259 nuidp
->nu_cr
.cr_ngroups
= NGROUPS
;
260 nuidp
->nu_cr
.cr_ref
= 1;
261 nuidp
->nu_timestamp
= nsd
->nsd_timestamp
;
262 nuidp
->nu_expire
= time_second
+ nsd
->nsd_ttl
;
264 * and save the session key in nu_key.
266 bcopy(nsd
->nsd_key
, nuidp
->nu_key
,
267 sizeof (nsd
->nsd_key
));
268 if (nfsd
->nfsd_nd
->nd_nam2
) {
269 struct sockaddr_in
*saddr
;
271 saddr
= (struct sockaddr_in
*)
272 nfsd
->nfsd_nd
->nd_nam2
;
273 switch (saddr
->sin_family
) {
275 nuidp
->nu_flag
|= NU_INETADDR
;
277 saddr
->sin_addr
.s_addr
;
281 nuidp
->nu_flag
|= NU_NAM
;
283 dup_sockaddr(nfsd
->nfsd_nd
->nd_nam2
);
287 TAILQ_INSERT_TAIL(&slp
->ns_uidlruhead
, nuidp
,
289 LIST_INSERT_HEAD(NUIDHASH(slp
, nsd
->nsd_uid
),
291 nfsrv_setcred(&nuidp
->nu_cr
,
292 &nfsd
->nfsd_nd
->nd_cr
);
293 nfsd
->nfsd_nd
->nd_flag
|= ND_KERBFULL
;
297 if ((uap
->flag
& NFSSVC_AUTHINFAIL
) && (nfsd
= nsd
->nsd_nfsd
))
298 nfsd
->nfsd_flag
|= NFSD_AUTHFAIL
;
299 error
= nfssvc_nfsd(nsd
, uap
->argp
, td
);
301 #endif /* NFS_NOSERVER */
302 if (error
== EINTR
|| error
== ERESTART
)
309 * Adds a socket to the list for servicing by nfsds.
312 nfssvc_addsock(struct file
*fp
, struct sockaddr
*mynam
, struct thread
*td
)
315 struct nfssvc_sock
*slp
;
319 so
= (struct socket
*)fp
->f_data
;
323 * Add it to the list, as required.
325 if (so
->so_proto
->pr_protocol
== IPPROTO_UDP
) {
327 if (tslp
->ns_flag
& SLP_VALID
) {
329 FREE(mynam
, M_SONAME
);
335 * Reserve buffer space in the socket. Note that due to bugs in
336 * Linux's delayed-ack code, serious performance degredation may
337 * occur with linux hosts if the minimum is used.
339 * NFS sockets are not limited to the standard sb_max or by
342 if (so
->so_type
== SOCK_STREAM
)
343 siz
= NFS_MAXPACKET
+ sizeof (u_long
);
346 if (siz
< nfs_soreserve
)
349 error
= soreserve(so
, siz
, siz
, NULL
);
352 FREE(mynam
, M_SONAME
);
357 * Set protocol specific options { for now TCP only } and
358 * reserve some space. For datagram sockets, this can get called
359 * repeatedly for the same socket, but that isn't harmful.
361 if (so
->so_type
== SOCK_STREAM
) {
365 bzero(&sopt
, sizeof sopt
);
366 sopt
.sopt_level
= SOL_SOCKET
;
367 sopt
.sopt_name
= SO_KEEPALIVE
;
368 sopt
.sopt_val
= &val
;
369 sopt
.sopt_valsize
= sizeof val
;
373 if (so
->so_proto
->pr_domain
->dom_family
== AF_INET
&&
374 so
->so_proto
->pr_protocol
== IPPROTO_TCP
) {
378 bzero(&sopt
, sizeof sopt
);
379 sopt
.sopt_level
= IPPROTO_TCP
;
380 sopt
.sopt_name
= TCP_NODELAY
;
381 sopt
.sopt_val
= &val
;
382 sopt
.sopt_valsize
= sizeof val
;
386 so
->so_rcv
.ssb_flags
&= ~SSB_NOINTR
;
387 so
->so_rcv
.ssb_timeo
= 0;
388 so
->so_snd
.ssb_flags
&= ~SSB_NOINTR
;
389 so
->so_snd
.ssb_timeo
= 0;
391 slp
= (struct nfssvc_sock
*)kmalloc(sizeof (struct nfssvc_sock
),
392 M_NFSSVC
, M_WAITOK
| M_ZERO
);
393 mtx_init(&slp
->ns_solock
);
394 STAILQ_INIT(&slp
->ns_rec
);
395 TAILQ_INIT(&slp
->ns_uidlruhead
);
396 TAILQ_INSERT_TAIL(&nfssvc_sockhead
, slp
, ns_chain
);
403 so
->so_upcallarg
= (caddr_t
)slp
;
404 so
->so_upcall
= nfsrv_rcv
;
405 so
->so_rcv
.ssb_flags
|= SSB_UPCALL
;
406 slp
->ns_flag
= (SLP_VALID
| SLP_NEEDQ
);
407 nfsrv_wakenfsd(slp
, 1);
413 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
414 * until it is killed by a signal.
417 nfssvc_nfsd(struct nfsd_srvargs
*nsd
, caddr_t argp
, struct thread
*td
)
420 struct nfssvc_sock
*slp
;
421 struct nfsd
*nfsd
= nsd
->nsd_nfsd
;
422 struct nfsrv_descript
*nd
= NULL
;
423 struct mbuf
*m
, *mreq
;
424 int error
= 0, cacherep
, sotype
, writes_todo
;
433 nsd
->nsd_nfsd
= nfsd
= (struct nfsd
*)
434 kmalloc(sizeof (struct nfsd
), M_NFSD
, M_WAITOK
|M_ZERO
);
437 TAILQ_INSERT_TAIL(&nfsd_head
, nfsd
, nfsd_chain
);
443 * Loop getting rpc requests until SIGKILL.
446 if ((nfsd
->nfsd_flag
& NFSD_REQINPROG
) == 0) {
447 while (nfsd
->nfsd_slp
== NULL
&&
448 (nfsd_head_flag
& NFSD_CHECKSLP
) == 0) {
449 nfsd
->nfsd_flag
|= NFSD_WAITING
;
451 error
= tsleep((caddr_t
)nfsd
, PCATCH
, "nfsd", 0);
456 if (nfsd
->nfsd_slp
== NULL
&&
457 (nfsd_head_flag
& NFSD_CHECKSLP
) != 0) {
458 TAILQ_FOREACH(slp
, &nfssvc_sockhead
, ns_chain
) {
459 if ((slp
->ns_flag
& (SLP_VALID
| SLP_DOREC
))
460 == (SLP_VALID
| SLP_DOREC
)) {
461 slp
->ns_flag
&= ~SLP_DOREC
;
463 nfsd
->nfsd_slp
= slp
;
468 nfsd_head_flag
&= ~NFSD_CHECKSLP
;
470 if ((slp
= nfsd
->nfsd_slp
) == NULL
)
472 if (slp
->ns_flag
& SLP_VALID
) {
473 if (slp
->ns_flag
& SLP_DISCONN
)
475 else if (slp
->ns_flag
& SLP_NEEDQ
) {
476 slp
->ns_flag
&= ~SLP_NEEDQ
;
477 (void) nfs_slplock(slp
, 1);
478 nfsrv_rcv(slp
->ns_so
, (caddr_t
)slp
,
482 error
= nfsrv_dorec(slp
, nfsd
, &nd
);
483 cur_usec
= nfs_curusec();
484 if (error
&& slp
->ns_tq
.lh_first
&&
485 slp
->ns_tq
.lh_first
->nd_time
<= cur_usec
) {
491 nfsd
->nfsd_flag
|= NFSD_REQINPROG
;
495 slp
= nfsd
->nfsd_slp
;
497 if (error
|| (slp
->ns_flag
& SLP_VALID
) == 0) {
499 kfree((caddr_t
)nd
, M_NFSRVDESC
);
502 nfsd
->nfsd_slp
= NULL
;
503 nfsd
->nfsd_flag
&= ~NFSD_REQINPROG
;
508 sotype
= slp
->ns_so
->so_type
;
510 getmicrotime(&nd
->nd_starttime
);
512 nd
->nd_nam
= nd
->nd_nam2
;
514 nd
->nd_nam
= slp
->ns_nam
;
517 * Check to see if authorization is needed.
519 if (nfsd
->nfsd_flag
& NFSD_NEEDAUTH
) {
520 nfsd
->nfsd_flag
&= ~NFSD_NEEDAUTH
;
522 ((struct sockaddr_in
*)
523 nd
->nd_nam
)->sin_addr
.s_addr
;
524 nsd
->nsd_authlen
= nfsd
->nfsd_authlen
;
525 nsd
->nsd_verflen
= nfsd
->nfsd_verflen
;
526 if (!copyout(nfsd
->nfsd_authstr
,nsd
->nsd_authstr
,
527 nfsd
->nfsd_authlen
) &&
528 !copyout(nfsd
->nfsd_verfstr
, nsd
->nsd_verfstr
,
529 nfsd
->nfsd_verflen
) &&
530 !copyout((caddr_t
)nsd
, argp
, sizeof (*nsd
)))
532 cacherep
= RC_DROPIT
;
534 cacherep
= nfsrv_getcache(nd
, slp
, &mreq
);
537 if (nfsd
->nfsd_flag
& NFSD_AUTHFAIL
) {
538 nfsd
->nfsd_flag
&= ~NFSD_AUTHFAIL
;
539 nd
->nd_procnum
= NFSPROC_NOOP
;
540 nd
->nd_repstat
= (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
542 } else if (nfs_privport
) {
543 /* Check if source port is privileged */
545 struct sockaddr
*nam
= nd
->nd_nam
;
546 struct sockaddr_in
*sin
;
548 sin
= (struct sockaddr_in
*)nam
;
549 port
= ntohs(sin
->sin_port
);
550 if (port
>= IPPORT_RESERVED
&&
551 nd
->nd_procnum
!= NFSPROC_NULL
) {
552 nd
->nd_procnum
= NFSPROC_NOOP
;
553 nd
->nd_repstat
= (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
555 kprintf("NFS request from unprivileged port (%s:%d)\n",
556 inet_ntoa(sin
->sin_addr
), port
);
563 * Loop to get all the write rpc relies that have been
569 if (nd
&& (nd
->nd_flag
& ND_NFSV3
))
570 procrastinate
= nfsrvw_procrastinate_v3
;
572 procrastinate
= nfsrvw_procrastinate
;
573 if (writes_todo
|| (nd
->nd_procnum
== NFSPROC_WRITE
&&
576 error
= nfsrv_writegather(&nd
, slp
,
577 nfsd
->nfsd_td
, &mreq
);
579 error
= (*(nfsrv3_procs
[nd
->nd_procnum
]))(nd
,
580 slp
, nfsd
->nfsd_td
, &mreq
);
584 if (error
!= 0 && error
!= NFSERR_RETVOID
) {
585 if (nd
->nd_procnum
!= NQNFSPROC_VACATED
)
587 nfsrv_updatecache(nd
, FALSE
, mreq
);
589 FREE(nd
->nd_nam2
, M_SONAME
);
592 nfsstats
.srvrpccnt
[nd
->nd_procnum
]++;
593 nfsrv_updatecache(nd
, TRUE
, mreq
);
602 if (siz
<= 0 || siz
> NFS_MAXPACKET
) {
603 kprintf("mbuf siz=%d\n",siz
);
604 panic("Bad nfs svc reply");
607 m
->m_pkthdr
.len
= siz
;
608 m
->m_pkthdr
.rcvif
= NULL
;
610 * For stream protocols, prepend a Sun RPC
613 if (sotype
== SOCK_STREAM
) {
614 M_PREPEND(m
, NFSX_UNSIGNED
, MB_WAIT
);
617 *mtod(m
, u_int32_t
*) = htonl(0x80000000 | siz
);
619 if (slp
->ns_so
->so_proto
->pr_flags
& PR_CONNREQUIRED
)
620 (void) nfs_slplock(slp
, 1);
621 if (slp
->ns_flag
& SLP_VALID
)
622 error
= nfs_send(slp
->ns_so
, nd
->nd_nam2
, m
, NULL
);
628 nfsd_rt(sotype
, nd
, cacherep
);
630 FREE(nd
->nd_nam2
, M_SONAME
);
632 m_freem(nd
->nd_mrep
);
635 if (slp
->ns_so
->so_proto
->pr_flags
& PR_CONNREQUIRED
)
637 if (error
== EINTR
|| error
== ERESTART
) {
638 kfree((caddr_t
)nd
, M_NFSRVDESC
);
646 nfsd_rt(sotype
, nd
, cacherep
);
647 m_freem(nd
->nd_mrep
);
649 FREE(nd
->nd_nam2
, M_SONAME
);
653 FREE((caddr_t
)nd
, M_NFSRVDESC
);
658 * Check to see if there are outstanding writes that
659 * need to be serviced.
661 cur_usec
= nfs_curusec();
663 if (slp
->ns_tq
.lh_first
&&
664 slp
->ns_tq
.lh_first
->nd_time
<= cur_usec
) {
670 } while (writes_todo
);
672 if (nfsrv_dorec(slp
, nfsd
, &nd
)) {
673 nfsd
->nfsd_flag
&= ~NFSD_REQINPROG
;
674 nfsd
->nfsd_slp
= NULL
;
679 TAILQ_REMOVE(&nfsd_head
, nfsd
, nfsd_chain
);
681 kfree((caddr_t
)nfsd
, M_NFSD
);
682 nsd
->nsd_nfsd
= NULL
;
683 if (--nfs_numnfsd
== 0)
684 nfsrv_init(TRUE
); /* Reinitialize everything */
689 * Shut down a socket associated with an nfssvc_sock structure.
690 * Should be called with the send lock set, if required.
691 * The trick here is to increment the sref at the start, so that the nfsds
692 * will stop using it and clear ns_flag at the end so that it will not be
693 * reassigned during cleanup.
696 nfsrv_zapsock(struct nfssvc_sock
*slp
)
698 struct nfsuid
*nuidp
, *nnuidp
;
699 struct nfsrv_descript
*nwp
, *nnwp
;
702 struct nfsrv_rec
*rec
;
704 slp
->ns_flag
&= ~SLP_ALLFLAGS
;
709 so
->so_rcv
.ssb_flags
&= ~SSB_UPCALL
;
710 so
->so_upcall
= NULL
;
711 so
->so_upcallarg
= NULL
;
712 soshutdown(so
, SHUT_RDWR
);
715 FREE(slp
->ns_nam
, M_SONAME
);
716 m_freem(slp
->ns_raw
);
717 while ((rec
= STAILQ_FIRST(&slp
->ns_rec
)) != NULL
) {
719 STAILQ_REMOVE_HEAD(&slp
->ns_rec
, nr_link
);
721 FREE(rec
->nr_address
, M_SONAME
);
722 m_freem(rec
->nr_packet
);
723 kfree(rec
, M_NFSRVDESC
);
725 TAILQ_FOREACH_MUTABLE(nuidp
, &slp
->ns_uidlruhead
, nu_lru
,
727 LIST_REMOVE(nuidp
, nu_hash
);
728 TAILQ_REMOVE(&slp
->ns_uidlruhead
, nuidp
, nu_lru
);
729 if (nuidp
->nu_flag
& NU_NAM
)
730 FREE(nuidp
->nu_nam
, M_SONAME
);
731 kfree((caddr_t
)nuidp
, M_NFSUID
);
734 for (nwp
= slp
->ns_tq
.lh_first
; nwp
; nwp
= nnwp
) {
735 nnwp
= nwp
->nd_tq
.le_next
;
736 LIST_REMOVE(nwp
, nd_tq
);
737 kfree((caddr_t
)nwp
, M_NFSRVDESC
);
739 LIST_INIT(&slp
->ns_tq
);
745 * Derefence a server socket structure. If it has no more references and
746 * is no longer valid, you can throw it away.
749 nfsrv_slpderef(struct nfssvc_sock
*slp
)
751 if (--(slp
->ns_sref
) == 0 && (slp
->ns_flag
& SLP_VALID
) == 0) {
752 TAILQ_REMOVE(&nfssvc_sockhead
, slp
, ns_chain
);
753 kfree((caddr_t
)slp
, M_NFSSVC
);
758 * Lock a socket against others.
760 * Returns 0 on failure, 1 on success.
763 nfs_slplock(struct nfssvc_sock
*slp
, int wait
)
765 mtx_t mtx
= &slp
->ns_solock
;
768 mtx_lock_ex(mtx
, "nfsslplck", 0, 0);
770 } else if (mtx_lock_ex_try(mtx
) == 0) {
778 * Unlock the stream socket for others.
781 nfs_slpunlock(struct nfssvc_sock
*slp
)
783 mtx_t mtx
= &slp
->ns_solock
;
789 * Initialize the data structures for the server.
790 * Handshake with any new nfsds starting up to avoid any chance of
794 nfsrv_init(int terminating
)
796 struct nfssvc_sock
*slp
, *nslp
;
798 if (nfssvc_sockhead_flag
& SLP_INIT
)
800 nfssvc_sockhead_flag
|= SLP_INIT
;
802 TAILQ_FOREACH_MUTABLE(slp
, &nfssvc_sockhead
, ns_chain
, nslp
) {
803 if (slp
->ns_flag
& SLP_VALID
)
805 TAILQ_REMOVE(&nfssvc_sockhead
, slp
, ns_chain
);
806 kfree((caddr_t
)slp
, M_NFSSVC
);
808 nfsrv_cleancache(); /* And clear out server cache */
810 nfs_pub
.np_valid
= 0;
812 TAILQ_INIT(&nfssvc_sockhead
);
813 nfssvc_sockhead_flag
&= ~SLP_INIT
;
814 if (nfssvc_sockhead_flag
& SLP_WANTINIT
) {
815 nfssvc_sockhead_flag
&= ~SLP_WANTINIT
;
816 wakeup((caddr_t
)&nfssvc_sockhead
);
819 TAILQ_INIT(&nfsd_head
);
820 nfsd_head_flag
&= ~NFSD_CHECKSLP
;
823 nfs_udpsock
= (struct nfssvc_sock
*)
824 kmalloc(sizeof (struct nfssvc_sock
), M_NFSSVC
, M_WAITOK
| M_ZERO
);
825 mtx_init(&nfs_udpsock
->ns_solock
);
826 STAILQ_INIT(&nfs_udpsock
->ns_rec
);
827 TAILQ_INIT(&nfs_udpsock
->ns_uidlruhead
);
828 TAILQ_INSERT_HEAD(&nfssvc_sockhead
, nfs_udpsock
, ns_chain
);
830 nfs_cltpsock
= (struct nfssvc_sock
*)
831 kmalloc(sizeof (struct nfssvc_sock
), M_NFSSVC
, M_WAITOK
| M_ZERO
);
832 mtx_init(&nfs_cltpsock
->ns_solock
);
833 STAILQ_INIT(&nfs_cltpsock
->ns_rec
);
834 TAILQ_INIT(&nfs_cltpsock
->ns_uidlruhead
);
835 TAILQ_INSERT_TAIL(&nfssvc_sockhead
, nfs_cltpsock
, ns_chain
);
840 * Add entries to the server monitor log.
843 nfsd_rt(int sotype
, struct nfsrv_descript
*nd
, int cacherep
)
847 rt
= &nfsdrt
.drt
[nfsdrt
.pos
];
848 if (cacherep
== RC_DOIT
)
850 else if (cacherep
== RC_REPLY
)
851 rt
->flag
= DRT_CACHEREPLY
;
853 rt
->flag
= DRT_CACHEDROP
;
854 if (sotype
== SOCK_STREAM
)
856 if (nd
->nd_flag
& ND_NFSV3
)
857 rt
->flag
|= DRT_NFSV3
;
858 rt
->proc
= nd
->nd_procnum
;
859 if (nd
->nd_nam
->sa_family
== AF_INET
)
860 rt
->ipadr
= ((struct sockaddr_in
*)nd
->nd_nam
)->sin_addr
.s_addr
;
862 rt
->ipadr
= INADDR_ANY
;
863 rt
->resptime
= nfs_curusec() - (nd
->nd_starttime
.tv_sec
* 1000000 + nd
->nd_starttime
.tv_usec
);
864 getmicrotime(&rt
->tstamp
);
865 nfsdrt
.pos
= (nfsdrt
.pos
+ 1) % NFSRTTLOGSIZ
;
867 #endif /* NFS_NOSERVER */
869 static int nfs_defect
= 0;
870 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, defect
, CTLFLAG_RW
, &nfs_defect
, 0, "");
873 * Get an authorization string for the uid by having the mount_nfs sitting
874 * on this mount point porpous out of the kernel and do it.
877 nfs_getauth(struct nfsmount
*nmp
, struct nfsreq
*rep
,
878 struct ucred
*cred
, char **auth_str
, int *auth_len
, char *verf_str
,
879 int *verf_len
, NFSKERBKEY_T key
/* return session key */)
883 while ((nmp
->nm_state
& NFSSTA_WAITAUTH
) == 0) {
884 nmp
->nm_state
|= NFSSTA_WANTAUTH
;
885 (void) tsleep((caddr_t
)&nmp
->nm_authtype
, 0,
887 error
= nfs_sigintr(nmp
, rep
, rep
->r_td
);
889 nmp
->nm_state
&= ~NFSSTA_WANTAUTH
;
893 nmp
->nm_state
&= ~(NFSSTA_WAITAUTH
| NFSSTA_WANTAUTH
);
894 nmp
->nm_authstr
= *auth_str
= (char *)kmalloc(RPCAUTH_MAXSIZ
, M_TEMP
, M_WAITOK
);
895 nmp
->nm_authlen
= RPCAUTH_MAXSIZ
;
896 nmp
->nm_verfstr
= verf_str
;
897 nmp
->nm_verflen
= *verf_len
;
898 nmp
->nm_authuid
= cred
->cr_uid
;
899 wakeup((caddr_t
)&nmp
->nm_authstr
);
902 * And wait for mount_nfs to do its stuff.
904 while ((nmp
->nm_state
& NFSSTA_HASAUTH
) == 0 && error
== 0) {
905 (void) tsleep((caddr_t
)&nmp
->nm_authlen
, 0,
907 error
= nfs_sigintr(nmp
, rep
, rep
->r_td
);
909 if (nmp
->nm_state
& NFSSTA_AUTHERR
) {
910 nmp
->nm_state
&= ~NFSSTA_AUTHERR
;
914 kfree((caddr_t
)*auth_str
, M_TEMP
);
916 *auth_len
= nmp
->nm_authlen
;
917 *verf_len
= nmp
->nm_verflen
;
918 bcopy((caddr_t
)nmp
->nm_key
, (caddr_t
)key
, sizeof (key
));
920 nmp
->nm_state
&= ~NFSSTA_HASAUTH
;
921 nmp
->nm_state
|= NFSSTA_WAITAUTH
;
922 if (nmp
->nm_state
& NFSSTA_WANTAUTH
) {
923 nmp
->nm_state
&= ~NFSSTA_WANTAUTH
;
924 wakeup((caddr_t
)&nmp
->nm_authtype
);
930 * Get a nickname authenticator and verifier.
933 nfs_getnickauth(struct nfsmount
*nmp
, struct ucred
*cred
, char **auth_str
,
934 int *auth_len
, char *verf_str
, int verf_len
)
936 struct nfsuid
*nuidp
;
937 u_int32_t
*nickp
, *verfp
;
938 struct timeval ktvin
, ktvout
;
941 if (verf_len
< (4 * NFSX_UNSIGNED
))
942 panic("nfs_getnickauth verf too small");
944 for (nuidp
= NMUIDHASH(nmp
, cred
->cr_uid
)->lh_first
;
945 nuidp
!= 0; nuidp
= nuidp
->nu_hash
.le_next
) {
946 if (nuidp
->nu_cr
.cr_uid
== cred
->cr_uid
)
949 if (!nuidp
|| nuidp
->nu_expire
< time_second
)
953 * Move to the end of the lru list (end of lru == most recently used).
955 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
956 TAILQ_INSERT_TAIL(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
958 nickp
= (u_int32_t
*)kmalloc(2 * NFSX_UNSIGNED
, M_TEMP
, M_WAITOK
);
959 *nickp
++ = txdr_unsigned(RPCAKN_NICKNAME
);
960 *nickp
= txdr_unsigned(nuidp
->nu_nickname
);
961 *auth_str
= (char *)nickp
;
962 *auth_len
= 2 * NFSX_UNSIGNED
;
965 * Now we must encrypt the verifier and package it up.
967 verfp
= (u_int32_t
*)verf_str
;
968 *verfp
++ = txdr_unsigned(RPCAKN_NICKNAME
);
969 if (time_second
> nuidp
->nu_timestamp
.tv_sec
||
970 (time_second
== nuidp
->nu_timestamp
.tv_sec
&&
971 time_second
> nuidp
->nu_timestamp
.tv_usec
))
972 getmicrotime(&nuidp
->nu_timestamp
);
974 nuidp
->nu_timestamp
.tv_usec
++;
975 ktvin
.tv_sec
= txdr_unsigned(nuidp
->nu_timestamp
.tv_sec
);
976 ktvin
.tv_usec
= txdr_unsigned(nuidp
->nu_timestamp
.tv_usec
);
979 * Now encrypt the timestamp verifier in ecb mode using the session
989 *verfp
++ = ktvout
.tv_sec
;
990 *verfp
++ = ktvout
.tv_usec
;
996 * Save the current nickname in a hash list entry on the mount point.
999 nfs_savenickauth(struct nfsmount
*nmp
, struct ucred
*cred
, int len
,
1000 NFSKERBKEY_T key
, struct mbuf
**mdp
, char **dposp
,
1003 struct nfsuid
*nuidp
;
1005 struct timeval ktvin
, ktvout
;
1007 int deltasec
, error
= 0;
1008 struct nfsm_info info
;
1014 if (len
== (3 * NFSX_UNSIGNED
)) {
1015 NULLOUT(tl
= nfsm_dissect(&info
, 3 * NFSX_UNSIGNED
));
1016 ktvin
.tv_sec
= *tl
++;
1017 ktvin
.tv_usec
= *tl
++;
1018 nick
= fxdr_unsigned(u_int32_t
, *tl
);
1021 * Decrypt the timestamp in ecb mode.
1029 ktvout
.tv_sec
= fxdr_unsigned(long, ktvout
.tv_sec
);
1030 ktvout
.tv_usec
= fxdr_unsigned(long, ktvout
.tv_usec
);
1031 deltasec
= time_second
- ktvout
.tv_sec
;
1033 deltasec
= -deltasec
;
1035 * If ok, add it to the hash list for the mount point.
1037 if (deltasec
<= NFS_KERBCLOCKSKEW
) {
1038 if (nmp
->nm_numuids
< nuidhash_max
) {
1040 nuidp
= (struct nfsuid
*)
1041 kmalloc(sizeof (struct nfsuid
), M_NFSUID
,
1044 nuidp
= TAILQ_FIRST(&nmp
->nm_uidlruhead
);
1045 LIST_REMOVE(nuidp
, nu_hash
);
1046 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
,
1050 nuidp
->nu_cr
.cr_uid
= cred
->cr_uid
;
1051 nuidp
->nu_expire
= time_second
+ NFS_KERBTTL
;
1052 nuidp
->nu_timestamp
= ktvout
;
1053 nuidp
->nu_nickname
= nick
;
1054 bcopy(key
, nuidp
->nu_key
, sizeof (key
));
1055 TAILQ_INSERT_TAIL(&nmp
->nm_uidlruhead
, nuidp
,
1057 LIST_INSERT_HEAD(NMUIDHASH(nmp
, cred
->cr_uid
),
1061 ERROROUT(nfsm_adv(&info
, nfsm_rndup(len
)));