]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
43866e37 | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
1c79356b | 7 | * |
43866e37 A |
8 | * This file contains Original Code and/or Modifications of Original Code |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
43866e37 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
1c79356b A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ | |
26 | /* | |
27 | * Copyright (c) 1989, 1993 | |
28 | * The Regents of the University of California. All rights reserved. | |
29 | * | |
30 | * This code is derived from software contributed to Berkeley by | |
31 | * Rick Macklem at The University of Guelph. | |
32 | * | |
33 | * Redistribution and use in source and binary forms, with or without | |
34 | * modification, are permitted provided that the following conditions | |
35 | * are met: | |
36 | * 1. Redistributions of source code must retain the above copyright | |
37 | * notice, this list of conditions and the following disclaimer. | |
38 | * 2. Redistributions in binary form must reproduce the above copyright | |
39 | * notice, this list of conditions and the following disclaimer in the | |
40 | * documentation and/or other materials provided with the distribution. | |
41 | * 3. All advertising materials mentioning features or use of this software | |
42 | * must display the following acknowledgement: | |
43 | * This product includes software developed by the University of | |
44 | * California, Berkeley and its contributors. | |
45 | * 4. Neither the name of the University nor the names of its contributors | |
46 | * may be used to endorse or promote products derived from this software | |
47 | * without specific prior written permission. | |
48 | * | |
49 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
50 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
51 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
53 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
54 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
55 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
56 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
57 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
58 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
59 | * SUCH DAMAGE. | |
60 | * | |
61 | * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 | |
62 | * FreeBSD-Id: nfs_syscalls.c,v 1.32 1997/11/07 08:53:25 phk Exp $ | |
63 | */ | |
64 | ||
65 | #include <sys/param.h> | |
66 | #include <sys/systm.h> | |
67 | /* XXX CSM 11/25/97 FreeBSD's generated syscall prototypes */ | |
68 | #ifdef notyet | |
69 | #include <sys/sysproto.h> | |
70 | #endif | |
71 | #include <sys/kernel.h> | |
72 | #include <sys/file.h> | |
73 | #include <sys/filedesc.h> | |
74 | #include <sys/stat.h> | |
75 | #include <sys/vnode.h> | |
76 | #include <sys/mount.h> | |
77 | #include <sys/proc.h> | |
78 | #include <sys/sysctl.h> | |
79 | #include <sys/uio.h> | |
80 | #include <sys/malloc.h> | |
81 | #include <sys/buf.h> | |
82 | #include <sys/mbuf.h> | |
83 | #include <sys/socket.h> | |
84 | #include <sys/socketvar.h> | |
85 | #include <sys/domain.h> | |
86 | #include <sys/protosw.h> | |
87 | #include <sys/namei.h> | |
88 | #include <sys/syslog.h> | |
89 | #include <sys/user.h> | |
90 | #include <machine/spl.h> | |
91 | ||
92 | #include <netinet/in.h> | |
93 | #include <netinet/tcp.h> | |
94 | #if ISO | |
95 | #include <netiso/iso.h> | |
96 | #endif | |
97 | #include <nfs/xdr_subs.h> | |
98 | #include <nfs/rpcv2.h> | |
99 | #include <nfs/nfsproto.h> | |
100 | #include <nfs/nfs.h> | |
101 | #include <nfs/nfsm_subs.h> | |
102 | #include <nfs/nfsrvcache.h> | |
103 | #include <nfs/nfsmount.h> | |
104 | #include <nfs/nfsnode.h> | |
105 | #include <nfs/nqnfs.h> | |
106 | #include <nfs/nfsrtt.h> | |
107 | ||
108 | ||
109 | /* Global defs. */ | |
110 | extern int (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *nd, | |
111 | struct nfssvc_sock *slp, | |
112 | struct proc *procp, | |
113 | struct mbuf **mreqp)); | |
114 | extern int nfs_numasync; | |
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, 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 | * Nfs server psuedo system call for the nfsd's | |
200 | * Based on the flag value it either: | |
201 | * - adds a socket to the selection list | |
202 | * - remains in the kernel as an nfsd | |
203 | * - remains in the kernel as an nfsiod | |
204 | */ | |
205 | #ifndef _SYS_SYSPROTO_H_ | |
206 | struct nfssvc_args { | |
207 | int flag; | |
208 | caddr_t argp; | |
209 | }; | |
210 | #endif | |
211 | int | |
212 | nfssvc(p, uap) | |
213 | struct proc *p; | |
214 | register struct nfssvc_args *uap; | |
215 | { | |
216 | #ifndef NFS_NOSERVER | |
217 | struct nameidata nd; | |
218 | struct file *fp; | |
219 | struct mbuf *nam; | |
220 | struct nfsd_args nfsdarg; | |
221 | struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; | |
222 | struct nfsd_cargs ncd; | |
223 | struct nfsd *nfsd; | |
224 | struct nfssvc_sock *slp; | |
225 | struct nfsuid *nuidp; | |
226 | struct nfsmount *nmp; | |
227 | #endif /* NFS_NOSERVER */ | |
228 | int error; | |
229 | ||
230 | /* | |
231 | * Must be super user | |
232 | */ | |
233 | error = suser(p->p_ucred, &p->p_acflag); | |
234 | if(error) | |
235 | return (error); | |
236 | while (nfssvc_sockhead_flag & SLP_INIT) { | |
237 | nfssvc_sockhead_flag |= SLP_WANTINIT; | |
238 | (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); | |
239 | } | |
240 | if (uap->flag & NFSSVC_BIOD) | |
241 | error = nfssvc_iod(p); | |
242 | #ifdef NFS_NOSERVER | |
243 | else | |
244 | error = ENXIO; | |
245 | #else /* !NFS_NOSERVER */ | |
246 | else if (uap->flag & NFSSVC_MNTD) { | |
247 | error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); | |
248 | if (error) | |
249 | return (error); | |
250 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, | |
251 | ncd.ncd_dirp, p); | |
252 | error = namei(&nd); | |
253 | if (error) | |
254 | return (error); | |
255 | if ((nd.ni_vp->v_flag & VROOT) == 0) | |
256 | error = EINVAL; | |
257 | nmp = VFSTONFS(nd.ni_vp->v_mount); | |
258 | vput(nd.ni_vp); | |
259 | if (error) | |
260 | return (error); | |
261 | ||
262 | /* disable split funnels now */ | |
263 | thread_funnel_merge(kernel_flock, network_flock); | |
264 | ||
265 | if ((nmp->nm_flag & NFSMNT_MNTD) && | |
266 | (uap->flag & NFSSVC_GOTAUTH) == 0) | |
267 | return (0); | |
268 | nmp->nm_flag |= NFSMNT_MNTD; | |
269 | error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, | |
270 | uap->argp, p); | |
271 | } else if (uap->flag & NFSSVC_ADDSOCK) { | |
272 | error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); | |
273 | if (error) | |
274 | return (error); | |
275 | error = getsock(p->p_fd, nfsdarg.sock, &fp); | |
276 | if (error) | |
277 | return (error); | |
278 | /* | |
279 | * Get the client address for connected sockets. | |
280 | */ | |
281 | if (nfsdarg.name == NULL || nfsdarg.namelen == 0) | |
282 | nam = (struct mbuf *)0; | |
283 | else { | |
284 | error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, | |
285 | MT_SONAME); | |
286 | if (error) | |
287 | return (error); | |
288 | } | |
289 | error = nfssvc_addsock(fp, nam, p); | |
290 | } else { | |
291 | error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); | |
292 | if (error) | |
293 | return (error); | |
294 | ||
295 | /* disable split funnels now */ | |
296 | thread_funnel_merge(kernel_flock, network_flock); | |
297 | ||
298 | if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) && | |
299 | (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { | |
300 | slp = nfsd->nfsd_slp; | |
301 | ||
302 | /* | |
303 | * First check to see if another nfsd has already | |
304 | * added this credential. | |
305 | */ | |
306 | for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; | |
307 | nuidp != 0; nuidp = nuidp->nu_hash.le_next) { | |
308 | if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid && | |
309 | (!nfsd->nfsd_nd->nd_nam2 || | |
310 | netaddr_match(NU_NETFAM(nuidp), | |
311 | &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) | |
312 | break; | |
313 | } | |
314 | if (nuidp) { | |
315 | nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr); | |
316 | nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; | |
317 | } else { | |
318 | /* | |
319 | * Nope, so we will. | |
320 | */ | |
321 | if (slp->ns_numuids < nuidhash_max) { | |
322 | slp->ns_numuids++; | |
323 | nuidp = (struct nfsuid *) | |
324 | _MALLOC_ZONE(sizeof (struct nfsuid), | |
325 | M_NFSUID, M_WAITOK); | |
326 | } else | |
327 | nuidp = (struct nfsuid *)0; | |
328 | if ((slp->ns_flag & SLP_VALID) == 0) { | |
329 | if (nuidp) | |
330 | _FREE_ZONE((caddr_t)nuidp, | |
331 | sizeof (struct nfsuid), M_NFSUID); | |
332 | } else { | |
333 | if (nuidp == (struct nfsuid *)0) { | |
334 | nuidp = slp->ns_uidlruhead.tqh_first; | |
335 | LIST_REMOVE(nuidp, nu_hash); | |
336 | TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, | |
337 | nu_lru); | |
338 | if (nuidp->nu_flag & NU_NAM) | |
339 | m_freem(nuidp->nu_nam); | |
340 | } | |
341 | nuidp->nu_flag = 0; | |
342 | nuidp->nu_cr = nsd->nsd_cr; | |
343 | if (nuidp->nu_cr.cr_ngroups > NGROUPS) | |
344 | nuidp->nu_cr.cr_ngroups = NGROUPS; | |
345 | nuidp->nu_cr.cr_ref = 1; | |
346 | nuidp->nu_timestamp = nsd->nsd_timestamp; | |
347 | nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl; | |
348 | /* | |
349 | * and save the session key in nu_key. | |
350 | */ | |
351 | bcopy(nsd->nsd_key, nuidp->nu_key, | |
352 | sizeof (nsd->nsd_key)); | |
353 | if (nfsd->nfsd_nd->nd_nam2) { | |
354 | struct sockaddr_in *saddr; | |
355 | ||
356 | saddr = mtod(nfsd->nfsd_nd->nd_nam2, | |
357 | struct sockaddr_in *); | |
358 | switch (saddr->sin_family) { | |
359 | case AF_INET: | |
360 | nuidp->nu_flag |= NU_INETADDR; | |
361 | nuidp->nu_inetaddr = | |
362 | saddr->sin_addr.s_addr; | |
363 | break; | |
364 | case AF_ISO: | |
365 | default: | |
366 | nuidp->nu_flag |= NU_NAM; | |
367 | nuidp->nu_nam = m_copym( | |
368 | nfsd->nfsd_nd->nd_nam2, 0, | |
369 | M_COPYALL, M_WAIT); | |
370 | break; | |
371 | }; | |
372 | } | |
373 | TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, | |
374 | nu_lru); | |
375 | LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), | |
376 | nuidp, nu_hash); | |
377 | nfsrv_setcred(&nuidp->nu_cr, | |
378 | &nfsd->nfsd_nd->nd_cr); | |
379 | nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; | |
380 | } | |
381 | } | |
382 | } | |
383 | if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) | |
384 | nfsd->nfsd_flag |= NFSD_AUTHFAIL; | |
385 | error = nfssvc_nfsd(nsd, uap->argp, p); | |
386 | } | |
387 | #endif /* NFS_NOSERVER */ | |
388 | if (error == EINTR || error == ERESTART) | |
389 | error = 0; | |
390 | return (error); | |
391 | } | |
392 | ||
393 | #ifndef NFS_NOSERVER | |
394 | /* | |
395 | * Adds a socket to the list for servicing by nfsds. | |
396 | */ | |
397 | static int | |
398 | nfssvc_addsock(fp, mynam, p) | |
399 | struct file *fp; | |
400 | struct mbuf *mynam; | |
401 | struct proc *p; | |
402 | { | |
403 | register struct mbuf *m; | |
404 | register int siz; | |
405 | register struct nfssvc_sock *slp; | |
406 | register struct socket *so; | |
407 | struct nfssvc_sock *tslp; | |
408 | int error, s; | |
409 | ||
410 | so = (struct socket *)fp->f_data; | |
411 | tslp = (struct nfssvc_sock *)0; | |
412 | /* | |
413 | * Add it to the list, as required. | |
414 | */ | |
415 | thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); | |
416 | if (so->so_proto->pr_protocol == IPPROTO_UDP) { | |
417 | tslp = nfs_udpsock; | |
418 | if (tslp->ns_flag & SLP_VALID) { | |
419 | m_freem(mynam); | |
420 | thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); | |
421 | return (EPERM); | |
422 | } | |
423 | #if ISO | |
424 | } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) { | |
425 | tslp = nfs_cltpsock; | |
426 | if (tslp->ns_flag & SLP_VALID) { | |
427 | m_freem(mynam); | |
428 | thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); | |
429 | return (EPERM); | |
430 | } | |
431 | #endif /* ISO */ | |
432 | } | |
433 | if (so->so_type == SOCK_STREAM) | |
434 | siz = NFS_MAXPACKET + sizeof (u_long); | |
435 | else | |
436 | siz = NFS_MAXPACKET; | |
437 | error = soreserve(so, siz, siz); | |
438 | if (error) { | |
439 | m_freem(mynam); | |
440 | thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); | |
441 | return (error); | |
442 | } | |
443 | ||
444 | /* | |
445 | * Set protocol specific options { for now TCP only } and | |
446 | * reserve some space. For datagram sockets, this can get called | |
447 | * repeatedly for the same socket, but that isn't harmful. | |
448 | */ | |
449 | if (so->so_type == SOCK_STREAM) { | |
450 | struct sockopt sopt; | |
451 | int val; | |
452 | ||
453 | bzero(&sopt, sizeof sopt); | |
454 | sopt.sopt_level = SOL_SOCKET; | |
455 | sopt.sopt_name = SO_KEEPALIVE; | |
456 | sopt.sopt_val = &val; | |
457 | sopt.sopt_valsize = sizeof val; | |
458 | val = 1; | |
459 | sosetopt(so, &sopt); | |
460 | } | |
461 | if (so->so_proto->pr_domain->dom_family == AF_INET && | |
462 | so->so_proto->pr_protocol == IPPROTO_TCP) { | |
463 | struct sockopt sopt; | |
464 | int val; | |
465 | ||
466 | bzero(&sopt, sizeof sopt); | |
467 | sopt.sopt_level = IPPROTO_TCP; | |
468 | sopt.sopt_name = TCP_NODELAY; | |
469 | sopt.sopt_val = &val; | |
470 | sopt.sopt_valsize = sizeof val; | |
471 | val = 1; | |
472 | sosetopt(so, &sopt); | |
473 | } | |
474 | ||
475 | so->so_rcv.sb_flags &= ~SB_NOINTR; | |
476 | so->so_rcv.sb_timeo = 0; | |
477 | so->so_snd.sb_flags &= ~SB_NOINTR; | |
478 | so->so_snd.sb_timeo = 0; | |
479 | thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); | |
480 | if (tslp) | |
481 | slp = tslp; | |
482 | else { | |
483 | MALLOC(slp, struct nfssvc_sock *, sizeof(struct nfssvc_sock), | |
484 | M_NFSSVC, M_WAITOK); | |
485 | bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); | |
486 | TAILQ_INIT(&slp->ns_uidlruhead); | |
487 | TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); | |
488 | } | |
489 | slp->ns_so = so; | |
490 | slp->ns_nam = mynam; | |
491 | slp->ns_fp = fp; | |
492 | (void)fref(fp); | |
493 | thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); | |
494 | s = splnet(); | |
495 | so->so_upcallarg = (caddr_t)slp; | |
496 | so->so_upcall = nfsrv_rcv; | |
497 | so->so_rcv.sb_flags |= SB_UPCALL; /* required for freebsd merge */ | |
498 | thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); | |
499 | slp->ns_flag = (SLP_VALID | SLP_NEEDQ); | |
500 | nfsrv_wakenfsd(slp); | |
501 | splx(s); | |
502 | return (0); | |
503 | } | |
504 | ||
505 | /* | |
506 | * Called by nfssvc() for nfsds. Just loops around servicing rpc requests | |
507 | * until it is killed by a signal. | |
508 | */ | |
509 | static int | |
510 | nfssvc_nfsd(nsd, argp, p) | |
511 | struct nfsd_srvargs *nsd; | |
512 | caddr_t argp; | |
513 | struct proc *p; | |
514 | { | |
515 | register struct mbuf *m; | |
516 | register int siz; | |
517 | register struct nfssvc_sock *slp; | |
518 | register struct socket *so; | |
519 | register int *solockp; | |
520 | struct nfsd *nfsd = nsd->nsd_nfsd; | |
521 | struct nfsrv_descript *nd = NULL; | |
522 | struct mbuf *mreq; | |
523 | int error = 0, cacherep, s, sotype, writes_todo; | |
524 | int procrastinate; | |
525 | u_quad_t cur_usec; | |
526 | extern void nfs_aio_thread_init(); | |
527 | ||
528 | #ifndef nolint | |
529 | cacherep = RC_DOIT; | |
530 | writes_todo = 0; | |
531 | #endif | |
532 | s = splnet(); | |
533 | if (nfsd == (struct nfsd *)0) { | |
534 | MALLOC(nfsd, struct nfsd *, sizeof(struct nfsd), M_NFSD, M_WAITOK); | |
535 | nsd->nsd_nfsd = nfsd; | |
536 | bzero((caddr_t)nfsd, sizeof (struct nfsd)); | |
537 | nfsd->nfsd_procp = p; | |
538 | TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); | |
539 | nfs_numnfsd++; | |
540 | nfs_aio_thread_init(); | |
541 | } | |
542 | /* | |
543 | * Loop getting rpc requests until SIGKILL. | |
544 | */ | |
545 | for (;;) { | |
546 | if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { | |
547 | while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && | |
548 | (nfsd_head_flag & NFSD_CHECKSLP) == 0) { | |
549 | nfsd->nfsd_flag |= NFSD_WAITING; | |
550 | nfsd_waiting++; | |
551 | error = tsleep((caddr_t)nfsd, PSOCK | PCATCH, | |
552 | "nfsd", 0); | |
553 | nfsd_waiting--; | |
554 | if (error) | |
555 | goto done; | |
556 | } | |
557 | if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && | |
558 | (nfsd_head_flag & NFSD_CHECKSLP) != 0) { | |
559 | for (slp = nfssvc_sockhead.tqh_first; slp != 0; | |
560 | slp = slp->ns_chain.tqe_next) { | |
561 | if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) | |
562 | == (SLP_VALID | SLP_DOREC)) { | |
563 | slp->ns_flag &= ~SLP_DOREC; | |
564 | slp->ns_sref++; | |
565 | nfsd->nfsd_slp = slp; | |
566 | break; | |
567 | } | |
568 | } | |
569 | if (slp == 0) | |
570 | nfsd_head_flag &= ~NFSD_CHECKSLP; | |
571 | } | |
572 | if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0) | |
573 | continue; | |
574 | if (slp->ns_flag & SLP_VALID) { | |
575 | if (slp->ns_flag & SLP_DISCONN) | |
576 | nfsrv_zapsock(slp); | |
577 | else if (slp->ns_flag & SLP_NEEDQ) { | |
578 | slp->ns_flag &= ~SLP_NEEDQ; | |
579 | (void) nfs_sndlock(&slp->ns_solock, | |
580 | (struct nfsreq *)0); | |
581 | thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); | |
582 | nfsrv_rcv(slp->ns_so, (caddr_t)slp, | |
583 | M_WAIT); | |
584 | thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); | |
585 | nfs_sndunlock(&slp->ns_solock); | |
586 | } | |
587 | error = nfsrv_dorec(slp, nfsd, &nd); | |
588 | cur_usec = (u_quad_t)time.tv_sec * 1000000 + | |
589 | (u_quad_t)time.tv_usec; | |
590 | if (error && slp->ns_tq.lh_first && | |
591 | slp->ns_tq.lh_first->nd_time <= cur_usec) { | |
592 | error = 0; | |
593 | cacherep = RC_DOIT; | |
594 | writes_todo = 1; | |
595 | } else | |
596 | writes_todo = 0; | |
597 | nfsd->nfsd_flag |= NFSD_REQINPROG; | |
598 | } | |
599 | } else { | |
600 | error = 0; | |
601 | slp = nfsd->nfsd_slp; | |
602 | } | |
603 | if (error || (slp->ns_flag & SLP_VALID) == 0) { | |
604 | if (nd) { | |
605 | _FREE_ZONE((caddr_t)nd, | |
606 | sizeof *nd, M_NFSRVDESC); | |
607 | nd = NULL; | |
608 | } | |
609 | nfsd->nfsd_slp = (struct nfssvc_sock *)0; | |
610 | nfsd->nfsd_flag &= ~NFSD_REQINPROG; | |
611 | nfsrv_slpderef(slp); | |
612 | continue; | |
613 | } | |
614 | splx(s); | |
615 | so = slp->ns_so; | |
616 | sotype = so->so_type; | |
617 | if (so->so_proto->pr_flags & PR_CONNREQUIRED) | |
618 | solockp = &slp->ns_solock; | |
619 | else | |
620 | solockp = (int *)0; | |
621 | if (nd) { | |
622 | nd->nd_starttime = time; | |
623 | if (nd->nd_nam2) | |
624 | nd->nd_nam = nd->nd_nam2; | |
625 | else | |
626 | nd->nd_nam = slp->ns_nam; | |
627 | ||
628 | /* | |
629 | * Check to see if authorization is needed. | |
630 | */ | |
631 | if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { | |
632 | nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; | |
633 | nsd->nsd_haddr = mtod(nd->nd_nam, | |
634 | struct sockaddr_in *)->sin_addr.s_addr; | |
635 | nsd->nsd_authlen = nfsd->nfsd_authlen; | |
636 | nsd->nsd_verflen = nfsd->nfsd_verflen; | |
637 | if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr, | |
638 | nfsd->nfsd_authlen) && | |
639 | !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr, | |
640 | nfsd->nfsd_verflen) && | |
641 | !copyout((caddr_t)nsd, argp, sizeof (*nsd))) | |
642 | return (ENEEDAUTH); | |
643 | cacherep = RC_DROPIT; | |
644 | } else | |
645 | cacherep = nfsrv_getcache(nd, slp, &mreq); | |
646 | ||
647 | /* | |
648 | * Check for just starting up for NQNFS and send | |
649 | * fake "try again later" replies to the NQNFS clients. | |
650 | */ | |
651 | if (notstarted && nqnfsstarttime <= time.tv_sec) { | |
652 | if (modify_flag) { | |
653 | nqnfsstarttime = time.tv_sec + nqsrv_writeslack; | |
654 | modify_flag = 0; | |
655 | } else | |
656 | notstarted = 0; | |
657 | } | |
658 | if (notstarted) { | |
659 | if ((nd->nd_flag & ND_NQNFS) == 0) | |
660 | cacherep = RC_DROPIT; | |
661 | else if (nd->nd_procnum != NFSPROC_WRITE) { | |
662 | nd->nd_procnum = NFSPROC_NOOP; | |
663 | nd->nd_repstat = NQNFS_TRYLATER; | |
664 | cacherep = RC_DOIT; | |
665 | } else | |
666 | modify_flag = 1; | |
667 | } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { | |
668 | nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; | |
669 | nd->nd_procnum = NFSPROC_NOOP; | |
670 | nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); | |
671 | cacherep = RC_DOIT; | |
672 | } else if (nfs_privport) { | |
673 | /* Check if source port is privileged */ | |
674 | u_short port; | |
675 | struct sockaddr *nam = nd->nd_nam; | |
676 | struct sockaddr_in *sin; | |
677 | ||
678 | sin = (struct sockaddr_in *)nam; | |
679 | port = ntohs(sin->sin_port); | |
680 | if (port >= IPPORT_RESERVED && | |
681 | nd->nd_procnum != NFSPROC_NULL) { | |
682 | nd->nd_procnum = NFSPROC_NOOP; | |
683 | nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); | |
684 | cacherep = RC_DOIT; | |
685 | printf("NFS request from unprivileged port (%s:%d)\n", | |
686 | (char *)(inet_ntoa(sin->sin_addr)), port); | |
687 | } | |
688 | } | |
689 | ||
690 | } | |
691 | ||
692 | /* | |
693 | * Loop to get all the write rpc relies that have been | |
694 | * gathered together. | |
695 | */ | |
696 | do { | |
697 | switch (cacherep) { | |
698 | case RC_DOIT: | |
699 | if (nd && (nd->nd_flag & ND_NFSV3)) | |
700 | procrastinate = nfsrvw_procrastinate_v3; | |
701 | else | |
702 | procrastinate = nfsrvw_procrastinate; | |
703 | if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && | |
704 | procrastinate > 0 && !notstarted)) | |
705 | error = nfsrv_writegather(&nd, slp, | |
706 | nfsd->nfsd_procp, &mreq); | |
707 | else | |
708 | error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, | |
709 | slp, nfsd->nfsd_procp, &mreq); | |
710 | if (mreq == NULL) | |
711 | break; | |
712 | if (error) { | |
713 | if (nd->nd_procnum != NQNFSPROC_VACATED) | |
714 | nfsstats.srv_errs++; | |
715 | nfsrv_updatecache(nd, FALSE, mreq); | |
716 | if (nd->nd_nam2) | |
717 | m_freem(nd->nd_nam2); | |
718 | break; | |
719 | } | |
720 | nfsstats.srvrpccnt[nd->nd_procnum]++; | |
721 | nfsrv_updatecache(nd, TRUE, mreq); | |
722 | nd->nd_mrep = (struct mbuf *)0; | |
723 | case RC_REPLY: | |
724 | m = mreq; | |
725 | siz = 0; | |
726 | while (m) { | |
727 | siz += m->m_len; | |
728 | m = m->m_next; | |
729 | } | |
730 | if (siz <= 0 || siz > NFS_MAXPACKET) { | |
731 | printf("mbuf siz=%d\n",siz); | |
732 | panic("Bad nfs svc reply"); | |
733 | } | |
734 | m = mreq; | |
735 | m->m_pkthdr.len = siz; | |
736 | m->m_pkthdr.rcvif = (struct ifnet *)0; | |
737 | /* | |
738 | * For stream protocols, prepend a Sun RPC | |
739 | * Record Mark. | |
740 | */ | |
741 | if (sotype == SOCK_STREAM) { | |
742 | M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); | |
743 | *mtod(m, u_long *) = htonl(0x80000000 | siz); | |
744 | } | |
745 | if (solockp) | |
746 | (void) nfs_sndlock(solockp, (struct nfsreq *)0); | |
747 | if (slp->ns_flag & SLP_VALID) | |
748 | error = nfs_send(so, nd->nd_nam2, m, NULL); | |
749 | else { | |
750 | error = EPIPE; | |
751 | m_freem(m); | |
752 | } | |
753 | if (nfsrtton) | |
754 | nfsd_rt(sotype, nd, cacherep); | |
755 | if (nd->nd_nam2) | |
756 | MFREE(nd->nd_nam2, m); | |
757 | if (nd->nd_mrep) | |
758 | m_freem(nd->nd_mrep); | |
759 | if (error == EPIPE) | |
760 | nfsrv_zapsock(slp); | |
761 | if (solockp) | |
762 | nfs_sndunlock(solockp); | |
763 | if (error == EINTR || error == ERESTART) { | |
764 | _FREE_ZONE((caddr_t)nd, | |
765 | sizeof *nd, M_NFSRVDESC); | |
766 | nfsrv_slpderef(slp); | |
767 | s = splnet(); | |
768 | goto done; | |
769 | } | |
770 | break; | |
771 | case RC_DROPIT: | |
772 | if (nfsrtton) | |
773 | nfsd_rt(sotype, nd, cacherep); | |
774 | m_freem(nd->nd_mrep); | |
775 | m_freem(nd->nd_nam2); | |
776 | break; | |
777 | }; | |
778 | if (nd) { | |
779 | FREE_ZONE((caddr_t)nd, sizeof *nd, M_NFSRVDESC); | |
780 | nd = NULL; | |
781 | } | |
782 | ||
783 | /* | |
784 | * Check to see if there are outstanding writes that | |
785 | * need to be serviced. | |
786 | */ | |
787 | cur_usec = (u_quad_t)time.tv_sec * 1000000 + | |
788 | (u_quad_t)time.tv_usec; | |
789 | s = splsoftclock(); | |
790 | if (slp->ns_tq.lh_first && | |
791 | slp->ns_tq.lh_first->nd_time <= cur_usec) { | |
792 | cacherep = RC_DOIT; | |
793 | writes_todo = 1; | |
794 | } else | |
795 | writes_todo = 0; | |
796 | splx(s); | |
797 | } while (writes_todo); | |
798 | s = splnet(); | |
799 | if (nfsrv_dorec(slp, nfsd, &nd)) { | |
800 | nfsd->nfsd_flag &= ~NFSD_REQINPROG; | |
801 | nfsd->nfsd_slp = NULL; | |
802 | nfsrv_slpderef(slp); | |
803 | } | |
804 | } | |
805 | done: | |
806 | TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); | |
807 | splx(s); | |
808 | _FREE((caddr_t)nfsd, M_NFSD); | |
809 | nsd->nsd_nfsd = (struct nfsd *)0; | |
810 | if (--nfs_numnfsd == 0) | |
811 | nfsrv_init(TRUE); /* Reinitialize everything */ | |
812 | return (error); | |
813 | } | |
814 | #endif /* NFS_NOSERVER */ | |
815 | ||
816 | int nfs_defect = 0; | |
817 | /* XXX CSM 11/25/97 Upgrade sysctl.h someday */ | |
818 | #ifdef notyet | |
819 | SYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); | |
820 | #endif | |
821 | ||
822 | static int nfssvc_iod_continue(int); | |
823 | ||
824 | /* | |
825 | * Asynchronous I/O daemons for client nfs. | |
826 | * They do read-ahead and write-behind operations on the block I/O cache. | |
827 | * Never returns unless it fails or gets killed. | |
828 | */ | |
829 | static int | |
830 | nfssvc_iod(p) | |
831 | struct proc *p; | |
832 | { | |
833 | register struct buf *bp; | |
834 | register int i, myiod; | |
835 | struct nfsmount *nmp; | |
836 | int error = 0; | |
837 | struct uthread *ut; | |
838 | ||
839 | /* | |
840 | * Assign my position or return error if too many already running | |
841 | */ | |
842 | myiod = -1; | |
843 | for (i = 0; i < NFS_MAXASYNCDAEMON; i++) | |
844 | if (nfs_asyncdaemon[i] == 0) { | |
845 | nfs_asyncdaemon[i]++; | |
846 | myiod = i; | |
847 | break; | |
848 | } | |
849 | if (myiod == -1) | |
850 | return (EBUSY); | |
851 | nfs_numasync++; | |
852 | ||
853 | /* stuff myiod into uthread to get off local stack for | |
854 | continuation */ | |
855 | ||
9bccf70c | 856 | ut = (struct uthread *)get_bsdthread_info(current_act()); |
1c79356b A |
857 | ut->uu_state.uu_nfs_myiod = myiod; /* squirrel away for continuation */ |
858 | ||
859 | nfssvc_iod_continue(0); | |
860 | /* NOTREACHED */ | |
861 | ||
862 | } | |
863 | ||
864 | /* | |
865 | * Continuation for Asynchronous I/O daemons for client nfs. | |
866 | */ | |
867 | static int | |
868 | nfssvc_iod_continue(error) | |
869 | { | |
870 | register struct buf *bp; | |
871 | register int i, myiod; | |
872 | struct nfsmount *nmp; | |
873 | struct uthread *ut; | |
874 | struct proc *p; | |
875 | ||
876 | /* | |
877 | * real myiod is stored in uthread, recover it | |
878 | */ | |
9bccf70c | 879 | ut = (struct uthread *)get_bsdthread_info(current_act()); |
1c79356b | 880 | myiod = ut->uu_state.uu_nfs_myiod; |
0b4e3aa0 | 881 | p = current_proc(); |
1c79356b A |
882 | |
883 | /* | |
884 | * Just loop around doin our stuff until SIGKILL | |
885 | * - actually we don't loop with continuations... | |
886 | */ | |
887 | for (;;) { | |
888 | while (((nmp = nfs_iodmount[myiod]) == NULL | |
889 | || nmp->nm_bufq.tqh_first == NULL) | |
890 | && error == 0) { | |
891 | if (nmp) | |
892 | nmp->nm_bufqiods--; | |
893 | nfs_iodwant[myiod] = p; | |
894 | nfs_iodmount[myiod] = NULL; | |
895 | error = tsleep0((caddr_t)&nfs_iodwant[myiod], | |
896 | PWAIT | PCATCH, "nfsidl", 0, nfssvc_iod_continue); | |
897 | /* NOTREACHED */ | |
898 | } | |
899 | if (error) { | |
900 | nfs_asyncdaemon[myiod] = 0; | |
901 | if (nmp) nmp->nm_bufqiods--; | |
902 | nfs_iodwant[myiod] = NULL; | |
903 | nfs_iodmount[myiod] = NULL; | |
904 | nfs_numasync--; | |
905 | if (error == EINTR || error == ERESTART) | |
906 | error = 0; | |
1c79356b | 907 | unix_syscall_return(error); |
1c79356b A |
908 | } |
909 | while ((bp = nmp->nm_bufq.tqh_first) != NULL) { | |
910 | /* Take one off the front of the list */ | |
911 | TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); | |
912 | nmp->nm_bufqlen--; | |
913 | if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) { | |
914 | nmp->nm_bufqwant = FALSE; | |
915 | wakeup(&nmp->nm_bufq); | |
916 | } | |
917 | if (ISSET(bp->b_flags, B_READ)) | |
918 | (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); | |
919 | else | |
920 | (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); | |
921 | ||
922 | /* | |
923 | * If there are more than one iod on this mount, then defect | |
924 | * so that the iods can be shared out fairly between the mounts | |
925 | */ | |
926 | if (nfs_defect && nmp->nm_bufqiods > 1) { | |
927 | NFS_DPF(ASYNCIO, | |
928 | ("nfssvc_iod: iod %d defecting from mount %p\n", | |
929 | myiod, nmp)); | |
930 | nfs_iodmount[myiod] = NULL; | |
931 | nmp->nm_bufqiods--; | |
932 | break; | |
933 | } | |
934 | } | |
935 | } | |
936 | } | |
937 | ||
938 | /* | |
939 | * Shut down a socket associated with an nfssvc_sock structure. | |
940 | * Should be called with the send lock set, if required. | |
941 | * The trick here is to increment the sref at the start, so that the nfsds | |
942 | * will stop using it and clear ns_flag at the end so that it will not be | |
943 | * reassigned during cleanup. | |
944 | */ | |
945 | static void | |
946 | nfsrv_zapsock(slp) | |
947 | register struct nfssvc_sock *slp; | |
948 | { | |
949 | register struct nfsuid *nuidp, *nnuidp; | |
950 | register struct nfsrv_descript *nwp, *nnwp; | |
951 | struct socket *so; | |
952 | struct file *fp; | |
953 | struct mbuf *m; | |
954 | int s; | |
955 | ||
956 | slp->ns_flag &= ~SLP_ALLFLAGS; | |
957 | fp = slp->ns_fp; | |
958 | if (fp) { | |
959 | slp->ns_fp = (struct file *)0; | |
960 | so = slp->ns_so; | |
961 | thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); | |
962 | so->so_upcall = NULL; | |
963 | so->so_rcv.sb_flags &= ~SB_UPCALL; | |
964 | soshutdown(so, 2); | |
965 | thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); | |
966 | closef(fp, (struct proc *)0); | |
967 | if (slp->ns_nam) | |
968 | MFREE(slp->ns_nam, m); | |
969 | m_freem(slp->ns_raw); | |
970 | m_freem(slp->ns_rec); | |
971 | for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; | |
972 | nuidp = nnuidp) { | |
973 | nnuidp = nuidp->nu_lru.tqe_next; | |
974 | LIST_REMOVE(nuidp, nu_hash); | |
975 | TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); | |
976 | if (nuidp->nu_flag & NU_NAM) | |
977 | m_freem(nuidp->nu_nam); | |
978 | _FREE_ZONE((caddr_t)nuidp, | |
979 | sizeof (struct nfsuid), M_NFSUID); | |
980 | } | |
981 | s = splsoftclock(); | |
982 | for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { | |
983 | nnwp = nwp->nd_tq.le_next; | |
984 | LIST_REMOVE(nwp, nd_tq); | |
985 | _FREE_ZONE((caddr_t)nwp, sizeof *nwp, M_NFSRVDESC); | |
986 | } | |
987 | LIST_INIT(&slp->ns_tq); | |
988 | splx(s); | |
989 | } | |
990 | } | |
991 | ||
992 | /* | |
993 | * Get an authorization string for the uid by having the mount_nfs sitting | |
994 | * on this mount point porpous out of the kernel and do it. | |
995 | */ | |
996 | int | |
997 | nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) | |
998 | register struct nfsmount *nmp; | |
999 | struct nfsreq *rep; | |
1000 | struct ucred *cred; | |
1001 | char **auth_str; | |
1002 | int *auth_len; | |
1003 | char *verf_str; | |
1004 | int *verf_len; | |
1005 | NFSKERBKEY_T key; /* return session key */ | |
1006 | { | |
1007 | int error = 0; | |
1008 | ||
1009 | while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) { | |
1010 | nmp->nm_flag |= NFSMNT_WANTAUTH; | |
1011 | (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, | |
1012 | "nfsauth1", 2 * hz); | |
1013 | error = nfs_sigintr(nmp, rep, rep->r_procp); | |
1014 | if (error) { | |
1015 | nmp->nm_flag &= ~NFSMNT_WANTAUTH; | |
1016 | return (error); | |
1017 | } | |
1018 | } | |
1019 | nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH); | |
1020 | MALLOC(*auth_str, char *, RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); | |
1021 | nmp->nm_authstr = *auth_str; | |
1022 | nmp->nm_authlen = RPCAUTH_MAXSIZ; | |
1023 | nmp->nm_verfstr = verf_str; | |
1024 | nmp->nm_verflen = *verf_len; | |
1025 | nmp->nm_authuid = cred->cr_uid; | |
1026 | wakeup((caddr_t)&nmp->nm_authstr); | |
1027 | ||
1028 | /* | |
1029 | * And wait for mount_nfs to do its stuff. | |
1030 | */ | |
1031 | while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) { | |
1032 | (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, | |
1033 | "nfsauth2", 2 * hz); | |
1034 | error = nfs_sigintr(nmp, rep, rep->r_procp); | |
1035 | } | |
1036 | if (nmp->nm_flag & NFSMNT_AUTHERR) { | |
1037 | nmp->nm_flag &= ~NFSMNT_AUTHERR; | |
1038 | error = EAUTH; | |
1039 | } | |
1040 | if (error) | |
1041 | _FREE((caddr_t)*auth_str, M_TEMP); | |
1042 | else { | |
1043 | *auth_len = nmp->nm_authlen; | |
1044 | *verf_len = nmp->nm_verflen; | |
1045 | bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); | |
1046 | } | |
1047 | nmp->nm_flag &= ~NFSMNT_HASAUTH; | |
1048 | nmp->nm_flag |= NFSMNT_WAITAUTH; | |
1049 | if (nmp->nm_flag & NFSMNT_WANTAUTH) { | |
1050 | nmp->nm_flag &= ~NFSMNT_WANTAUTH; | |
1051 | wakeup((caddr_t)&nmp->nm_authtype); | |
1052 | } | |
1053 | return (error); | |
1054 | } | |
1055 | ||
1056 | /* | |
1057 | * Get a nickname authenticator and verifier. | |
1058 | */ | |
1059 | int | |
1060 | nfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len) | |
1061 | struct nfsmount *nmp; | |
1062 | struct ucred *cred; | |
1063 | char **auth_str; | |
1064 | int *auth_len; | |
1065 | char *verf_str; | |
1066 | int verf_len; | |
1067 | { | |
1068 | register struct nfsuid *nuidp; | |
1069 | register u_long *nickp, *verfp; | |
1070 | struct timeval ktvin, ktvout; | |
1071 | ||
1072 | #if DIAGNOSTIC | |
1073 | if (verf_len < (4 * NFSX_UNSIGNED)) | |
1074 | panic("nfs_getnickauth verf too small"); | |
1075 | #endif | |
1076 | for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first; | |
1077 | nuidp != 0; nuidp = nuidp->nu_hash.le_next) { | |
1078 | if (nuidp->nu_cr.cr_uid == cred->cr_uid) | |
1079 | break; | |
1080 | } | |
1081 | if (!nuidp || nuidp->nu_expire < time.tv_sec) | |
1082 | return (EACCES); | |
1083 | ||
1084 | /* | |
1085 | * Move to the end of the lru list (end of lru == most recently used). | |
1086 | */ | |
1087 | TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); | |
1088 | TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); | |
1089 | ||
1090 | MALLOC(nickp, u_long *, 2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); | |
1091 | *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); | |
1092 | *nickp = txdr_unsigned(nuidp->nu_nickname); | |
1093 | *auth_str = (char *)nickp; | |
1094 | *auth_len = 2 * NFSX_UNSIGNED; | |
1095 | ||
1096 | /* | |
1097 | * Now we must encrypt the verifier and package it up. | |
1098 | */ | |
1099 | verfp = (u_long *)verf_str; | |
1100 | *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); | |
1101 | if (time.tv_sec > nuidp->nu_timestamp.tv_sec || | |
1102 | (time.tv_sec == nuidp->nu_timestamp.tv_sec && | |
1103 | time.tv_usec > nuidp->nu_timestamp.tv_usec)) | |
1104 | nuidp->nu_timestamp = time; | |
1105 | else | |
1106 | nuidp->nu_timestamp.tv_usec++; | |
1107 | ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); | |
1108 | ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); | |
1109 | ||
1110 | /* | |
1111 | * Now encrypt the timestamp verifier in ecb mode using the session | |
1112 | * key. | |
1113 | */ | |
1114 | #if NFSKERB | |
1115 | XXX | |
1116 | #endif | |
1117 | ||
1118 | *verfp++ = ktvout.tv_sec; | |
1119 | *verfp++ = ktvout.tv_usec; | |
1120 | *verfp = 0; | |
1121 | return (0); | |
1122 | } | |
1123 | ||
1124 | /* | |
1125 | * Save the current nickname in a hash list entry on the mount point. | |
1126 | */ | |
1127 | int | |
1128 | nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) | |
1129 | register struct nfsmount *nmp; | |
1130 | struct ucred *cred; | |
1131 | int len; | |
1132 | NFSKERBKEY_T key; | |
1133 | struct mbuf **mdp; | |
1134 | char **dposp; | |
1135 | struct mbuf *mrep; | |
1136 | { | |
1137 | register struct nfsuid *nuidp; | |
1138 | register u_long *tl; | |
1139 | register long t1; | |
1140 | struct mbuf *md = *mdp; | |
1141 | struct timeval ktvin, ktvout; | |
1142 | u_long nick; | |
1143 | char *dpos = *dposp, *cp2; | |
1144 | int deltasec, error = 0; | |
1145 | ||
1146 | if (len == (3 * NFSX_UNSIGNED)) { | |
1147 | nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); | |
1148 | ktvin.tv_sec = *tl++; | |
1149 | ktvin.tv_usec = *tl++; | |
1150 | nick = fxdr_unsigned(u_long, *tl); | |
1151 | ||
1152 | /* | |
1153 | * Decrypt the timestamp in ecb mode. | |
1154 | */ | |
1155 | #if NFSKERB | |
1156 | XXX | |
1157 | #endif | |
1158 | ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); | |
1159 | ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); | |
1160 | deltasec = time.tv_sec - ktvout.tv_sec; | |
1161 | if (deltasec < 0) | |
1162 | deltasec = -deltasec; | |
1163 | /* | |
1164 | * If ok, add it to the hash list for the mount point. | |
1165 | */ | |
1166 | if (deltasec <= NFS_KERBCLOCKSKEW) { | |
1167 | if (nmp->nm_numuids < nuidhash_max) { | |
1168 | nmp->nm_numuids++; | |
1169 | MALLOC_ZONE(nuidp, struct nfsuid *, | |
1170 | sizeof (struct nfsuid), | |
1171 | M_NFSUID, M_WAITOK); | |
1172 | } else { | |
1173 | nuidp = nmp->nm_uidlruhead.tqh_first; | |
1174 | LIST_REMOVE(nuidp, nu_hash); | |
1175 | TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, | |
1176 | nu_lru); | |
1177 | } | |
1178 | nuidp->nu_flag = 0; | |
1179 | nuidp->nu_cr.cr_uid = cred->cr_uid; | |
1180 | nuidp->nu_expire = time.tv_sec + NFS_KERBTTL; | |
1181 | nuidp->nu_timestamp = ktvout; | |
1182 | nuidp->nu_nickname = nick; | |
1183 | bcopy(key, nuidp->nu_key, sizeof (key)); | |
1184 | TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, | |
1185 | nu_lru); | |
1186 | LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid), | |
1187 | nuidp, nu_hash); | |
1188 | } | |
1189 | } else | |
1190 | nfsm_adv(nfsm_rndup(len)); | |
1191 | nfsmout: | |
1192 | *mdp = md; | |
1193 | *dposp = dpos; | |
1194 | return (error); | |
1195 | } | |
1196 | ||
1197 | #ifndef NFS_NOSERVER | |
1198 | ||
1199 | /* | |
1200 | * Derefence a server socket structure. If it has no more references and | |
1201 | * is no longer valid, you can throw it away. | |
1202 | */ | |
1203 | void | |
1204 | nfsrv_slpderef(slp) | |
1205 | register struct nfssvc_sock *slp; | |
1206 | { | |
1207 | if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { | |
1208 | TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); | |
1209 | _FREE((caddr_t)slp, M_NFSSVC); | |
1210 | } | |
1211 | } | |
1212 | ||
1213 | /* | |
1214 | * Initialize the data structures for the server. | |
1215 | * Handshake with any new nfsds starting up to avoid any chance of | |
1216 | * corruption. | |
1217 | */ | |
1218 | void | |
1219 | nfsrv_init(terminating) | |
1220 | int terminating; | |
1221 | { | |
1222 | register struct nfssvc_sock *slp, *nslp; | |
1223 | ||
1224 | if (nfssvc_sockhead_flag & SLP_INIT) | |
1225 | panic("nfsd init"); | |
1226 | nfssvc_sockhead_flag |= SLP_INIT; | |
1227 | if (terminating) { | |
1228 | for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) { | |
1229 | nslp = slp->ns_chain.tqe_next; | |
1230 | if (slp->ns_flag & SLP_VALID) | |
1231 | nfsrv_zapsock(slp); | |
1232 | TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); | |
1233 | _FREE((caddr_t)slp, M_NFSSVC); | |
1234 | } | |
1235 | nfsrv_cleancache(); /* And clear out server cache */ | |
1236 | /* XXX CSM 12/4/97 Revisit when enabling WebNFS */ | |
1237 | #ifdef notyet | |
1238 | } else | |
1239 | nfs_pub.np_valid = 0; | |
1240 | #else | |
1241 | } | |
1242 | #endif | |
1243 | ||
1244 | TAILQ_INIT(&nfssvc_sockhead); | |
1245 | nfssvc_sockhead_flag &= ~SLP_INIT; | |
1246 | if (nfssvc_sockhead_flag & SLP_WANTINIT) { | |
1247 | nfssvc_sockhead_flag &= ~SLP_WANTINIT; | |
1248 | wakeup((caddr_t)&nfssvc_sockhead); | |
1249 | } | |
1250 | ||
1251 | TAILQ_INIT(&nfsd_head); | |
1252 | nfsd_head_flag &= ~NFSD_CHECKSLP; | |
1253 | ||
1254 | MALLOC(nfs_udpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock), | |
1255 | M_NFSSVC, M_WAITOK); | |
1256 | bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock)); | |
1257 | TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); | |
1258 | TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); | |
1259 | ||
1260 | MALLOC(nfs_cltpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock), | |
1261 | M_NFSSVC, M_WAITOK); | |
1262 | bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock)); | |
1263 | TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); | |
1264 | TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); | |
1265 | } | |
1266 | ||
1267 | /* | |
1268 | * Add entries to the server monitor log. | |
1269 | */ | |
1270 | static void | |
1271 | nfsd_rt(sotype, nd, cacherep) | |
1272 | int sotype; | |
1273 | register struct nfsrv_descript *nd; | |
1274 | int cacherep; | |
1275 | { | |
1276 | register struct drt *rt; | |
1277 | ||
1278 | rt = &nfsdrt.drt[nfsdrt.pos]; | |
1279 | if (cacherep == RC_DOIT) | |
1280 | rt->flag = 0; | |
1281 | else if (cacherep == RC_REPLY) | |
1282 | rt->flag = DRT_CACHEREPLY; | |
1283 | else | |
1284 | rt->flag = DRT_CACHEDROP; | |
1285 | if (sotype == SOCK_STREAM) | |
1286 | rt->flag |= DRT_TCP; | |
1287 | if (nd->nd_flag & ND_NQNFS) | |
1288 | rt->flag |= DRT_NQNFS; | |
1289 | else if (nd->nd_flag & ND_NFSV3) | |
1290 | rt->flag |= DRT_NFSV3; | |
1291 | rt->proc = nd->nd_procnum; | |
1292 | if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET) | |
1293 | rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr; | |
1294 | else | |
1295 | rt->ipadr = INADDR_ANY; | |
1296 | rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) + | |
1297 | (time.tv_usec - nd->nd_starttime.tv_usec); | |
1298 | rt->tstamp = time; | |
1299 | nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; | |
1300 | } | |
1301 | #endif /* NFS_NOSERVER */ |