]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_syscalls.c
448b3b9f8604526a1dfa20b55ca7a61b86582df7
[apple/xnu.git] / bsd / nfs / nfs_syscalls.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95
59 * FreeBSD-Id: nfs_syscalls.c,v 1.32 1997/11/07 08:53:25 phk Exp $
60 */
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 /* XXX CSM 11/25/97 FreeBSD's generated syscall prototypes */
65 #ifdef notyet
66 #include <sys/sysproto.h>
67 #endif
68 #include <sys/kernel.h>
69 #include <sys/file.h>
70 #include <sys/filedesc.h>
71 #include <sys/stat.h>
72 #include <sys/vnode.h>
73 #include <sys/mount.h>
74 #include <sys/proc.h>
75 #include <sys/sysctl.h>
76 #include <sys/ubc.h>
77 #include <sys/uio.h>
78 #include <sys/malloc.h>
79 #include <sys/mbuf.h>
80 #include <sys/socket.h>
81 #include <sys/socketvar.h>
82 #include <sys/domain.h>
83 #include <sys/protosw.h>
84 #include <sys/namei.h>
85 #include <sys/fcntl.h>
86 #include <sys/lockf.h>
87 #include <sys/syslog.h>
88 #include <sys/user.h>
89 #include <machine/spl.h>
90
91 #include <netinet/in.h>
92 #include <netinet/tcp.h>
93 #if ISO
94 #include <netiso/iso.h>
95 #endif
96 #include <nfs/xdr_subs.h>
97 #include <nfs/rpcv2.h>
98 #include <nfs/nfsproto.h>
99 #include <nfs/nfs.h>
100 #include <nfs/nfsm_subs.h>
101 #include <nfs/nfsrvcache.h>
102 #include <nfs/nfsmount.h>
103 #include <nfs/nfsnode.h>
104 #include <nfs/nqnfs.h>
105 #include <nfs/nfsrtt.h>
106 #include <nfs/nfs_lock.h>
107
108 /* Global defs. */
109 extern int (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *nd,
110 struct nfssvc_sock *slp,
111 struct proc *procp,
112 struct mbuf **mreqp));
113 extern int nfs_numasync;
114 extern int nfs_ioddelwri;
115 extern time_t nqnfsstarttime;
116 extern int nqsrv_writeslack;
117 extern int nfsrtton;
118 extern struct nfsstats nfsstats;
119 extern int nfsrvw_procrastinate;
120 extern int nfsrvw_procrastinate_v3;
121 struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
122 static int nuidhash_max = NFS_MAXUIDHASH;
123
124 static void nfsrv_zapsock __P((struct nfssvc_sock *slp));
125 static int nfssvc_iod __P((struct proc *));
126
127 #define TRUE 1
128 #define FALSE 0
129
130 static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
131
132 #ifndef NFS_NOSERVER
133 int nfsd_waiting = 0;
134 static struct nfsdrt nfsdrt;
135 static int nfs_numnfsd = 0;
136 static int notstarted = 1;
137 static int modify_flag = 0;
138 static void nfsd_rt __P((int sotype, struct nfsrv_descript *nd,
139 int cacherep));
140 static int nfssvc_addsock __P((struct file *, struct mbuf *,
141 struct proc *));
142 static int nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *));
143
144 static int nfs_privport = 0;
145 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
146 #ifdef notyet
147 SYSCTL_INT(_vfs_nfs, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW, &nfs_privport, 0, "");
148 SYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay, CTLFLAG_RW, &nfsrvw_procrastinate, 0, "");
149 SYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay_v3, CTLFLAG_RW, &nfsrvw_procrastinate_v3, 0, "");
150 #endif
151
152 /*
153 * NFS server system calls
154 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
155 */
156
157 /*
158 * Get file handle system call
159 */
160 #ifndef _SYS_SYSPROTO_H_
161 struct getfh_args {
162 char *fname;
163 fhandle_t *fhp;
164 };
165 #endif
166 int
167 getfh(p, uap)
168 struct proc *p;
169 register struct getfh_args *uap;
170 {
171 register struct vnode *vp;
172 fhandle_t fh;
173 int error;
174 struct nameidata nd;
175
176 /*
177 * Must be super user
178 */
179 error = suser(p->p_ucred, &p->p_acflag);
180 if(error)
181 return (error);
182 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE, uap->fname, p);
183 error = namei(&nd);
184 if (error)
185 return (error);
186 vp = nd.ni_vp;
187 bzero((caddr_t)&fh, sizeof(fh));
188 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
189 error = VFS_VPTOFH(vp, &fh.fh_fid);
190 vput(vp);
191 if (error)
192 return (error);
193 error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
194 return (error);
195 }
196
197 #endif /* NFS_NOSERVER */
198
199 /*
200 * syscall for the rpc.lockd to use to translate a NFS file handle into
201 * an open descriptor.
202 *
203 * warning: do not remove the suser() call or this becomes one giant
204 * security hole.
205 */
206 #ifndef _SYS_SYSPROTO_H_
207 struct fhopen_args {
208 const struct fhandle *u_fhp;
209 int flags;
210 };
211 #endif
212 int
213 fhopen(p, uap, retval)
214 struct proc *p;
215 register struct fhopen_args *uap;
216 register_t *retval;
217 {
218 struct mount *mp;
219 struct vnode *vp;
220 struct fhandle fhp;
221 struct vattr vat;
222 struct vattr *vap = &vat;
223 struct flock lf;
224 struct file *fp;
225 register struct filedesc *fdp = p->p_fd;
226 int fmode, mode, error, type;
227 struct file *nfp;
228 int indx;
229 struct ucred *credanon;
230 int exflags;
231 struct ucred *cred = p->p_ucred;
232 int didhold = 0;
233 extern struct fileops vnops;
234
235 /*
236 * Must be super user
237 */
238 error = suser(cred, &p->p_acflag);
239 if (error)
240 return (error);
241
242 fmode = FFLAGS(uap->flags);
243 /* why not allow a non-read/write open for our lockd? */
244 if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
245 return (EINVAL);
246 error = copyin((void*)uap->u_fhp, &fhp, sizeof(fhp));
247 if (error)
248 return (error);
249 /* find the mount point */
250 mp = vfs_getvfs(&fhp.fh_fsid);
251 if (mp == NULL)
252 return (ESTALE);
253 /* now give me my vnode, it gets returned to me locked */
254 /* XXX CSM need to split VFS_CHECKEXP out of VFS_FHTOVP? */
255 error = VFS_FHTOVP(mp, &fhp.fh_fid, NULL, &vp, &exflags, &credanon);
256 if (error)
257 return (error);
258 /*
259 * from now on we have to make sure not
260 * to forget about the vnode
261 * any error that causes an abort must vput(vp)
262 * just set error = err and 'goto bad;'.
263 */
264
265 /*
266 * from vn_open
267 */
268 if (vp->v_type == VSOCK) {
269 error = EOPNOTSUPP;
270 goto bad;
271 }
272
273 if (UBCINFOEXISTS(vp) && ((didhold = ubc_hold(vp)) == 0)) {
274 error = ENOENT;
275 goto bad;
276 }
277
278 if (fmode & FREAD && fmode & (FWRITE | O_TRUNC)) {
279 int err = 0;
280 if (vp->v_type == VDIR)
281 err = EISDIR;
282 else
283 err = vn_writechk(vp);
284 if (err && !(error = VOP_ACCESS(vp, VREAD, cred, p)))
285 error = err;
286 if (error || (error = VOP_ACCESS(vp, VREAD|VWRITE, cred, p)))
287 goto bad;
288 } else if (fmode & FREAD) {
289 if ((error = VOP_ACCESS(vp, VREAD, cred, p)))
290 goto bad;
291 } else if (fmode & (FWRITE | O_TRUNC)) {
292 if (vp->v_type == VDIR) {
293 error = EISDIR;
294 goto bad;
295 }
296 if ((error = vn_writechk(vp)) ||
297 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
298 goto bad;
299 }
300 if (fmode & O_TRUNC) {
301 VOP_UNLOCK(vp, 0, p); /* XXX */
302 VOP_LEASE(vp, p, cred, LEASE_WRITE);
303 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
304 VATTR_NULL(vap);
305 vap->va_size = 0;
306 error = VOP_SETATTR(vp, vap, cred, p);
307 if (error)
308 goto bad;
309 }
310
311 error = VOP_OPEN(vp, fmode, cred, p);
312 if (error)
313 goto bad;
314
315 if (fmode & FWRITE)
316 if (++vp->v_writecount <= 0)
317 panic("fhopen: v_writecount");
318 /*
319 * end of vn_open code
320 */
321
322 if ((error = falloc(p, &nfp, &indx)) != 0) {
323 if (fmode & FWRITE)
324 vp->v_writecount--;
325 goto bad;
326 }
327 fp = nfp;
328
329 /*
330 * Hold an extra reference to avoid having fp ripped out
331 * from under us while we block in the lock op
332 */
333 fref(fp);
334 nfp->f_data = (caddr_t)vp;
335 nfp->f_flag = fmode & FMASK;
336 nfp->f_ops = &vnops;
337 nfp->f_type = DTYPE_VNODE;
338 if (fmode & (O_EXLOCK | O_SHLOCK)) {
339 lf.l_whence = SEEK_SET;
340 lf.l_start = 0;
341 lf.l_len = 0;
342 if (fmode & O_EXLOCK)
343 lf.l_type = F_WRLCK;
344 else
345 lf.l_type = F_RDLCK;
346 type = F_FLOCK;
347 if ((fmode & FNONBLOCK) == 0)
348 type |= F_WAIT;
349 VOP_UNLOCK(vp, 0, p);
350 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf,
351 type)) != 0) {
352 (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
353 ffree(fp);
354 fdrelse(p, indx);
355 /*
356 * release our private reference
357 */
358 frele(fp);
359
360 return (error);
361 }
362 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
363 fp->f_flag |= FHASLOCK;
364 }
365
366 VOP_UNLOCK(vp, 0, p);
367 *fdflags(p, indx) &= ~UF_RESERVED;
368 frele(fp);
369 *retval = indx;
370 return (0);
371
372 bad:
373 VOP_UNLOCK(vp, 0, p);
374 if (didhold)
375 ubc_rele(vp);
376 vrele(vp);
377 return (error);
378 }
379
380 /*
381 * Nfs server psuedo system call for the nfsd's
382 * Based on the flag value it either:
383 * - adds a socket to the selection list
384 * - remains in the kernel as an nfsd
385 * - remains in the kernel as an nfsiod
386 */
387 #ifndef _SYS_SYSPROTO_H_
388 struct nfssvc_args {
389 int flag;
390 caddr_t argp;
391 };
392 #endif
393 int
394 nfssvc(p, uap)
395 struct proc *p;
396 register struct nfssvc_args *uap;
397 {
398 #ifndef NFS_NOSERVER
399 struct nameidata nd;
400 struct file *fp;
401 struct mbuf *nam;
402 struct nfsd_args nfsdarg;
403 struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
404 struct nfsd_cargs ncd;
405 struct nfsd *nfsd;
406 struct nfssvc_sock *slp;
407 struct nfsuid *nuidp;
408 struct nfsmount *nmp;
409 struct timeval now;
410 #endif /* NFS_NOSERVER */
411 int error;
412
413 /*
414 * Must be super user
415 */
416 error = suser(p->p_ucred, &p->p_acflag);
417 if(error)
418 return (error);
419 while (nfssvc_sockhead_flag & SLP_INIT) {
420 nfssvc_sockhead_flag |= SLP_WANTINIT;
421 (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0);
422 }
423 if (uap->flag & NFSSVC_BIOD)
424 error = nfssvc_iod(p);
425 #ifdef NFS_NOSERVER
426 else
427 error = ENXIO;
428 #else /* !NFS_NOSERVER */
429 else if (uap->flag & NFSSVC_MNTD) {
430 error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd));
431 if (error)
432 return (error);
433 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
434 ncd.ncd_dirp, p);
435 error = namei(&nd);
436 if (error)
437 return (error);
438 if ((nd.ni_vp->v_flag & VROOT) == 0)
439 error = EINVAL;
440 nmp = VFSTONFS(nd.ni_vp->v_mount);
441 vput(nd.ni_vp);
442 if (error)
443 return (error);
444
445 if ((nmp->nm_state & NFSSTA_MNTD) &&
446 (uap->flag & NFSSVC_GOTAUTH) == 0)
447 return (0);
448 nmp->nm_state |= NFSSTA_MNTD;
449 error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag,
450 uap->argp, p);
451 } else if (uap->flag & NFSSVC_ADDSOCK) {
452 error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg));
453 if (error)
454 return (error);
455 error = getsock(p->p_fd, nfsdarg.sock, &fp);
456 if (error)
457 return (error);
458 /*
459 * Get the client address for connected sockets.
460 */
461 if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
462 nam = (struct mbuf *)0;
463 else {
464 error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
465 MT_SONAME);
466 if (error)
467 return (error);
468 }
469 error = nfssvc_addsock(fp, nam, p);
470 } else {
471 error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd));
472 if (error)
473 return (error);
474
475 if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) &&
476 (nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
477 slp = nfsd->nfsd_slp;
478
479 /*
480 * First check to see if another nfsd has already
481 * added this credential.
482 */
483 for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first;
484 nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
485 if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid &&
486 (!nfsd->nfsd_nd->nd_nam2 ||
487 netaddr_match(NU_NETFAM(nuidp),
488 &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
489 break;
490 }
491 if (nuidp) {
492 nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr);
493 nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
494 } else {
495 /*
496 * Nope, so we will.
497 */
498 if (slp->ns_numuids < nuidhash_max) {
499 slp->ns_numuids++;
500 nuidp = (struct nfsuid *)
501 _MALLOC_ZONE(sizeof (struct nfsuid),
502 M_NFSUID, M_WAITOK);
503 } else
504 nuidp = (struct nfsuid *)0;
505 if ((slp->ns_flag & SLP_VALID) == 0) {
506 if (nuidp)
507 FREE_ZONE((caddr_t)nuidp,
508 sizeof (struct nfsuid), M_NFSUID);
509 } else {
510 if (nuidp == (struct nfsuid *)0) {
511 nuidp = slp->ns_uidlruhead.tqh_first;
512 LIST_REMOVE(nuidp, nu_hash);
513 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
514 nu_lru);
515 if (nuidp->nu_flag & NU_NAM)
516 m_freem(nuidp->nu_nam);
517 }
518 nuidp->nu_flag = 0;
519 nuidp->nu_cr = nsd->nsd_cr;
520 if (nuidp->nu_cr.cr_ngroups > NGROUPS)
521 nuidp->nu_cr.cr_ngroups = NGROUPS;
522 nuidp->nu_cr.cr_ref = 1;
523 nuidp->nu_timestamp = nsd->nsd_timestamp;
524 microtime(&now);
525 nuidp->nu_expire = now.tv_sec + nsd->nsd_ttl;
526 /*
527 * and save the session key in nu_key.
528 */
529 bcopy(nsd->nsd_key, nuidp->nu_key,
530 sizeof (nsd->nsd_key));
531 if (nfsd->nfsd_nd->nd_nam2) {
532 struct sockaddr_in *saddr;
533
534 saddr = mtod(nfsd->nfsd_nd->nd_nam2,
535 struct sockaddr_in *);
536 switch (saddr->sin_family) {
537 case AF_INET:
538 nuidp->nu_flag |= NU_INETADDR;
539 nuidp->nu_inetaddr =
540 saddr->sin_addr.s_addr;
541 break;
542 case AF_ISO:
543 default:
544 nuidp->nu_flag |= NU_NAM;
545 nuidp->nu_nam = m_copym(
546 nfsd->nfsd_nd->nd_nam2, 0,
547 M_COPYALL, M_WAIT);
548 break;
549 };
550 }
551 TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
552 nu_lru);
553 LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
554 nuidp, nu_hash);
555 nfsrv_setcred(&nuidp->nu_cr,
556 &nfsd->nfsd_nd->nd_cr);
557 nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
558 }
559 }
560 }
561 if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
562 nfsd->nfsd_flag |= NFSD_AUTHFAIL;
563 error = nfssvc_nfsd(nsd, uap->argp, p);
564 }
565 #endif /* NFS_NOSERVER */
566 if (error == EINTR || error == ERESTART)
567 error = 0;
568 return (error);
569 }
570
571 #ifndef NFS_NOSERVER
572 /*
573 * Adds a socket to the list for servicing by nfsds.
574 */
575 static int
576 nfssvc_addsock(fp, mynam, p)
577 struct file *fp;
578 struct mbuf *mynam;
579 struct proc *p;
580 {
581 register struct mbuf *m;
582 register int siz;
583 register struct nfssvc_sock *slp;
584 register struct socket *so;
585 struct nfssvc_sock *tslp;
586 int error, s;
587
588 so = (struct socket *)fp->f_data;
589 tslp = (struct nfssvc_sock *)0;
590 /*
591 * Add it to the list, as required.
592 */
593 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
594 if (so->so_proto->pr_protocol == IPPROTO_UDP) {
595 tslp = nfs_udpsock;
596 if (tslp->ns_flag & SLP_VALID) {
597 m_freem(mynam);
598 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
599 return (EPERM);
600 }
601 #if ISO
602 } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) {
603 tslp = nfs_cltpsock;
604 if (tslp->ns_flag & SLP_VALID) {
605 m_freem(mynam);
606 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
607 return (EPERM);
608 }
609 #endif /* ISO */
610 }
611 /* reserve buffer space for 2 maximally-sized packets */
612 siz = NFS_MAXPACKET;
613 if (so->so_type == SOCK_STREAM)
614 siz += sizeof (u_long);
615 siz *= 2;
616 if (siz > NFS_MAXSOCKBUF)
617 siz = NFS_MAXSOCKBUF;
618 error = soreserve(so, siz, siz);
619 if (error) {
620 m_freem(mynam);
621 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
622 return (error);
623 }
624
625 /*
626 * Set protocol specific options { for now TCP only } and
627 * reserve some space. For datagram sockets, this can get called
628 * repeatedly for the same socket, but that isn't harmful.
629 */
630 if (so->so_type == SOCK_STREAM) {
631 struct sockopt sopt;
632 int val;
633
634 bzero(&sopt, sizeof sopt);
635 sopt.sopt_dir = SOPT_SET;
636 sopt.sopt_level = SOL_SOCKET;
637 sopt.sopt_name = SO_KEEPALIVE;
638 sopt.sopt_val = &val;
639 sopt.sopt_valsize = sizeof val;
640 val = 1;
641 sosetopt(so, &sopt);
642 }
643 if (so->so_proto->pr_domain->dom_family == AF_INET &&
644 so->so_proto->pr_protocol == IPPROTO_TCP) {
645 struct sockopt sopt;
646 int val;
647
648 bzero(&sopt, sizeof sopt);
649 sopt.sopt_dir = SOPT_SET;
650 sopt.sopt_level = IPPROTO_TCP;
651 sopt.sopt_name = TCP_NODELAY;
652 sopt.sopt_val = &val;
653 sopt.sopt_valsize = sizeof val;
654 val = 1;
655 sosetopt(so, &sopt);
656 }
657
658 so->so_rcv.sb_flags &= ~SB_NOINTR;
659 so->so_rcv.sb_timeo = 0;
660 so->so_snd.sb_flags &= ~SB_NOINTR;
661 so->so_snd.sb_timeo = 0;
662 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
663 if (tslp)
664 slp = tslp;
665 else {
666 MALLOC(slp, struct nfssvc_sock *, sizeof(struct nfssvc_sock),
667 M_NFSSVC, M_WAITOK);
668 bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
669 TAILQ_INIT(&slp->ns_uidlruhead);
670 TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
671 }
672 slp->ns_so = so;
673 slp->ns_nam = mynam;
674 slp->ns_fp = fp;
675 (void)fref(fp);
676 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
677 s = splnet();
678 so->so_upcallarg = (caddr_t)slp;
679 so->so_upcall = nfsrv_rcv;
680 so->so_rcv.sb_flags |= SB_UPCALL; /* required for freebsd merge */
681 slp->ns_nflag = SLPN_NEEDQ;
682 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
683 slp->ns_flag = SLP_VALID;
684 nfsrv_wakenfsd(slp);
685 splx(s);
686 return (0);
687 }
688
689 /*
690 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
691 * until it is killed by a signal.
692 */
693 static int
694 nfssvc_nfsd(nsd, argp, p)
695 struct nfsd_srvargs *nsd;
696 caddr_t argp;
697 struct proc *p;
698 {
699 register struct mbuf *m;
700 register int siz;
701 register struct nfssvc_sock *slp;
702 register struct socket *so;
703 struct nfsd *nfsd = nsd->nsd_nfsd;
704 struct nfsrv_descript *nd = NULL;
705 struct mbuf *mreq;
706 int error = 0, cacherep, s, sotype, writes_todo;
707 int procrastinate;
708 u_quad_t cur_usec;
709 struct timeval now;
710
711 #ifndef nolint
712 cacherep = RC_DOIT;
713 writes_todo = 0;
714 #endif
715 s = splnet();
716 if (nfsd == (struct nfsd *)0) {
717 MALLOC(nfsd, struct nfsd *, sizeof(struct nfsd), M_NFSD, M_WAITOK);
718 nsd->nsd_nfsd = nfsd;
719 bzero((caddr_t)nfsd, sizeof (struct nfsd));
720 nfsd->nfsd_procp = p;
721 TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
722 nfs_numnfsd++;
723 }
724 /*
725 * Loop getting rpc requests until SIGKILL.
726 */
727 for (;;) {
728 if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
729 while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
730 (nfsd_head_flag & NFSD_CHECKSLP) == 0) {
731 nfsd->nfsd_flag |= NFSD_WAITING;
732 nfsd_waiting++;
733 error = tsleep((caddr_t)nfsd, PSOCK | PCATCH,
734 "nfsd", 0);
735 nfsd_waiting--;
736 if (error)
737 goto done;
738 }
739 if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
740 (nfsd_head_flag & NFSD_CHECKSLP) != 0) {
741 for (slp = nfssvc_sockhead.tqh_first; slp != 0;
742 slp = slp->ns_chain.tqe_next) {
743 if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
744 == (SLP_VALID | SLP_DOREC)) {
745 slp->ns_flag &= ~SLP_DOREC;
746 slp->ns_sref++;
747 nfsd->nfsd_slp = slp;
748 break;
749 }
750 }
751 if (slp == 0)
752 nfsd_head_flag &= ~NFSD_CHECKSLP;
753 }
754 if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0)
755 continue;
756 if (slp->ns_flag & SLP_VALID) {
757 nfs_slplock(slp, 1);
758 if (slp->ns_nflag & SLPN_DISCONN) {
759 nfsrv_zapsock(slp);
760 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
761 } else if (slp->ns_nflag & SLPN_NEEDQ) {
762 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
763 slp->ns_nflag &= ~SLPN_NEEDQ;
764 nfsrv_rcv(slp->ns_so, (caddr_t)slp,
765 M_WAIT);
766 } else
767 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
768 error = nfsrv_dorec(slp, nfsd, &nd);
769 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
770 nfs_slpunlock(slp);
771 microuptime(&now);
772 cur_usec = (u_quad_t)now.tv_sec * 1000000 +
773 (u_quad_t)now.tv_usec;
774 if (error && slp->ns_tq.lh_first &&
775 slp->ns_tq.lh_first->nd_time <= cur_usec) {
776 error = 0;
777 cacherep = RC_DOIT;
778 writes_todo = 1;
779 } else
780 writes_todo = 0;
781 nfsd->nfsd_flag |= NFSD_REQINPROG;
782 }
783 } else {
784 error = 0;
785 slp = nfsd->nfsd_slp;
786 }
787 if (error || (slp->ns_flag & SLP_VALID) == 0) {
788 if (nd) {
789 if (nd->nd_nam2)
790 m_freem(nd->nd_nam2);
791 FREE_ZONE((caddr_t)nd,
792 sizeof *nd, M_NFSRVDESC);
793 nd = NULL;
794 }
795 nfsd->nfsd_slp = (struct nfssvc_sock *)0;
796 nfsd->nfsd_flag &= ~NFSD_REQINPROG;
797 nfsrv_slpderef(slp);
798 continue;
799 }
800 splx(s);
801 so = slp->ns_so;
802 sotype = so->so_type;
803 if (nd) {
804 microuptime(&nd->nd_starttime);
805 if (nd->nd_nam2)
806 nd->nd_nam = nd->nd_nam2;
807 else
808 nd->nd_nam = slp->ns_nam;
809
810 /*
811 * Check to see if authorization is needed.
812 */
813 if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
814 nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
815 nsd->nsd_haddr = mtod(nd->nd_nam,
816 struct sockaddr_in *)->sin_addr.s_addr;
817 nsd->nsd_authlen = nfsd->nfsd_authlen;
818 nsd->nsd_verflen = nfsd->nfsd_verflen;
819 if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr,
820 nfsd->nfsd_authlen) &&
821 !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr,
822 nfsd->nfsd_verflen) &&
823 !copyout((caddr_t)nsd, argp, sizeof (*nsd)))
824 return (ENEEDAUTH);
825 cacherep = RC_DROPIT;
826 } else
827 cacherep = nfsrv_getcache(nd, slp, &mreq);
828
829 /*
830 * Check for just starting up for NQNFS and send
831 * fake "try again later" replies to the NQNFS clients.
832 */
833 microtime(&now);
834 if (notstarted && nqnfsstarttime <= now.tv_sec) {
835 if (modify_flag) {
836 nqnfsstarttime = now.tv_sec + nqsrv_writeslack;
837 modify_flag = 0;
838 } else
839 notstarted = 0;
840 }
841 if (notstarted) {
842 if ((nd->nd_flag & ND_NQNFS) == 0)
843 cacherep = RC_DROPIT;
844 else if (nd->nd_procnum != NFSPROC_WRITE) {
845 nd->nd_procnum = NFSPROC_NOOP;
846 nd->nd_repstat = NQNFS_TRYLATER;
847 cacherep = RC_DOIT;
848 } else
849 modify_flag = 1;
850 } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
851 nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
852 nd->nd_procnum = NFSPROC_NOOP;
853 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
854 cacherep = RC_DOIT;
855 } else if (nfs_privport) {
856 /* Check if source port is privileged */
857 u_short port;
858 struct sockaddr *nam = mtod(nd->nd_nam, struct sockaddr*);
859 struct sockaddr_in *sin;
860
861 sin = (struct sockaddr_in *)nam;
862 port = ntohs(sin->sin_port);
863 if (port >= IPPORT_RESERVED &&
864 nd->nd_procnum != NFSPROC_NULL) {
865 nd->nd_procnum = NFSPROC_NOOP;
866 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
867 cacherep = RC_DOIT;
868 printf("NFS request from unprivileged port (%s:%d)\n",
869 (char *)(inet_ntoa(sin->sin_addr)), port);
870 }
871 }
872
873 }
874
875 /*
876 * Loop to get all the write rpc relies that have been
877 * gathered together.
878 */
879 do {
880 switch (cacherep) {
881 case RC_DOIT:
882 if (nd && (nd->nd_flag & ND_NFSV3))
883 procrastinate = nfsrvw_procrastinate_v3;
884 else
885 procrastinate = nfsrvw_procrastinate;
886 if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE &&
887 procrastinate > 0 && !notstarted))
888 error = nfsrv_writegather(&nd, slp,
889 nfsd->nfsd_procp, &mreq);
890 else
891 error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
892 slp, nfsd->nfsd_procp, &mreq);
893 if (mreq == NULL)
894 break;
895 if (error) {
896 if (nd->nd_procnum != NQNFSPROC_VACATED)
897 nfsstats.srv_errs++;
898 nfsrv_updatecache(nd, FALSE, mreq);
899 if (nd->nd_nam2) {
900 m_freem(nd->nd_nam2);
901 nd->nd_nam2 = NULL;
902 }
903 break;
904 }
905 nfsstats.srvrpccnt[nd->nd_procnum]++;
906 nfsrv_updatecache(nd, TRUE, mreq);
907 nd->nd_mrep = (struct mbuf *)0;
908 case RC_REPLY:
909 m = mreq;
910 siz = 0;
911 while (m) {
912 siz += m->m_len;
913 m = m->m_next;
914 }
915 if (siz <= 0 || siz > NFS_MAXPACKET) {
916 printf("mbuf siz=%d\n",siz);
917 panic("Bad nfs svc reply");
918 }
919 m = mreq;
920 m->m_pkthdr.len = siz;
921 m->m_pkthdr.rcvif = (struct ifnet *)0;
922 /*
923 * For stream protocols, prepend a Sun RPC
924 * Record Mark.
925 */
926 if (sotype == SOCK_STREAM) {
927 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
928 *mtod(m, u_long *) = htonl(0x80000000 | siz);
929 }
930 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
931 (void) nfs_slplock(slp, 1);
932 if (slp->ns_flag & SLP_VALID)
933 error = nfs_send(so, nd->nd_nam2, m, NULL);
934 else {
935 error = EPIPE;
936 m_freem(m);
937 }
938 mreq = NULL;
939 if (nfsrtton)
940 nfsd_rt(sotype, nd, cacherep);
941 if (nd->nd_nam2) {
942 MFREE(nd->nd_nam2, m);
943 nd->nd_nam2 = NULL;
944 }
945 if (nd->nd_mrep) {
946 m_freem(nd->nd_mrep);
947 nd->nd_mrep = NULL;
948 }
949 if (error == EPIPE)
950 nfsrv_zapsock(slp);
951 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
952 nfs_slpunlock(slp);
953 if (error == EINTR || error == ERESTART) {
954 FREE_ZONE((caddr_t)nd,
955 sizeof *nd, M_NFSRVDESC);
956 nfsrv_slpderef(slp);
957 s = splnet();
958 goto done;
959 }
960 break;
961 case RC_DROPIT:
962 if (nfsrtton)
963 nfsd_rt(sotype, nd, cacherep);
964 m_freem(nd->nd_mrep);
965 m_freem(nd->nd_nam2);
966 nd->nd_mrep = nd->nd_nam2 = NULL;
967 break;
968 };
969 if (nd) {
970 if (nd->nd_mrep)
971 m_freem(nd->nd_mrep);
972 if (nd->nd_nam2)
973 m_freem(nd->nd_nam2);
974 FREE_ZONE((caddr_t)nd, sizeof *nd, M_NFSRVDESC);
975 nd = NULL;
976 }
977
978 /*
979 * Check to see if there are outstanding writes that
980 * need to be serviced.
981 */
982 microuptime(&now);
983 cur_usec = (u_quad_t)now.tv_sec * 1000000 +
984 (u_quad_t)now.tv_usec;
985 s = splsoftclock();
986 if (slp->ns_tq.lh_first &&
987 slp->ns_tq.lh_first->nd_time <= cur_usec) {
988 cacherep = RC_DOIT;
989 writes_todo = 1;
990 } else
991 writes_todo = 0;
992 splx(s);
993 } while (writes_todo);
994 s = splnet();
995 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
996 if (nfsrv_dorec(slp, nfsd, &nd)) {
997 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
998 nfsd->nfsd_flag &= ~NFSD_REQINPROG;
999 nfsd->nfsd_slp = NULL;
1000 nfsrv_slpderef(slp);
1001 } else
1002 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
1003 }
1004 done:
1005 TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
1006 splx(s);
1007 _FREE((caddr_t)nfsd, M_NFSD);
1008 nsd->nsd_nfsd = (struct nfsd *)0;
1009 if (--nfs_numnfsd == 0)
1010 nfsrv_init(TRUE); /* Reinitialize everything */
1011 return (error);
1012 }
1013 #endif /* NFS_NOSERVER */
1014
1015 int nfs_defect = 0;
1016 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
1017 #ifdef notyet
1018 SYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, "");
1019 #endif
1020
1021 #ifndef _SYS_SYSPROTO_H_
1022 struct nfsclnt_args {
1023 int flag;
1024 caddr_t argp;
1025 };
1026 #endif
1027 int
1028 nfsclnt(struct proc *p, struct nfsclnt_args *uap)
1029 {
1030 struct lockd_ans la;
1031 int error;
1032
1033 if (uap->flag == NFSCLNT_LOCKDWAIT) {
1034 return (nfslockdwait(p));
1035 }
1036 if (uap->flag == NFSCLNT_LOCKDANS) {
1037 error = copyin(uap->argp, &la, sizeof(la));
1038 return (error != 0 ? error : nfslockdans(p, &la));
1039 }
1040 if (uap->flag == NFSCLNT_LOCKDFD)
1041 return (nfslockdfd(p, (int)uap->argp));
1042 return EINVAL;
1043 }
1044
1045
1046 static int nfssvc_iod_continue(int);
1047
1048 /*
1049 * Asynchronous I/O daemons for client nfs.
1050 * They do read-ahead and write-behind operations on the block I/O cache.
1051 * Never returns unless it fails or gets killed.
1052 */
1053 static int
1054 nfssvc_iod(p)
1055 struct proc *p;
1056 {
1057 register int i, myiod;
1058 struct nfsmount *nmp;
1059 int error = 0;
1060 struct uthread *ut;
1061
1062 /*
1063 * Assign my position or return error if too many already running
1064 */
1065 myiod = -1;
1066 for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1067 if (nfs_asyncdaemon[i] == 0) {
1068 nfs_asyncdaemon[i]++;
1069 myiod = i;
1070 break;
1071 }
1072 if (myiod == -1)
1073 return (EBUSY);
1074 nfs_numasync++;
1075
1076 /* stuff myiod into uthread to get off local stack for continuation */
1077
1078 ut = (struct uthread *)get_bsdthread_info(current_act());
1079 ut->uu_state.uu_nfs_myiod = myiod; /* squirrel away for continuation */
1080
1081 nfssvc_iod_continue(0);
1082 /* NOTREACHED */
1083
1084 }
1085
1086 /*
1087 * Continuation for Asynchronous I/O daemons for client nfs.
1088 */
1089 static int
1090 nfssvc_iod_continue(error)
1091 {
1092 register struct nfsbuf *bp;
1093 register int i, myiod;
1094 struct nfsmount *nmp;
1095 struct uthread *ut;
1096 struct proc *p;
1097
1098 /*
1099 * real myiod is stored in uthread, recover it
1100 */
1101 ut = (struct uthread *)get_bsdthread_info(current_act());
1102 myiod = ut->uu_state.uu_nfs_myiod;
1103 p = current_proc();
1104
1105 /*
1106 * Just loop around doin our stuff until SIGKILL
1107 * - actually we don't loop with continuations...
1108 */
1109 for (;;) {
1110 while (((nmp = nfs_iodmount[myiod]) == NULL
1111 || nmp->nm_bufq.tqh_first == NULL)
1112 && error == 0 && nfs_ioddelwri == 0) {
1113 if (nmp)
1114 nmp->nm_bufqiods--;
1115 nfs_iodwant[myiod] = p;
1116 nfs_iodmount[myiod] = NULL;
1117 error = tsleep0((caddr_t)&nfs_iodwant[myiod],
1118 PWAIT | PCATCH, "nfsidl", 0, nfssvc_iod_continue);
1119 /* NOTREACHED */
1120 }
1121 if (error) {
1122 nfs_asyncdaemon[myiod] = 0;
1123 if (nmp) nmp->nm_bufqiods--;
1124 nfs_iodwant[myiod] = NULL;
1125 nfs_iodmount[myiod] = NULL;
1126 nfs_numasync--;
1127 if (error == EINTR || error == ERESTART)
1128 error = 0;
1129 unix_syscall_return(error);
1130 }
1131 if (nmp != NULL) {
1132 while ((bp = nmp->nm_bufq.tqh_first) != NULL) {
1133 /* Take one off the front of the list */
1134 TAILQ_REMOVE(&nmp->nm_bufq, bp, nb_free);
1135 bp->nb_free.tqe_next = NFSNOLIST;
1136 nmp->nm_bufqlen--;
1137 if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) {
1138 nmp->nm_bufqwant = FALSE;
1139 wakeup(&nmp->nm_bufq);
1140 }
1141 if (ISSET(bp->nb_flags, NB_READ))
1142 (void) nfs_doio(bp, bp->nb_rcred, (struct proc *)0);
1143 else
1144 (void) nfs_doio(bp, bp->nb_wcred, (struct proc *)0);
1145
1146 /*
1147 * If there are more than one iod on this mount, then defect
1148 * so that the iods can be shared out fairly between the mounts
1149 */
1150 if (nfs_defect && nmp->nm_bufqiods > 1) {
1151 NFS_DPF(ASYNCIO,
1152 ("nfssvc_iod: iod %d defecting from mount %p\n",
1153 myiod, nmp));
1154 nfs_iodmount[myiod] = NULL;
1155 nmp->nm_bufqiods--;
1156 break;
1157 }
1158 }
1159 }
1160 if (nfs_ioddelwri) {
1161 i = 0;
1162 nfs_ioddelwri = 0;
1163 while (i < 8 && (bp = TAILQ_FIRST(&nfsbufdelwri)) != NULL) {
1164 struct nfsnode *np = VTONFS(bp->nb_vp);
1165 nfs_buf_remfree(bp);
1166 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
1167 /* put buffer at end of delwri list */
1168 TAILQ_INSERT_TAIL(&nfsbufdelwri, bp, nb_free);
1169 nfsbufdelwricnt++;
1170 nfs_flushcommits(np->n_vnode, (struct proc *)0);
1171 } else {
1172 SET(bp->nb_flags, (NB_BUSY | NB_ASYNC | NB_IOD));
1173 nfs_buf_write(bp);
1174 }
1175 i++;
1176 }
1177 }
1178 }
1179 }
1180
1181 /*
1182 * Shut down a socket associated with an nfssvc_sock structure.
1183 * Should be called with the send lock set, if required.
1184 * The trick here is to increment the sref at the start, so that the nfsds
1185 * will stop using it and clear ns_flag at the end so that it will not be
1186 * reassigned during cleanup.
1187 */
1188 static void
1189 nfsrv_zapsock(slp)
1190 register struct nfssvc_sock *slp;
1191 {
1192 register struct nfsuid *nuidp, *nnuidp;
1193 register struct nfsrv_descript *nwp, *nnwp;
1194 struct socket *so;
1195 struct file *fp;
1196 struct mbuf *m;
1197 int s;
1198
1199 slp->ns_flag &= ~SLP_ALLFLAGS;
1200 slp->ns_nflag &= ~SLP_ALLFLAGS;
1201 fp = slp->ns_fp;
1202 if (fp) {
1203 slp->ns_fp = (struct file *)0;
1204 so = slp->ns_so;
1205 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
1206 so->so_upcall = NULL;
1207 so->so_rcv.sb_flags &= ~SB_UPCALL;
1208 soshutdown(so, 2);
1209 if (slp->ns_nam)
1210 MFREE(slp->ns_nam, m);
1211 m_freem(slp->ns_raw);
1212 m_freem(slp->ns_rec);
1213 slp->ns_nam = slp->ns_raw = slp->ns_rec = NULL;
1214 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
1215 closef(fp, (struct proc *)0);
1216 for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0;
1217 nuidp = nnuidp) {
1218 nnuidp = nuidp->nu_lru.tqe_next;
1219 LIST_REMOVE(nuidp, nu_hash);
1220 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
1221 if (nuidp->nu_flag & NU_NAM)
1222 m_freem(nuidp->nu_nam);
1223 FREE_ZONE((caddr_t)nuidp,
1224 sizeof (struct nfsuid), M_NFSUID);
1225 }
1226 s = splsoftclock();
1227 for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) {
1228 nnwp = nwp->nd_tq.le_next;
1229 LIST_REMOVE(nwp, nd_tq);
1230 FREE_ZONE((caddr_t)nwp, sizeof *nwp, M_NFSRVDESC);
1231 }
1232 LIST_INIT(&slp->ns_tq);
1233 splx(s);
1234 }
1235 }
1236
1237 /*
1238 * Get an authorization string for the uid by having the mount_nfs sitting
1239 * on this mount point porpous out of the kernel and do it.
1240 */
1241 int
1242 nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
1243 register struct nfsmount *nmp;
1244 struct nfsreq *rep;
1245 struct ucred *cred;
1246 char **auth_str;
1247 int *auth_len;
1248 char *verf_str;
1249 int *verf_len;
1250 NFSKERBKEY_T key; /* return session key */
1251 {
1252 int error = 0;
1253
1254 while ((nmp->nm_state & NFSSTA_WAITAUTH) == 0) {
1255 nmp->nm_state |= NFSSTA_WANTAUTH;
1256 (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
1257 "nfsauth1", 2 * hz);
1258 error = nfs_sigintr(nmp, rep, rep->r_procp);
1259 if (error) {
1260 nmp->nm_state &= ~NFSSTA_WANTAUTH;
1261 return (error);
1262 }
1263 }
1264 nmp->nm_state &= ~(NFSSTA_WAITAUTH | NFSSTA_WANTAUTH);
1265 MALLOC(*auth_str, char *, RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
1266 nmp->nm_authstr = *auth_str;
1267 nmp->nm_authlen = RPCAUTH_MAXSIZ;
1268 nmp->nm_verfstr = verf_str;
1269 nmp->nm_verflen = *verf_len;
1270 nmp->nm_authuid = cred->cr_uid;
1271 wakeup((caddr_t)&nmp->nm_authstr);
1272
1273 /*
1274 * And wait for mount_nfs to do its stuff.
1275 */
1276 while ((nmp->nm_state & NFSSTA_HASAUTH) == 0 && error == 0) {
1277 (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
1278 "nfsauth2", 2 * hz);
1279 error = nfs_sigintr(nmp, rep, rep->r_procp);
1280 }
1281 if (nmp->nm_state & NFSSTA_AUTHERR) {
1282 nmp->nm_state &= ~NFSSTA_AUTHERR;
1283 error = EAUTH;
1284 }
1285 if (error)
1286 _FREE((caddr_t)*auth_str, M_TEMP);
1287 else {
1288 *auth_len = nmp->nm_authlen;
1289 *verf_len = nmp->nm_verflen;
1290 bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key));
1291 }
1292 nmp->nm_state &= ~NFSSTA_HASAUTH;
1293 nmp->nm_state |= NFSSTA_WAITAUTH;
1294 if (nmp->nm_state & NFSSTA_WANTAUTH) {
1295 nmp->nm_state &= ~NFSSTA_WANTAUTH;
1296 wakeup((caddr_t)&nmp->nm_authtype);
1297 }
1298 return (error);
1299 }
1300
1301 /*
1302 * Get a nickname authenticator and verifier.
1303 */
1304 int
1305 nfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len)
1306 struct nfsmount *nmp;
1307 struct ucred *cred;
1308 char **auth_str;
1309 int *auth_len;
1310 char *verf_str;
1311 int verf_len;
1312 {
1313 register struct nfsuid *nuidp;
1314 register u_long *nickp, *verfp;
1315 struct timeval ktvin, ktvout, now;
1316
1317 #if DIAGNOSTIC
1318 if (verf_len < (4 * NFSX_UNSIGNED))
1319 panic("nfs_getnickauth verf too small");
1320 #endif
1321 for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first;
1322 nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
1323 if (nuidp->nu_cr.cr_uid == cred->cr_uid)
1324 break;
1325 }
1326 microtime(&now);
1327 if (!nuidp || nuidp->nu_expire < now.tv_sec)
1328 return (EACCES);
1329
1330 /*
1331 * Move to the end of the lru list (end of lru == most recently used).
1332 */
1333 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
1334 TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
1335
1336 MALLOC(nickp, u_long *, 2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
1337 *nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
1338 *nickp = txdr_unsigned(nuidp->nu_nickname);
1339 *auth_str = (char *)nickp;
1340 *auth_len = 2 * NFSX_UNSIGNED;
1341
1342 /*
1343 * Now we must encrypt the verifier and package it up.
1344 */
1345 verfp = (u_long *)verf_str;
1346 *verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
1347 microtime(&now);
1348 if (now.tv_sec > nuidp->nu_timestamp.tv_sec ||
1349 (now.tv_sec == nuidp->nu_timestamp.tv_sec &&
1350 now.tv_usec > nuidp->nu_timestamp.tv_usec))
1351 nuidp->nu_timestamp = now;
1352 else
1353 nuidp->nu_timestamp.tv_usec++;
1354 ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
1355 ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
1356
1357 /*
1358 * Now encrypt the timestamp verifier in ecb mode using the session
1359 * key.
1360 */
1361 #if NFSKERB
1362 XXX
1363 #endif
1364
1365 *verfp++ = ktvout.tv_sec;
1366 *verfp++ = ktvout.tv_usec;
1367 *verfp = 0;
1368 return (0);
1369 }
1370
1371 /*
1372 * Save the current nickname in a hash list entry on the mount point.
1373 */
1374 int
1375 nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
1376 register struct nfsmount *nmp;
1377 struct ucred *cred;
1378 int len;
1379 NFSKERBKEY_T key;
1380 struct mbuf **mdp;
1381 char **dposp;
1382 struct mbuf *mrep;
1383 {
1384 register struct nfsuid *nuidp;
1385 register u_long *tl;
1386 register long t1;
1387 struct mbuf *md = *mdp;
1388 struct timeval ktvin, ktvout, now;
1389 u_long nick;
1390 char *dpos = *dposp, *cp2;
1391 int deltasec, error = 0;
1392
1393 if (len == (3 * NFSX_UNSIGNED)) {
1394 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
1395 ktvin.tv_sec = *tl++;
1396 ktvin.tv_usec = *tl++;
1397 nick = fxdr_unsigned(u_long, *tl);
1398
1399 /*
1400 * Decrypt the timestamp in ecb mode.
1401 */
1402 #if NFSKERB
1403 XXX
1404 #endif
1405 ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
1406 ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
1407 microtime(&now);
1408 deltasec = now.tv_sec - ktvout.tv_sec;
1409 if (deltasec < 0)
1410 deltasec = -deltasec;
1411 /*
1412 * If ok, add it to the hash list for the mount point.
1413 */
1414 if (deltasec <= NFS_KERBCLOCKSKEW) {
1415 if (nmp->nm_numuids < nuidhash_max) {
1416 nmp->nm_numuids++;
1417 MALLOC_ZONE(nuidp, struct nfsuid *,
1418 sizeof (struct nfsuid),
1419 M_NFSUID, M_WAITOK);
1420 } else {
1421 nuidp = nmp->nm_uidlruhead.tqh_first;
1422 LIST_REMOVE(nuidp, nu_hash);
1423 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
1424 nu_lru);
1425 }
1426 nuidp->nu_flag = 0;
1427 nuidp->nu_cr.cr_uid = cred->cr_uid;
1428 nuidp->nu_expire = now.tv_sec + NFS_KERBTTL;
1429 nuidp->nu_timestamp = ktvout;
1430 nuidp->nu_nickname = nick;
1431 bcopy(key, nuidp->nu_key, sizeof (key));
1432 TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
1433 nu_lru);
1434 LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid),
1435 nuidp, nu_hash);
1436 }
1437 } else
1438 nfsm_adv(nfsm_rndup(len));
1439 nfsmout:
1440 *mdp = md;
1441 *dposp = dpos;
1442 return (error);
1443 }
1444
1445 #ifndef NFS_NOSERVER
1446
1447 /*
1448 * Derefence a server socket structure. If it has no more references and
1449 * is no longer valid, you can throw it away.
1450 */
1451 void
1452 nfsrv_slpderef(slp)
1453 register struct nfssvc_sock *slp;
1454 {
1455 if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
1456 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
1457 _FREE((caddr_t)slp, M_NFSSVC);
1458 }
1459 }
1460
1461 /*
1462 * Lock a socket against others.
1463 */
1464 int
1465 nfs_slplock(slp, wait)
1466 register struct nfssvc_sock *slp;
1467 int wait;
1468 {
1469 int *statep = &slp->ns_solock;
1470
1471 if (!wait && (*statep & NFSSTA_SNDLOCK))
1472 return(0); /* already locked, fail */
1473 while (*statep & NFSSTA_SNDLOCK) {
1474 *statep |= NFSSTA_WANTSND;
1475 (void) tsleep((caddr_t)statep, PZERO - 1, "nfsslplck", 0);
1476 }
1477 *statep |= NFSSTA_SNDLOCK;
1478 return (1);
1479 }
1480
1481 /*
1482 * Unlock the stream socket for others.
1483 */
1484 void
1485 nfs_slpunlock(slp)
1486 struct nfssvc_sock *slp;
1487 {
1488 int *statep = &slp->ns_solock;
1489
1490 if ((*statep & NFSSTA_SNDLOCK) == 0)
1491 panic("nfs slpunlock");
1492 *statep &= ~NFSSTA_SNDLOCK;
1493 if (*statep & NFSSTA_WANTSND) {
1494 *statep &= ~NFSSTA_WANTSND;
1495 wakeup((caddr_t)statep);
1496 }
1497 }
1498
1499 /*
1500 * Initialize the data structures for the server.
1501 * Handshake with any new nfsds starting up to avoid any chance of
1502 * corruption.
1503 */
1504 void
1505 nfsrv_init(terminating)
1506 int terminating;
1507 {
1508 register struct nfssvc_sock *slp, *nslp;
1509
1510 if (nfssvc_sockhead_flag & SLP_INIT)
1511 panic("nfsd init");
1512 nfssvc_sockhead_flag |= SLP_INIT;
1513 if (terminating) {
1514 for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) {
1515 nslp = slp->ns_chain.tqe_next;
1516 if (slp->ns_flag & SLP_VALID)
1517 nfsrv_zapsock(slp);
1518 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
1519 _FREE((caddr_t)slp, M_NFSSVC);
1520 }
1521 nfsrv_cleancache(); /* And clear out server cache */
1522 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1523 #ifdef notyet
1524 } else
1525 nfs_pub.np_valid = 0;
1526 #else
1527 }
1528 #endif
1529
1530 TAILQ_INIT(&nfssvc_sockhead);
1531 nfssvc_sockhead_flag &= ~SLP_INIT;
1532 if (nfssvc_sockhead_flag & SLP_WANTINIT) {
1533 nfssvc_sockhead_flag &= ~SLP_WANTINIT;
1534 wakeup((caddr_t)&nfssvc_sockhead);
1535 }
1536
1537 TAILQ_INIT(&nfsd_head);
1538 nfsd_head_flag &= ~NFSD_CHECKSLP;
1539
1540 MALLOC(nfs_udpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock),
1541 M_NFSSVC, M_WAITOK);
1542 bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
1543 TAILQ_INIT(&nfs_udpsock->ns_uidlruhead);
1544 TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
1545
1546 MALLOC(nfs_cltpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock),
1547 M_NFSSVC, M_WAITOK);
1548 bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
1549 TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead);
1550 TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain);
1551 }
1552
1553 /*
1554 * Add entries to the server monitor log.
1555 */
1556 static void
1557 nfsd_rt(sotype, nd, cacherep)
1558 int sotype;
1559 register struct nfsrv_descript *nd;
1560 int cacherep;
1561 {
1562 register struct drt *rt;
1563 struct timeval now;
1564
1565 rt = &nfsdrt.drt[nfsdrt.pos];
1566 if (cacherep == RC_DOIT)
1567 rt->flag = 0;
1568 else if (cacherep == RC_REPLY)
1569 rt->flag = DRT_CACHEREPLY;
1570 else
1571 rt->flag = DRT_CACHEDROP;
1572 if (sotype == SOCK_STREAM)
1573 rt->flag |= DRT_TCP;
1574 if (nd->nd_flag & ND_NQNFS)
1575 rt->flag |= DRT_NQNFS;
1576 else if (nd->nd_flag & ND_NFSV3)
1577 rt->flag |= DRT_NFSV3;
1578 rt->proc = nd->nd_procnum;
1579 if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET)
1580 rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr;
1581 else
1582 rt->ipadr = INADDR_ANY;
1583 microuptime(&now);
1584 rt->resptime = ((now.tv_sec - nd->nd_starttime.tv_sec) * 1000000) +
1585 (now.tv_usec - nd->nd_starttime.tv_usec);
1586 microtime(&rt->tstamp); // XXX unused
1587 nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
1588 }
1589 #endif /* NFS_NOSERVER */