]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_syscalls.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_syscalls.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
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.
1c79356b 11 *
37839358
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
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.
1c79356b
A
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>
91447636 69#include <sys/file_internal.h>
1c79356b
A
70#include <sys/filedesc.h>
71#include <sys/stat.h>
91447636
A
72#include <sys/vnode_internal.h>
73#include <sys/mount_internal.h>
74#include <sys/proc_internal.h> /* for fdflags */
75#include <sys/kauth.h>
1c79356b 76#include <sys/sysctl.h>
55e303ae 77#include <sys/ubc.h>
1c79356b
A
78#include <sys/uio.h>
79#include <sys/malloc.h>
91447636 80#include <sys/kpi_mbuf.h>
1c79356b
A
81#include <sys/socket.h>
82#include <sys/socketvar.h>
83#include <sys/domain.h>
84#include <sys/protosw.h>
55e303ae
A
85#include <sys/fcntl.h>
86#include <sys/lockf.h>
1c79356b
A
87#include <sys/syslog.h>
88#include <sys/user.h>
91447636
A
89#include <sys/sysproto.h>
90#include <sys/kpi_socket.h>
91#include <libkern/OSAtomic.h>
1c79356b 92
ccc36f2f
A
93#include <bsm/audit_kernel.h>
94
1c79356b
A
95#include <netinet/in.h>
96#include <netinet/tcp.h>
97#if ISO
98#include <netiso/iso.h>
99#endif
100#include <nfs/xdr_subs.h>
101#include <nfs/rpcv2.h>
102#include <nfs/nfsproto.h>
103#include <nfs/nfs.h>
104#include <nfs/nfsm_subs.h>
105#include <nfs/nfsrvcache.h>
106#include <nfs/nfsmount.h>
107#include <nfs/nfsnode.h>
1c79356b 108#include <nfs/nfsrtt.h>
55e303ae 109#include <nfs/nfs_lock.h>
1c79356b 110
91447636
A
111extern void unix_syscall_return(int);
112
1c79356b 113/* Global defs. */
91447636 114extern int (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd,
1c79356b 115 struct nfssvc_sock *slp,
91447636
A
116 proc_t procp,
117 mbuf_t *mreqp);
1c79356b 118extern int nfs_numasync;
55e303ae 119extern int nfs_ioddelwri;
1c79356b
A
120extern int nfsrtton;
121extern struct nfsstats nfsstats;
122extern int nfsrvw_procrastinate;
123extern int nfsrvw_procrastinate_v3;
91447636 124
1c79356b
A
125struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
126static int nuidhash_max = NFS_MAXUIDHASH;
127
91447636
A
128static void nfsrv_zapsock(struct nfssvc_sock *slp);
129static int nfssvc_iod(proc_t);
130static int nfskerb_clientd(struct nfsmount *, struct nfsd_cargs *, int, user_addr_t, proc_t);
1c79356b
A
131
132static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
133
134#ifndef NFS_NOSERVER
135int nfsd_waiting = 0;
136static struct nfsdrt nfsdrt;
91447636
A
137int nfs_numnfsd = 0;
138static void nfsd_rt(int sotype, struct nfsrv_descript *nd, int cacherep);
139static int nfssvc_addsock(socket_t, mbuf_t, proc_t);
140static int nfssvc_nfsd(struct nfsd_srvargs *,user_addr_t, proc_t);
141static int nfssvc_export(user_addr_t, proc_t);
1c79356b
A
142
143static int nfs_privport = 0;
144/* XXX CSM 11/25/97 Upgrade sysctl.h someday */
145#ifdef notyet
146SYSCTL_INT(_vfs_nfs, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW, &nfs_privport, 0, "");
147SYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay, CTLFLAG_RW, &nfsrvw_procrastinate, 0, "");
148SYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay_v3, CTLFLAG_RW, &nfsrvw_procrastinate_v3, 0, "");
149#endif
150
151/*
152 * NFS server system calls
153 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
154 */
155
156/*
157 * Get file handle system call
158 */
1c79356b 159int
91447636 160getfh(proc_t p, struct getfh_args *uap, __unused int *retval)
1c79356b 161{
91447636
A
162 vnode_t vp;
163 struct nfs_filehandle nfh;
1c79356b
A
164 int error;
165 struct nameidata nd;
91447636
A
166 struct vfs_context context;
167 char path[MAXPATHLEN], *ptr;
168 u_int pathlen;
169 struct nfs_exportfs *nxfs;
170 struct nfs_export *nx;
171
172 context.vc_proc = p;
173 context.vc_ucred = kauth_cred_get();
1c79356b
A
174
175 /*
176 * Must be super user
177 */
91447636
A
178 error = proc_suser(p);
179 if (error)
180 return (error);
181
182 error = copyinstr(uap->fname, path, MAXPATHLEN, (size_t *)&pathlen);
183 if (error)
1c79356b 184 return (error);
91447636
A
185
186 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
187 UIO_SYSSPACE, path, &context);
1c79356b
A
188 error = namei(&nd);
189 if (error)
190 return (error);
91447636
A
191 nameidone(&nd);
192
1c79356b 193 vp = nd.ni_vp;
91447636
A
194
195 // find exportfs that matches f_mntonname
196 lck_rw_lock_shared(&nfs_export_rwlock);
197 ptr = vnode_mount(vp)->mnt_vfsstat.f_mntonname;
198 LIST_FOREACH(nxfs, &nfs_exports, nxfs_next) {
199 if (!strcmp(nxfs->nxfs_path, ptr))
200 break;
201 }
202 if (!nxfs || strncmp(nxfs->nxfs_path, path, strlen(nxfs->nxfs_path))) {
203 error = EINVAL;
204 goto out;
205 }
206 // find export that best matches remainder of path
207 ptr = path + strlen(nxfs->nxfs_path);
208 while (*ptr && (*ptr == '/'))
209 ptr++;
210 LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
211 int len = strlen(nx->nx_path);
212 if (len == 0) // we've hit the export entry for the root directory
213 break;
214 if (!strncmp(nx->nx_path, ptr, len))
215 break;
216 }
217 if (!nx) {
218 error = EINVAL;
219 goto out;
220 }
221
222 bzero(&nfh, sizeof(nfh));
c0fea474
A
223 nfh.nfh_xh.nxh_version = htonl(NFS_FH_VERSION);
224 nfh.nfh_xh.nxh_fsid = htonl(nxfs->nxfs_id);
225 nfh.nfh_xh.nxh_expid = htonl(nx->nx_id);
91447636
A
226 nfh.nfh_xh.nxh_flags = 0;
227 nfh.nfh_xh.nxh_reserved = 0;
228 nfh.nfh_len = NFS_MAX_FID_SIZE;
229 error = VFS_VPTOFH(vp, &nfh.nfh_len, &nfh.nfh_fid[0], NULL);
230 if (nfh.nfh_len > (int)NFS_MAX_FID_SIZE)
231 error = EOVERFLOW;
232 nfh.nfh_xh.nxh_fidlen = nfh.nfh_len;
233 nfh.nfh_len += sizeof(nfh.nfh_xh);
234
235out:
236 lck_rw_done(&nfs_export_rwlock);
237 vnode_put(vp);
1c79356b
A
238 if (error)
239 return (error);
91447636 240 error = copyout((caddr_t)&nfh, uap->fhp, sizeof(nfh));
1c79356b
A
241 return (error);
242}
243
244#endif /* NFS_NOSERVER */
55e303ae 245
91447636
A
246extern struct fileops vnops;
247
55e303ae
A
248/*
249 * syscall for the rpc.lockd to use to translate a NFS file handle into
250 * an open descriptor.
251 *
252 * warning: do not remove the suser() call or this becomes one giant
253 * security hole.
254 */
55e303ae 255int
91447636
A
256fhopen( proc_t p,
257 struct fhopen_args *uap,
258 register_t *retval)
55e303ae 259{
91447636
A
260 vnode_t vp;
261 struct nfs_filehandle nfh;
262 struct nfs_export *nx;
263 struct nfs_export_options *nxo;
55e303ae 264 struct flock lf;
91447636
A
265 struct fileproc *fp, *nfp;
266 int fmode, error, type;
55e303ae 267 int indx;
91447636
A
268 kauth_cred_t cred = proc_ucred(p);
269 struct vfs_context context;
270 kauth_action_t action;
271
272 context.vc_proc = p;
273 context.vc_ucred = cred;
55e303ae
A
274
275 /*
276 * Must be super user
277 */
91447636 278 error = suser(cred, 0);
55e303ae
A
279 if (error)
280 return (error);
281
282 fmode = FFLAGS(uap->flags);
283 /* why not allow a non-read/write open for our lockd? */
284 if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
285 return (EINVAL);
91447636
A
286
287 error = copyin(uap->u_fhp, &nfh.nfh_len, sizeof(nfh.nfh_len));
288 if (error)
289 return (error);
290 if ((nfh.nfh_len < (int)sizeof(struct nfs_exphandle)) ||
291 (nfh.nfh_len > (int)NFS_MAX_FH_SIZE))
292 return (EINVAL);
293 error = copyin(uap->u_fhp, &nfh, sizeof(nfh.nfh_len) + nfh.nfh_len);
55e303ae
A
294 if (error)
295 return (error);
91447636
A
296
297 lck_rw_lock_shared(&nfs_export_rwlock);
298 /* now give me my vnode, it gets returned to me with a reference */
299 error = nfsrv_fhtovp(&nfh, NULL, TRUE, &vp, &nx, &nxo);
300 lck_rw_done(&nfs_export_rwlock);
55e303ae
A
301 if (error)
302 return (error);
91447636 303
55e303ae 304 /*
91447636
A
305 * From now on we have to make sure not
306 * to forget about the vnode.
307 * Any error that causes an abort must vnode_put(vp).
308 * Just set error = err and 'goto bad;'.
55e303ae
A
309 */
310
311 /*
312 * from vn_open
313 */
91447636 314 if (vnode_vtype(vp) == VSOCK) {
55e303ae
A
315 error = EOPNOTSUPP;
316 goto bad;
317 }
318
91447636
A
319 /* disallow write operations on directories */
320 if (vnode_isdir(vp) && (fmode & (FWRITE | O_TRUNC))) {
321 error = EISDIR;
55e303ae
A
322 goto bad;
323 }
324
91447636
A
325 /* compute action to be authorized */
326 action = 0;
327 if (fmode & FREAD)
328 action |= KAUTH_VNODE_READ_DATA;
329 if (fmode & (FWRITE | O_TRUNC))
330 action |= KAUTH_VNODE_WRITE_DATA;
331 if ((error = vnode_authorize(vp, NULL, action, &context)) != 0)
332 goto bad;
55e303ae 333
91447636
A
334 if ((error = VNOP_OPEN(vp, fmode, &context)))
335 goto bad;
336 if ((error = vnode_ref_ext(vp, fmode)))
55e303ae
A
337 goto bad;
338
55e303ae
A
339 /*
340 * end of vn_open code
341 */
342
91447636 343 // starting here... error paths should call vn_close/vnode_put
55e303ae 344 if ((error = falloc(p, &nfp, &indx)) != 0) {
91447636 345 vn_close(vp, fmode & FMASK, cred, p);
55e303ae
A
346 goto bad;
347 }
348 fp = nfp;
349
91447636
A
350 fp->f_fglob->fg_flag = fmode & FMASK;
351 fp->f_fglob->fg_type = DTYPE_VNODE;
352 fp->f_fglob->fg_ops = &vnops;
353 fp->f_fglob->fg_data = (caddr_t)vp;
354
355 // XXX do we really need to support this with fhopen()?
55e303ae
A
356 if (fmode & (O_EXLOCK | O_SHLOCK)) {
357 lf.l_whence = SEEK_SET;
358 lf.l_start = 0;
359 lf.l_len = 0;
360 if (fmode & O_EXLOCK)
361 lf.l_type = F_WRLCK;
362 else
363 lf.l_type = F_RDLCK;
364 type = F_FLOCK;
365 if ((fmode & FNONBLOCK) == 0)
366 type |= F_WAIT;
91447636
A
367 if ((error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, type, &context))) {
368 vn_close(vp, fp->f_fglob->fg_flag, fp->f_fglob->fg_cred, p);
369 fp_free(p, indx, fp);
55e303ae
A
370 return (error);
371 }
91447636 372 fp->f_fglob->fg_flag |= FHASLOCK;
55e303ae
A
373 }
374
91447636
A
375 vnode_put(vp);
376
377 proc_fdlock(p);
55e303ae 378 *fdflags(p, indx) &= ~UF_RESERVED;
91447636
A
379 fp_drop(p, indx, fp, 1);
380 proc_fdunlock(p);
381
55e303ae
A
382 *retval = indx;
383 return (0);
384
385bad:
91447636 386 vnode_put(vp);
55e303ae
A
387 return (error);
388}
389
1c79356b
A
390/*
391 * Nfs server psuedo system call for the nfsd's
392 * Based on the flag value it either:
393 * - adds a socket to the selection list
394 * - remains in the kernel as an nfsd
395 * - remains in the kernel as an nfsiod
396 */
1c79356b 397int
91447636 398nfssvc(proc_t p, struct nfssvc_args *uap, __unused int *retval)
1c79356b
A
399{
400#ifndef NFS_NOSERVER
401 struct nameidata nd;
91447636
A
402 mbuf_t nam;
403 struct user_nfsd_args user_nfsdarg;
1c79356b
A
404 struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
405 struct nfsd_cargs ncd;
406 struct nfsd *nfsd;
407 struct nfssvc_sock *slp;
408 struct nfsuid *nuidp;
409 struct nfsmount *nmp;
55e303ae 410 struct timeval now;
91447636
A
411 socket_t so;
412 struct vfs_context context;
413 struct ucred temp_cred;
1c79356b
A
414#endif /* NFS_NOSERVER */
415 int error;
416
ccc36f2f
A
417 AUDIT_ARG(cmd, uap->flag);
418
1c79356b
A
419 /*
420 * Must be super user
421 */
91447636 422 error = proc_suser(p);
1c79356b
A
423 if(error)
424 return (error);
1c79356b
A
425 if (uap->flag & NFSSVC_BIOD)
426 error = nfssvc_iod(p);
427#ifdef NFS_NOSERVER
428 else
429 error = ENXIO;
430#else /* !NFS_NOSERVER */
431 else if (uap->flag & NFSSVC_MNTD) {
91447636
A
432
433 context.vc_proc = p;
434 context.vc_ucred = kauth_cred_get();
435
1c79356b
A
436 error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd));
437 if (error)
438 return (error);
91447636
A
439
440 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
441 (proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32),
442 CAST_USER_ADDR_T(ncd.ncd_dirp), &context);
1c79356b
A
443 error = namei(&nd);
444 if (error)
445 return (error);
91447636
A
446 nameidone(&nd);
447
448 if (vnode_isvroot(nd.ni_vp) == 0)
1c79356b 449 error = EINVAL;
91447636
A
450 nmp = VFSTONFS(vnode_mount(nd.ni_vp));
451 vnode_put(nd.ni_vp);
1c79356b
A
452 if (error)
453 return (error);
454
55e303ae 455 if ((nmp->nm_state & NFSSTA_MNTD) &&
1c79356b
A
456 (uap->flag & NFSSVC_GOTAUTH) == 0)
457 return (0);
55e303ae 458 nmp->nm_state |= NFSSTA_MNTD;
91447636 459 error = nfskerb_clientd(nmp, &ncd, uap->flag, uap->argp, p);
1c79356b 460 } else if (uap->flag & NFSSVC_ADDSOCK) {
91447636
A
461 if (IS_64BIT_PROCESS(p)) {
462 error = copyin(uap->argp, (caddr_t)&user_nfsdarg, sizeof(user_nfsdarg));
463 } else {
464 struct nfsd_args tmp_args;
465 error = copyin(uap->argp, (caddr_t)&tmp_args, sizeof(tmp_args));
466 if (error == 0) {
467 user_nfsdarg.sock = tmp_args.sock;
468 user_nfsdarg.name = CAST_USER_ADDR_T(tmp_args.name);
469 user_nfsdarg.namelen = tmp_args.namelen;
470 }
471 }
1c79356b
A
472 if (error)
473 return (error);
91447636
A
474 /* get the socket */
475 error = file_socket(user_nfsdarg.sock, &so);
1c79356b
A
476 if (error)
477 return (error);
91447636
A
478 /* Get the client address for connected sockets. */
479 if (user_nfsdarg.name == USER_ADDR_NULL || user_nfsdarg.namelen == 0) {
480 nam = NULL;
481 } else {
482 error = sockargs(&nam, user_nfsdarg.name, user_nfsdarg.namelen, MBUF_TYPE_SONAME);
483 if (error) {
484 /* drop the iocount file_socket() grabbed on the file descriptor */
485 file_drop(user_nfsdarg.sock);
1c79356b 486 return (error);
91447636 487 }
1c79356b 488 }
91447636
A
489 /*
490 * nfssvc_addsock() will grab a retain count on the socket
491 * to keep the socket from being closed when nfsd closes its
492 * file descriptor for it.
493 */
494 error = nfssvc_addsock(so, nam, p);
495 /* drop the iocount file_socket() grabbed on the file descriptor */
496 file_drop(user_nfsdarg.sock);
497 } else if (uap->flag & NFSSVC_NFSD) {
1c79356b
A
498 error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd));
499 if (error)
500 return (error);
501
1c79356b
A
502 if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) &&
503 (nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
504 slp = nfsd->nfsd_slp;
505
506 /*
507 * First check to see if another nfsd has already
508 * added this credential.
509 */
510 for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first;
511 nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
91447636 512 if (kauth_cred_getuid(nuidp->nu_cr) == nsd->nsd_cr.cr_uid &&
1c79356b
A
513 (!nfsd->nfsd_nd->nd_nam2 ||
514 netaddr_match(NU_NETFAM(nuidp),
515 &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
516 break;
517 }
518 if (nuidp) {
91447636 519 nfsrv_setcred(nuidp->nu_cr,nfsd->nfsd_nd->nd_cr);
1c79356b
A
520 nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
521 } else {
522 /*
523 * Nope, so we will.
524 */
525 if (slp->ns_numuids < nuidhash_max) {
526 slp->ns_numuids++;
527 nuidp = (struct nfsuid *)
528 _MALLOC_ZONE(sizeof (struct nfsuid),
529 M_NFSUID, M_WAITOK);
530 } else
531 nuidp = (struct nfsuid *)0;
532 if ((slp->ns_flag & SLP_VALID) == 0) {
91447636 533 if (nuidp) {
55e303ae 534 FREE_ZONE((caddr_t)nuidp,
1c79356b 535 sizeof (struct nfsuid), M_NFSUID);
91447636
A
536 slp->ns_numuids--;
537 }
1c79356b
A
538 } else {
539 if (nuidp == (struct nfsuid *)0) {
540 nuidp = slp->ns_uidlruhead.tqh_first;
91447636
A
541 if (!nuidp)
542 return (ENOMEM);
1c79356b
A
543 LIST_REMOVE(nuidp, nu_hash);
544 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
545 nu_lru);
546 if (nuidp->nu_flag & NU_NAM)
91447636
A
547 mbuf_freem(nuidp->nu_nam);
548 kauth_cred_rele(nuidp->nu_cr);
55e303ae 549 }
1c79356b 550 nuidp->nu_flag = 0;
91447636
A
551
552 if (nsd->nsd_cr.cr_ngroups > NGROUPS)
553 nsd->nsd_cr.cr_ngroups = NGROUPS;
554
555 nfsrv_setcred(&nsd->nsd_cr, &temp_cred);
556 nuidp->nu_cr = kauth_cred_create(&temp_cred);
557
558 if (!nuidp->nu_cr) {
559 FREE_ZONE(nuidp, sizeof(struct nfsuid), M_NFSUID);
560 slp->ns_numuids--;
561 return (ENOMEM);
562 }
1c79356b 563 nuidp->nu_timestamp = nsd->nsd_timestamp;
55e303ae
A
564 microtime(&now);
565 nuidp->nu_expire = now.tv_sec + nsd->nsd_ttl;
1c79356b
A
566 /*
567 * and save the session key in nu_key.
568 */
569 bcopy(nsd->nsd_key, nuidp->nu_key,
570 sizeof (nsd->nsd_key));
571 if (nfsd->nfsd_nd->nd_nam2) {
572 struct sockaddr_in *saddr;
573
91447636 574 saddr = mbuf_data(nfsd->nfsd_nd->nd_nam2);
1c79356b
A
575 switch (saddr->sin_family) {
576 case AF_INET:
577 nuidp->nu_flag |= NU_INETADDR;
578 nuidp->nu_inetaddr =
579 saddr->sin_addr.s_addr;
580 break;
581 case AF_ISO:
582 default:
583 nuidp->nu_flag |= NU_NAM;
91447636
A
584 error = mbuf_copym(nfsd->nfsd_nd->nd_nam2, 0,
585 MBUF_COPYALL, MBUF_WAITOK,
586 &nuidp->nu_nam);
587 if (error) {
588 kauth_cred_rele(nuidp->nu_cr);
589 FREE_ZONE(nuidp, sizeof(struct nfsuid), M_NFSUID);
590 slp->ns_numuids--;
591 return (error);
592 }
1c79356b
A
593 break;
594 };
595 }
596 TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
597 nu_lru);
598 LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
599 nuidp, nu_hash);
91447636
A
600 nfsrv_setcred(nuidp->nu_cr,
601 nfsd->nfsd_nd->nd_cr);
1c79356b
A
602 nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
603 }
604 }
605 }
606 if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
607 nfsd->nfsd_flag |= NFSD_AUTHFAIL;
608 error = nfssvc_nfsd(nsd, uap->argp, p);
91447636
A
609 } else if (uap->flag & NFSSVC_EXPORT) {
610 error = nfssvc_export(uap->argp, p);
611 } else {
612 error = EINVAL;
1c79356b
A
613 }
614#endif /* NFS_NOSERVER */
615 if (error == EINTR || error == ERESTART)
616 error = 0;
617 return (error);
618}
619
91447636
A
620/*
621 * NFSKERB client helper daemon.
622 * Gets authorization strings for "kerb" mounts.
623 */
624static int
625nfskerb_clientd(
626 struct nfsmount *nmp,
627 struct nfsd_cargs *ncd,
628 int flag,
629 user_addr_t argp,
630 proc_t p)
631{
632 struct nfsuid *nuidp, *nnuidp;
633 int error = 0;
634 struct nfsreq *rp;
635 struct timeval now;
636
637 /*
638 * First initialize some variables
639 */
640 microtime(&now);
641
642 /*
643 * If an authorization string is being passed in, get it.
644 */
645 if ((flag & NFSSVC_GOTAUTH) && (nmp->nm_state & NFSSTA_MOUNTED) &&
646 ((nmp->nm_state & NFSSTA_WAITAUTH) == 0)) {
647 if (nmp->nm_state & NFSSTA_HASAUTH)
648 panic("cld kerb");
649 if ((flag & NFSSVC_AUTHINFAIL) == 0) {
650 if (ncd->ncd_authlen <= nmp->nm_authlen &&
651 ncd->ncd_verflen <= nmp->nm_verflen &&
652 !copyin(CAST_USER_ADDR_T(ncd->ncd_authstr),nmp->nm_authstr,ncd->ncd_authlen)&&
653 !copyin(CAST_USER_ADDR_T(ncd->ncd_verfstr),nmp->nm_verfstr,ncd->ncd_verflen)){
654 nmp->nm_authtype = ncd->ncd_authtype;
655 nmp->nm_authlen = ncd->ncd_authlen;
656 nmp->nm_verflen = ncd->ncd_verflen;
657#if NFSKERB
658 nmp->nm_key = ncd->ncd_key;
659#endif
660 } else
661 nmp->nm_state |= NFSSTA_AUTHERR;
662 } else
663 nmp->nm_state |= NFSSTA_AUTHERR;
664 nmp->nm_state |= NFSSTA_HASAUTH;
665 wakeup((caddr_t)&nmp->nm_authlen);
666 } else {
667 nmp->nm_state |= NFSSTA_WAITAUTH;
668 }
669
670 /*
671 * Loop every second updating queue until there is a termination sig.
672 */
673 while (nmp->nm_state & NFSSTA_MOUNTED) {
674 /* Get an authorization string, if required. */
675 if ((nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_HASAUTH)) == 0) {
676 ncd->ncd_authuid = nmp->nm_authuid;
677 if (copyout((caddr_t)ncd, argp, sizeof (struct nfsd_cargs)))
678 nmp->nm_state |= NFSSTA_WAITAUTH;
679 else
680 return (ENEEDAUTH);
681 }
682 /* Wait a bit (no pun) and do it again. */
683 if ((nmp->nm_state & NFSSTA_MOUNTED) &&
684 (nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_HASAUTH))) {
685 error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH,
686 "nfskrbtimr", hz / 3);
687 if (error == EINTR || error == ERESTART)
688 dounmount(nmp->nm_mountp, 0, p);
689 }
690 }
691
692 /*
693 * Finally, we can free up the mount structure.
694 */
695 for (nuidp = nmp->nm_uidlruhead.tqh_first; nuidp != 0; nuidp = nnuidp) {
696 nnuidp = nuidp->nu_lru.tqe_next;
697 LIST_REMOVE(nuidp, nu_hash);
698 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
699 kauth_cred_rele(nuidp->nu_cr);
700 FREE_ZONE((caddr_t)nuidp, sizeof (struct nfsuid), M_NFSUID);
701 }
702 /*
703 * Loop through outstanding request list and remove dangling
704 * references to defunct nfsmount struct
705 */
706 for (rp = nfs_reqq.tqh_first; rp; rp = rp->r_chain.tqe_next)
707 if (rp->r_nmp == nmp)
708 rp->r_nmp = (struct nfsmount *)0;
709 /* Need to wake up any rcvlock waiters so they notice the unmount. */
710 if (nmp->nm_state & NFSSTA_WANTRCV) {
711 nmp->nm_state &= ~NFSSTA_WANTRCV;
712 wakeup(&nmp->nm_state);
713 }
714 FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT);
715 if (error == EWOULDBLOCK)
716 error = 0;
717 return (error);
718}
719
1c79356b
A
720#ifndef NFS_NOSERVER
721/*
722 * Adds a socket to the list for servicing by nfsds.
723 */
724static int
91447636
A
725nfssvc_addsock(
726 socket_t so,
727 mbuf_t mynam,
728 __unused proc_t p)
1c79356b 729{
91447636
A
730 int siz;
731 struct nfssvc_sock *slp;
732 struct nfssvc_sock *tslp = NULL;
733 int error, sodomain, sotype, soprotocol, on = 1;
734 struct timeval timeo;
735
736 /* make sure mbuf constants are set up */
737 if (!nfs_mbuf_mlen)
738 nfs_mbuf_init();
739
740 sock_gettype(so, &sodomain, &sotype, &soprotocol);
741
1c79356b
A
742 /*
743 * Add it to the list, as required.
744 */
91447636 745 if (soprotocol == IPPROTO_UDP) {
1c79356b 746 tslp = nfs_udpsock;
91447636
A
747 if (!tslp || (tslp->ns_flag & SLP_VALID)) {
748 mbuf_freem(mynam);
1c79356b
A
749 return (EPERM);
750 }
751#if ISO
91447636 752 } else if (soprotocol == ISOPROTO_CLTP) {
1c79356b 753 tslp = nfs_cltpsock;
91447636
A
754 if (!tslp || (tslp->ns_flag & SLP_VALID)) {
755 mbuf_freem(mynam);
1c79356b
A
756 return (EPERM);
757 }
758#endif /* ISO */
759 }
55e303ae
A
760 /* reserve buffer space for 2 maximally-sized packets */
761 siz = NFS_MAXPACKET;
91447636 762 if (sotype == SOCK_STREAM)
55e303ae
A
763 siz += sizeof (u_long);
764 siz *= 2;
765 if (siz > NFS_MAXSOCKBUF)
766 siz = NFS_MAXSOCKBUF;
91447636
A
767 if ((error = sock_setsockopt(so, SOL_SOCKET, SO_SNDBUF, &siz, sizeof(siz))) ||
768 (error = sock_setsockopt(so, SOL_SOCKET, SO_RCVBUF, &siz, sizeof(siz)))) {
769 mbuf_freem(mynam);
1c79356b
A
770 return (error);
771 }
772
773 /*
774 * Set protocol specific options { for now TCP only } and
775 * reserve some space. For datagram sockets, this can get called
776 * repeatedly for the same socket, but that isn't harmful.
777 */
91447636
A
778 if (sotype == SOCK_STREAM) {
779 sock_setsockopt(so, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
1c79356b 780 }
91447636
A
781 if (sodomain == AF_INET && soprotocol == IPPROTO_TCP) {
782 sock_setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
1c79356b
A
783 }
784
91447636
A
785 sock_nointerrupt(so, 0);
786
787 timeo.tv_usec = 0;
788 timeo.tv_sec = 0;
789 error = sock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
790 error = sock_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
791
792 if (tslp) {
1c79356b 793 slp = tslp;
91447636
A
794 lck_mtx_lock(nfsd_mutex);
795 } else {
1c79356b
A
796 MALLOC(slp, struct nfssvc_sock *, sizeof(struct nfssvc_sock),
797 M_NFSSVC, M_WAITOK);
91447636
A
798 if (!slp) {
799 mbuf_freem(mynam);
800 return (ENOMEM);
801 }
1c79356b 802 bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
91447636
A
803 lck_rw_init(&slp->ns_rwlock, nfs_slp_rwlock_group, nfs_slp_lock_attr);
804 lck_mtx_init(&slp->ns_wgmutex, nfs_slp_mutex_group, nfs_slp_lock_attr);
1c79356b 805 TAILQ_INIT(&slp->ns_uidlruhead);
91447636 806 lck_mtx_lock(nfsd_mutex);
1c79356b
A
807 TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
808 }
91447636
A
809
810 sock_retain(so); /* grab a retain count on the socket */
1c79356b 811 slp->ns_so = so;
91447636 812 slp->ns_sotype = sotype;
1c79356b 813 slp->ns_nam = mynam;
91447636
A
814
815 socket_lock(so, 1);
1c79356b
A
816 so->so_upcallarg = (caddr_t)slp;
817 so->so_upcall = nfsrv_rcv;
818 so->so_rcv.sb_flags |= SB_UPCALL; /* required for freebsd merge */
91447636
A
819 socket_unlock(so, 1);
820
821 slp->ns_flag = SLP_VALID | SLP_NEEDQ;
822
1c79356b 823 nfsrv_wakenfsd(slp);
91447636
A
824 lck_mtx_unlock(nfsd_mutex);
825
1c79356b
A
826 return (0);
827}
828
829/*
830 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
831 * until it is killed by a signal.
832 */
833static int
834nfssvc_nfsd(nsd, argp, p)
835 struct nfsd_srvargs *nsd;
91447636
A
836 user_addr_t argp;
837 proc_t p;
1c79356b 838{
91447636
A
839 mbuf_t m, mreq;
840 struct nfssvc_sock *slp;
1c79356b
A
841 struct nfsd *nfsd = nsd->nsd_nfsd;
842 struct nfsrv_descript *nd = NULL;
91447636
A
843 int error = 0, cacherep, writes_todo;
844 int siz, procrastinate;
1c79356b 845 u_quad_t cur_usec;
55e303ae 846 struct timeval now;
91447636 847 boolean_t funnel_state;
1c79356b
A
848
849#ifndef nolint
850 cacherep = RC_DOIT;
851 writes_todo = 0;
852#endif
1c79356b
A
853 if (nfsd == (struct nfsd *)0) {
854 MALLOC(nfsd, struct nfsd *, sizeof(struct nfsd), M_NFSD, M_WAITOK);
91447636
A
855 if (!nfsd)
856 return (ENOMEM);
1c79356b
A
857 nsd->nsd_nfsd = nfsd;
858 bzero((caddr_t)nfsd, sizeof (struct nfsd));
859 nfsd->nfsd_procp = p;
91447636 860 lck_mtx_lock(nfsd_mutex);
1c79356b
A
861 TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
862 nfs_numnfsd++;
91447636 863 lck_mtx_unlock(nfsd_mutex);
1c79356b 864 }
91447636
A
865
866 funnel_state = thread_funnel_set(kernel_flock, FALSE);
867
1c79356b
A
868 /*
869 * Loop getting rpc requests until SIGKILL.
870 */
871 for (;;) {
872 if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
91447636
A
873 lck_mtx_lock(nfsd_mutex);
874 while ((nfsd->nfsd_slp == NULL) && !(nfsd_head_flag & NFSD_CHECKSLP)) {
1c79356b
A
875 nfsd->nfsd_flag |= NFSD_WAITING;
876 nfsd_waiting++;
91447636 877 error = msleep(nfsd, nfsd_mutex, PSOCK | PCATCH, "nfsd", 0);
1c79356b 878 nfsd_waiting--;
91447636
A
879 if (error) {
880 lck_mtx_unlock(nfsd_mutex);
1c79356b 881 goto done;
91447636 882 }
1c79356b 883 }
91447636
A
884 if ((nfsd->nfsd_slp == NULL) && (nfsd_head_flag & NFSD_CHECKSLP)) {
885 TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain) {
886 lck_rw_lock_shared(&slp->ns_rwlock);
1c79356b
A
887 if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
888 == (SLP_VALID | SLP_DOREC)) {
91447636
A
889 if (lck_rw_lock_shared_to_exclusive(&slp->ns_rwlock)) {
890 /* upgrade failed and we lost the lock; take exclusive and recheck */
891 lck_rw_lock_exclusive(&slp->ns_rwlock);
892 if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
893 != (SLP_VALID | SLP_DOREC)) {
894 /* flags no longer set, so skip this socket */
895 lck_rw_done(&slp->ns_rwlock);
896 continue;
897 }
898 }
1c79356b
A
899 slp->ns_flag &= ~SLP_DOREC;
900 slp->ns_sref++;
901 nfsd->nfsd_slp = slp;
91447636 902 lck_rw_done(&slp->ns_rwlock);
1c79356b
A
903 break;
904 }
91447636 905 lck_rw_done(&slp->ns_rwlock);
1c79356b
A
906 }
907 if (slp == 0)
908 nfsd_head_flag &= ~NFSD_CHECKSLP;
909 }
91447636
A
910 lck_mtx_unlock(nfsd_mutex);
911 if ((slp = nfsd->nfsd_slp) == NULL)
1c79356b 912 continue;
91447636 913 lck_rw_lock_exclusive(&slp->ns_rwlock);
1c79356b 914 if (slp->ns_flag & SLP_VALID) {
743b1565 915 if ((slp->ns_flag & (SLP_NEEDQ|SLP_DISCONN)) == SLP_NEEDQ) {
91447636
A
916 slp->ns_flag &= ~SLP_NEEDQ;
917 nfsrv_rcv_locked(slp->ns_so, slp, MBUF_WAITOK);
918 }
743b1565
A
919 if (slp->ns_flag & SLP_DISCONN)
920 nfsrv_zapsock(slp);
1c79356b 921 error = nfsrv_dorec(slp, nfsd, &nd);
55e303ae
A
922 microuptime(&now);
923 cur_usec = (u_quad_t)now.tv_sec * 1000000 +
924 (u_quad_t)now.tv_usec;
91447636 925 if (error && slp->ns_wgtime && (slp->ns_wgtime <= cur_usec)) {
1c79356b
A
926 error = 0;
927 cacherep = RC_DOIT;
928 writes_todo = 1;
929 } else
930 writes_todo = 0;
931 nfsd->nfsd_flag |= NFSD_REQINPROG;
932 }
91447636 933 lck_rw_done(&slp->ns_rwlock);
1c79356b
A
934 } else {
935 error = 0;
936 slp = nfsd->nfsd_slp;
937 }
938 if (error || (slp->ns_flag & SLP_VALID) == 0) {
939 if (nd) {
55e303ae 940 if (nd->nd_nam2)
91447636
A
941 mbuf_freem(nd->nd_nam2);
942 if (nd->nd_cr)
943 kauth_cred_rele(nd->nd_cr);
55e303ae 944 FREE_ZONE((caddr_t)nd,
1c79356b
A
945 sizeof *nd, M_NFSRVDESC);
946 nd = NULL;
947 }
91447636 948 nfsd->nfsd_slp = NULL;
1c79356b
A
949 nfsd->nfsd_flag &= ~NFSD_REQINPROG;
950 nfsrv_slpderef(slp);
951 continue;
952 }
1c79356b 953 if (nd) {
55e303ae 954 microuptime(&nd->nd_starttime);
1c79356b
A
955 if (nd->nd_nam2)
956 nd->nd_nam = nd->nd_nam2;
957 else
958 nd->nd_nam = slp->ns_nam;
959
960 /*
961 * Check to see if authorization is needed.
962 */
963 if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
964 nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
91447636 965 nsd->nsd_haddr = ((struct sockaddr_in *)mbuf_data(nd->nd_nam))->sin_addr.s_addr;
1c79356b
A
966 nsd->nsd_authlen = nfsd->nfsd_authlen;
967 nsd->nsd_verflen = nfsd->nfsd_verflen;
91447636 968 if (!copyout(nfsd->nfsd_authstr,CAST_USER_ADDR_T(nsd->nsd_authstr),
1c79356b 969 nfsd->nfsd_authlen) &&
91447636 970 !copyout(nfsd->nfsd_verfstr, CAST_USER_ADDR_T(nsd->nsd_verfstr),
1c79356b 971 nfsd->nfsd_verflen) &&
91447636
A
972 !copyout((caddr_t)nsd, argp, sizeof (*nsd))) {
973 thread_funnel_set(kernel_flock, funnel_state);
1c79356b 974 return (ENEEDAUTH);
91447636 975 }
1c79356b
A
976 cacherep = RC_DROPIT;
977 } else
978 cacherep = nfsrv_getcache(nd, slp, &mreq);
979
91447636 980 if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
1c79356b
A
981 nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
982 nd->nd_procnum = NFSPROC_NOOP;
983 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
984 cacherep = RC_DOIT;
985 } else if (nfs_privport) {
986 /* Check if source port is privileged */
987 u_short port;
91447636 988 struct sockaddr *nam = mbuf_data(nd->nd_nam);
1c79356b
A
989 struct sockaddr_in *sin;
990
991 sin = (struct sockaddr_in *)nam;
992 port = ntohs(sin->sin_port);
993 if (port >= IPPORT_RESERVED &&
994 nd->nd_procnum != NFSPROC_NULL) {
91447636 995 char strbuf[MAX_IPv4_STR_LEN];
1c79356b
A
996 nd->nd_procnum = NFSPROC_NOOP;
997 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
998 cacherep = RC_DOIT;
999 printf("NFS request from unprivileged port (%s:%d)\n",
91447636
A
1000 inet_ntop(AF_INET, &sin->sin_addr, strbuf, sizeof(strbuf)),
1001 port);
1c79356b
A
1002 }
1003 }
1004
1005 }
1006
1007 /*
1008 * Loop to get all the write rpc relies that have been
1009 * gathered together.
1010 */
1011 do {
1012 switch (cacherep) {
1013 case RC_DOIT:
1014 if (nd && (nd->nd_flag & ND_NFSV3))
1015 procrastinate = nfsrvw_procrastinate_v3;
1016 else
1017 procrastinate = nfsrvw_procrastinate;
91447636
A
1018 lck_rw_lock_shared(&nfs_export_rwlock);
1019 if (writes_todo || ((nd->nd_procnum == NFSPROC_WRITE) && (procrastinate > 0)))
1020 error = nfsrv_writegather(&nd, slp, nfsd->nfsd_procp, &mreq);
1c79356b 1021 else
91447636
A
1022 error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, slp, nfsd->nfsd_procp, &mreq);
1023 lck_rw_done(&nfs_export_rwlock);
1c79356b
A
1024 if (mreq == NULL)
1025 break;
1026 if (error) {
91447636 1027 OSAddAtomic(1, (SInt32*)&nfsstats.srv_errs);
1c79356b 1028 nfsrv_updatecache(nd, FALSE, mreq);
55e303ae 1029 if (nd->nd_nam2) {
91447636 1030 mbuf_freem(nd->nd_nam2);
55e303ae
A
1031 nd->nd_nam2 = NULL;
1032 }
1c79356b
A
1033 break;
1034 }
91447636 1035 OSAddAtomic(1, (SInt32*)&nfsstats.srvrpccnt[nd->nd_procnum]);
1c79356b 1036 nfsrv_updatecache(nd, TRUE, mreq);
91447636 1037 nd->nd_mrep = NULL;
1c79356b
A
1038 case RC_REPLY:
1039 m = mreq;
1040 siz = 0;
1041 while (m) {
91447636
A
1042 siz += mbuf_len(m);
1043 m = mbuf_next(m);
1c79356b
A
1044 }
1045 if (siz <= 0 || siz > NFS_MAXPACKET) {
1046 printf("mbuf siz=%d\n",siz);
1047 panic("Bad nfs svc reply");
1048 }
1049 m = mreq;
91447636
A
1050 mbuf_pkthdr_setlen(m, siz);
1051 error = mbuf_pkthdr_setrcvif(m, NULL);
1052 if (error)
1053 panic("nfsd setrcvif failed: %d", error);
1c79356b
A
1054 /*
1055 * For stream protocols, prepend a Sun RPC
1056 * Record Mark.
1057 */
91447636
A
1058 if (slp->ns_sotype == SOCK_STREAM) {
1059 error = mbuf_prepend(&m, NFSX_UNSIGNED, MBUF_WAITOK);
1060 if (!error)
1061 *(u_long*)mbuf_data(m) = htonl(0x80000000 | siz);
1c79356b 1062 }
91447636
A
1063 if (!error) {
1064 if (slp->ns_flag & SLP_VALID) {
1065 error = nfs_send(slp->ns_so, nd->nd_nam2, m, NULL);
1066 } else {
1067 error = EPIPE;
1068 mbuf_freem(m);
1069 }
1070 } else {
1071 mbuf_freem(m);
1c79356b 1072 }
55e303ae 1073 mreq = NULL;
1c79356b 1074 if (nfsrtton)
91447636 1075 nfsd_rt(slp->ns_sotype, nd, cacherep);
55e303ae 1076 if (nd->nd_nam2) {
91447636 1077 mbuf_freem(nd->nd_nam2);
55e303ae
A
1078 nd->nd_nam2 = NULL;
1079 }
1080 if (nd->nd_mrep) {
91447636 1081 mbuf_freem(nd->nd_mrep);
55e303ae
A
1082 nd->nd_mrep = NULL;
1083 }
91447636
A
1084 if (error == EPIPE) {
1085 lck_rw_lock_exclusive(&slp->ns_rwlock);
1c79356b 1086 nfsrv_zapsock(slp);
91447636
A
1087 lck_rw_done(&slp->ns_rwlock);
1088 }
1c79356b 1089 if (error == EINTR || error == ERESTART) {
91447636
A
1090 if (nd->nd_cr)
1091 kauth_cred_rele(nd->nd_cr);
1092 FREE_ZONE((caddr_t)nd, sizeof *nd, M_NFSRVDESC);
1c79356b 1093 nfsrv_slpderef(slp);
1c79356b
A
1094 goto done;
1095 }
1096 break;
1097 case RC_DROPIT:
1098 if (nfsrtton)
91447636
A
1099 nfsd_rt(slp->ns_sotype, nd, cacherep);
1100 mbuf_freem(nd->nd_mrep);
1101 mbuf_freem(nd->nd_nam2);
55e303ae 1102 nd->nd_mrep = nd->nd_nam2 = NULL;
1c79356b
A
1103 break;
1104 };
1105 if (nd) {
55e303ae 1106 if (nd->nd_mrep)
91447636 1107 mbuf_freem(nd->nd_mrep);
55e303ae 1108 if (nd->nd_nam2)
91447636
A
1109 mbuf_freem(nd->nd_nam2);
1110 if (nd->nd_cr)
1111 kauth_cred_rele(nd->nd_cr);
1c79356b
A
1112 FREE_ZONE((caddr_t)nd, sizeof *nd, M_NFSRVDESC);
1113 nd = NULL;
1114 }
1115
1116 /*
1117 * Check to see if there are outstanding writes that
1118 * need to be serviced.
1119 */
55e303ae
A
1120 microuptime(&now);
1121 cur_usec = (u_quad_t)now.tv_sec * 1000000 +
1122 (u_quad_t)now.tv_usec;
91447636 1123 if (slp->ns_wgtime && (slp->ns_wgtime <= cur_usec)) {
1c79356b
A
1124 cacherep = RC_DOIT;
1125 writes_todo = 1;
91447636 1126 } else {
1c79356b 1127 writes_todo = 0;
91447636 1128 }
1c79356b 1129 } while (writes_todo);
91447636 1130 lck_rw_lock_exclusive(&slp->ns_rwlock);
1c79356b 1131 if (nfsrv_dorec(slp, nfsd, &nd)) {
91447636 1132 lck_rw_done(&slp->ns_rwlock);
1c79356b
A
1133 nfsd->nfsd_flag &= ~NFSD_REQINPROG;
1134 nfsd->nfsd_slp = NULL;
1135 nfsrv_slpderef(slp);
91447636
A
1136 } else {
1137 lck_rw_done(&slp->ns_rwlock);
1138 }
1c79356b
A
1139 }
1140done:
91447636
A
1141 thread_funnel_set(kernel_flock, funnel_state);
1142 lck_mtx_lock(nfsd_mutex);
1c79356b 1143 TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
91447636 1144 FREE(nfsd, M_NFSD);
1c79356b
A
1145 nsd->nsd_nfsd = (struct nfsd *)0;
1146 if (--nfs_numnfsd == 0)
1147 nfsrv_init(TRUE); /* Reinitialize everything */
91447636 1148 lck_mtx_unlock(nfsd_mutex);
1c79356b
A
1149 return (error);
1150}
91447636
A
1151
1152static int
1153nfssvc_export(user_addr_t argp, proc_t p)
1154{
1155 int error = 0, is_64bit;
1156 struct user_nfs_export_args unxa;
1157 struct vfs_context context;
1158
1159 context.vc_proc = p;
1160 context.vc_ucred = kauth_cred_get();
1161 is_64bit = IS_64BIT_PROCESS(p);
1162
1163 /* copy in pointers to path and export args */
1164 if (is_64bit) {
1165 error = copyin(argp, (caddr_t)&unxa, sizeof(unxa));
1166 } else {
1167 struct nfs_export_args tnxa;
1168 error = copyin(argp, (caddr_t)&tnxa, sizeof(tnxa));
1169 if (error == 0) {
1170 /* munge into LP64 version of nfs_export_args structure */
1171 unxa.nxa_fsid = tnxa.nxa_fsid;
1172 unxa.nxa_expid = tnxa.nxa_expid;
1173 unxa.nxa_fspath = CAST_USER_ADDR_T(tnxa.nxa_fspath);
1174 unxa.nxa_exppath = CAST_USER_ADDR_T(tnxa.nxa_exppath);
1175 unxa.nxa_flags = tnxa.nxa_flags;
1176 unxa.nxa_netcount = tnxa.nxa_netcount;
1177 unxa.nxa_nets = CAST_USER_ADDR_T(tnxa.nxa_nets);
1178 }
1179 }
1180 if (error)
1181 return (error);
1182
1183 error = nfsrv_export(&unxa, &context);
1184
1185 return (error);
1186}
1187
1c79356b
A
1188#endif /* NFS_NOSERVER */
1189
1190int nfs_defect = 0;
1191/* XXX CSM 11/25/97 Upgrade sysctl.h someday */
1192#ifdef notyet
1193SYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, "");
1194#endif
1195
55e303ae 1196int
91447636 1197nfsclnt(proc_t p, struct nfsclnt_args *uap, __unused int *retval)
55e303ae
A
1198{
1199 struct lockd_ans la;
1200 int error;
1201
1202 if (uap->flag == NFSCLNT_LOCKDWAIT) {
1203 return (nfslockdwait(p));
1204 }
1205 if (uap->flag == NFSCLNT_LOCKDANS) {
1206 error = copyin(uap->argp, &la, sizeof(la));
1207 return (error != 0 ? error : nfslockdans(p, &la));
1208 }
1209 if (uap->flag == NFSCLNT_LOCKDFD)
91447636 1210 return (nfslockdfd(p, CAST_DOWN(int, uap->argp)));
55e303ae
A
1211 return EINVAL;
1212}
1213
1214
1c79356b
A
1215static int nfssvc_iod_continue(int);
1216
1217/*
1218 * Asynchronous I/O daemons for client nfs.
1219 * They do read-ahead and write-behind operations on the block I/O cache.
1220 * Never returns unless it fails or gets killed.
1221 */
1222static int
91447636 1223nfssvc_iod(__unused proc_t p)
1c79356b 1224{
1c79356b 1225 register int i, myiod;
1c79356b
A
1226 struct uthread *ut;
1227
1228 /*
1229 * Assign my position or return error if too many already running
1230 */
1231 myiod = -1;
1232 for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1233 if (nfs_asyncdaemon[i] == 0) {
1234 nfs_asyncdaemon[i]++;
1235 myiod = i;
1236 break;
1237 }
1238 if (myiod == -1)
1239 return (EBUSY);
1240 nfs_numasync++;
1241
55e303ae 1242 /* stuff myiod into uthread to get off local stack for continuation */
1c79356b 1243
91447636 1244 ut = (struct uthread *)get_bsdthread_info(current_thread());
1c79356b
A
1245 ut->uu_state.uu_nfs_myiod = myiod; /* squirrel away for continuation */
1246
1247 nfssvc_iod_continue(0);
1248 /* NOTREACHED */
91447636 1249 return (0);
1c79356b
A
1250}
1251
1252/*
1253 * Continuation for Asynchronous I/O daemons for client nfs.
1254 */
1255static int
91447636 1256nfssvc_iod_continue(int error)
1c79356b 1257{
55e303ae 1258 register struct nfsbuf *bp;
1c79356b
A
1259 register int i, myiod;
1260 struct nfsmount *nmp;
1261 struct uthread *ut;
91447636 1262 proc_t p;
1c79356b
A
1263
1264 /*
1265 * real myiod is stored in uthread, recover it
1266 */
91447636 1267 ut = (struct uthread *)get_bsdthread_info(current_thread());
1c79356b 1268 myiod = ut->uu_state.uu_nfs_myiod;
91447636 1269 p = current_proc(); // XXX
1c79356b
A
1270
1271 /*
1272 * Just loop around doin our stuff until SIGKILL
55e303ae 1273 * - actually we don't loop with continuations...
1c79356b 1274 */
91447636 1275 lck_mtx_lock(nfs_iod_mutex);
1c79356b
A
1276 for (;;) {
1277 while (((nmp = nfs_iodmount[myiod]) == NULL
1278 || nmp->nm_bufq.tqh_first == NULL)
55e303ae 1279 && error == 0 && nfs_ioddelwri == 0) {
1c79356b
A
1280 if (nmp)
1281 nmp->nm_bufqiods--;
91447636 1282 nfs_iodwant[myiod] = p; // XXX this doesn't need to be a proc_t
1c79356b 1283 nfs_iodmount[myiod] = NULL;
91447636
A
1284 error = msleep0((caddr_t)&nfs_iodwant[myiod], nfs_iod_mutex,
1285 PWAIT | PCATCH | PDROP, "nfsidl", 0, nfssvc_iod_continue);
1286 lck_mtx_lock(nfs_iod_mutex);
1c79356b
A
1287 }
1288 if (error) {
1289 nfs_asyncdaemon[myiod] = 0;
1290 if (nmp) nmp->nm_bufqiods--;
1291 nfs_iodwant[myiod] = NULL;
1292 nfs_iodmount[myiod] = NULL;
91447636 1293 lck_mtx_unlock(nfs_iod_mutex);
1c79356b
A
1294 nfs_numasync--;
1295 if (error == EINTR || error == ERESTART)
1296 error = 0;
1c79356b 1297 unix_syscall_return(error);
1c79356b 1298 }
55e303ae 1299 if (nmp != NULL) {
91447636 1300 while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) {
55e303ae
A
1301 /* Take one off the front of the list */
1302 TAILQ_REMOVE(&nmp->nm_bufq, bp, nb_free);
1303 bp->nb_free.tqe_next = NFSNOLIST;
1304 nmp->nm_bufqlen--;
1305 if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) {
1306 nmp->nm_bufqwant = FALSE;
91447636 1307 lck_mtx_unlock(nfs_iod_mutex);
55e303ae 1308 wakeup(&nmp->nm_bufq);
91447636
A
1309 } else {
1310 lck_mtx_unlock(nfs_iod_mutex);
55e303ae 1311 }
91447636
A
1312
1313 SET(bp->nb_flags, NB_IOD);
55e303ae 1314 if (ISSET(bp->nb_flags, NB_READ))
91447636 1315 nfs_doio(bp, bp->nb_rcred, NULL);
55e303ae 1316 else
91447636 1317 nfs_doio(bp, bp->nb_wcred, NULL);
1c79356b 1318
91447636 1319 lck_mtx_lock(nfs_iod_mutex);
55e303ae
A
1320 /*
1321 * If there are more than one iod on this mount, then defect
1322 * so that the iods can be shared out fairly between the mounts
1323 */
1324 if (nfs_defect && nmp->nm_bufqiods > 1) {
55e303ae
A
1325 nfs_iodmount[myiod] = NULL;
1326 nmp->nm_bufqiods--;
1327 break;
1328 }
1329 }
1330 }
91447636
A
1331 lck_mtx_unlock(nfs_iod_mutex);
1332
55e303ae
A
1333 if (nfs_ioddelwri) {
1334 i = 0;
1335 nfs_ioddelwri = 0;
91447636 1336 lck_mtx_lock(nfs_buf_mutex);
55e303ae
A
1337 while (i < 8 && (bp = TAILQ_FIRST(&nfsbufdelwri)) != NULL) {
1338 struct nfsnode *np = VTONFS(bp->nb_vp);
1339 nfs_buf_remfree(bp);
91447636
A
1340 nfs_buf_refget(bp);
1341 while ((error = nfs_buf_acquire(bp, 0, 0, 0)) == EAGAIN);
1342 nfs_buf_refrele(bp);
1343 if (error)
1344 break;
1345 if (!bp->nb_vp) {
1346 /* buffer is no longer valid */
1347 nfs_buf_drop(bp);
1348 continue;
1349 }
55e303ae
A
1350 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
1351 /* put buffer at end of delwri list */
1352 TAILQ_INSERT_TAIL(&nfsbufdelwri, bp, nb_free);
1353 nfsbufdelwricnt++;
91447636
A
1354 nfs_buf_drop(bp);
1355 lck_mtx_unlock(nfs_buf_mutex);
1356 nfs_flushcommits(np->n_vnode, NULL, 1);
55e303ae 1357 } else {
91447636
A
1358 SET(bp->nb_flags, (NB_ASYNC | NB_IOD));
1359 lck_mtx_unlock(nfs_buf_mutex);
55e303ae
A
1360 nfs_buf_write(bp);
1361 }
1362 i++;
91447636 1363 lck_mtx_lock(nfs_buf_mutex);
1c79356b 1364 }
91447636 1365 lck_mtx_unlock(nfs_buf_mutex);
1c79356b 1366 }
91447636
A
1367
1368 lck_mtx_lock(nfs_iod_mutex);
1c79356b
A
1369 }
1370}
1371
1372/*
1373 * Shut down a socket associated with an nfssvc_sock structure.
1374 * Should be called with the send lock set, if required.
1375 * The trick here is to increment the sref at the start, so that the nfsds
1376 * will stop using it and clear ns_flag at the end so that it will not be
1377 * reassigned during cleanup.
1378 */
1379static void
91447636 1380nfsrv_zapsock(struct nfssvc_sock *slp)
1c79356b 1381{
91447636 1382 socket_t so;
1c79356b 1383
91447636
A
1384 if ((slp->ns_flag & SLP_VALID) == 0)
1385 return;
1c79356b 1386 slp->ns_flag &= ~SLP_ALLFLAGS;
91447636
A
1387
1388 so = slp->ns_so;
1389 if (so == NULL)
1390 return;
1391
743b1565
A
1392 /*
1393 * Attempt to deter future upcalls, but leave the
1394 * upcall info in place to avoid a race with the
1395 * networking code.
1396 */
91447636 1397 socket_lock(so, 1);
91447636
A
1398 so->so_rcv.sb_flags &= ~SB_UPCALL;
1399 socket_unlock(so, 1);
743b1565 1400
91447636 1401 sock_shutdown(so, SHUT_RDWR);
1c79356b
A
1402}
1403
1404/*
1405 * Get an authorization string for the uid by having the mount_nfs sitting
1406 * on this mount point porpous out of the kernel and do it.
1407 */
1408int
1409nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
1410 register struct nfsmount *nmp;
1411 struct nfsreq *rep;
91447636 1412 kauth_cred_t cred;
1c79356b
A
1413 char **auth_str;
1414 int *auth_len;
1415 char *verf_str;
1416 int *verf_len;
1417 NFSKERBKEY_T key; /* return session key */
1418{
1419 int error = 0;
1420
55e303ae
A
1421 while ((nmp->nm_state & NFSSTA_WAITAUTH) == 0) {
1422 nmp->nm_state |= NFSSTA_WANTAUTH;
1c79356b
A
1423 (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
1424 "nfsauth1", 2 * hz);
1425 error = nfs_sigintr(nmp, rep, rep->r_procp);
1426 if (error) {
55e303ae 1427 nmp->nm_state &= ~NFSSTA_WANTAUTH;
1c79356b
A
1428 return (error);
1429 }
1430 }
91447636 1431 nmp->nm_state &= ~NFSSTA_WANTAUTH;
1c79356b 1432 MALLOC(*auth_str, char *, RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
91447636
A
1433 if (!*auth_str)
1434 return (ENOMEM);
1c79356b
A
1435 nmp->nm_authstr = *auth_str;
1436 nmp->nm_authlen = RPCAUTH_MAXSIZ;
1437 nmp->nm_verfstr = verf_str;
1438 nmp->nm_verflen = *verf_len;
91447636
A
1439 nmp->nm_authuid = kauth_cred_getuid(cred);
1440 nmp->nm_state &= ~NFSSTA_WAITAUTH;
1c79356b
A
1441 wakeup((caddr_t)&nmp->nm_authstr);
1442
1443 /*
1444 * And wait for mount_nfs to do its stuff.
1445 */
55e303ae 1446 while ((nmp->nm_state & NFSSTA_HASAUTH) == 0 && error == 0) {
1c79356b
A
1447 (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
1448 "nfsauth2", 2 * hz);
1449 error = nfs_sigintr(nmp, rep, rep->r_procp);
1450 }
55e303ae
A
1451 if (nmp->nm_state & NFSSTA_AUTHERR) {
1452 nmp->nm_state &= ~NFSSTA_AUTHERR;
1c79356b
A
1453 error = EAUTH;
1454 }
1455 if (error)
91447636 1456 FREE(*auth_str, M_TEMP);
1c79356b
A
1457 else {
1458 *auth_len = nmp->nm_authlen;
1459 *verf_len = nmp->nm_verflen;
1460 bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key));
1461 }
55e303ae
A
1462 nmp->nm_state &= ~NFSSTA_HASAUTH;
1463 nmp->nm_state |= NFSSTA_WAITAUTH;
1464 if (nmp->nm_state & NFSSTA_WANTAUTH) {
1465 nmp->nm_state &= ~NFSSTA_WANTAUTH;
1c79356b
A
1466 wakeup((caddr_t)&nmp->nm_authtype);
1467 }
1468 return (error);
1469}
1470
1471/*
1472 * Get a nickname authenticator and verifier.
1473 */
1474int
91447636
A
1475nfs_getnickauth(
1476 struct nfsmount *nmp,
1477 kauth_cred_t cred,
1478 char **auth_str,
1479 int *auth_len,
1480 char *verf_str,
1481 __unused int verf_len)
1c79356b
A
1482{
1483 register struct nfsuid *nuidp;
1484 register u_long *nickp, *verfp;
55e303ae 1485 struct timeval ktvin, ktvout, now;
1c79356b
A
1486
1487#if DIAGNOSTIC
1488 if (verf_len < (4 * NFSX_UNSIGNED))
1489 panic("nfs_getnickauth verf too small");
1490#endif
91447636 1491 for (nuidp = NMUIDHASH(nmp, kauth_cred_getuid(cred))->lh_first;
1c79356b 1492 nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
91447636 1493 if (kauth_cred_getuid(nuidp->nu_cr) == kauth_cred_getuid(cred))
1c79356b
A
1494 break;
1495 }
55e303ae
A
1496 microtime(&now);
1497 if (!nuidp || nuidp->nu_expire < now.tv_sec)
1c79356b
A
1498 return (EACCES);
1499
91447636
A
1500 MALLOC(nickp, u_long *, 2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
1501 if (!nickp)
1502 return (ENOMEM);
1503
1c79356b
A
1504 /*
1505 * Move to the end of the lru list (end of lru == most recently used).
1506 */
1507 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
1508 TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
1509
1c79356b
A
1510 *nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
1511 *nickp = txdr_unsigned(nuidp->nu_nickname);
1512 *auth_str = (char *)nickp;
1513 *auth_len = 2 * NFSX_UNSIGNED;
1514
1515 /*
1516 * Now we must encrypt the verifier and package it up.
1517 */
1518 verfp = (u_long *)verf_str;
1519 *verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
55e303ae
A
1520 microtime(&now);
1521 if (now.tv_sec > nuidp->nu_timestamp.tv_sec ||
1522 (now.tv_sec == nuidp->nu_timestamp.tv_sec &&
1523 now.tv_usec > nuidp->nu_timestamp.tv_usec))
1524 nuidp->nu_timestamp = now;
1c79356b
A
1525 else
1526 nuidp->nu_timestamp.tv_usec++;
1527 ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
1528 ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
1529
1530 /*
1531 * Now encrypt the timestamp verifier in ecb mode using the session
1532 * key.
1533 */
1534#if NFSKERB
1535 XXX
1536#endif
1537
1538 *verfp++ = ktvout.tv_sec;
1539 *verfp++ = ktvout.tv_usec;
1540 *verfp = 0;
1541 return (0);
1542}
1543
1544/*
1545 * Save the current nickname in a hash list entry on the mount point.
1546 */
1547int
1548nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
1549 register struct nfsmount *nmp;
91447636 1550 kauth_cred_t cred;
1c79356b
A
1551 int len;
1552 NFSKERBKEY_T key;
91447636 1553 mbuf_t *mdp;
1c79356b 1554 char **dposp;
91447636 1555 mbuf_t mrep;
1c79356b
A
1556{
1557 register struct nfsuid *nuidp;
1558 register u_long *tl;
1559 register long t1;
91447636 1560 mbuf_t md = *mdp;
55e303ae 1561 struct timeval ktvin, ktvout, now;
1c79356b
A
1562 u_long nick;
1563 char *dpos = *dposp, *cp2;
1564 int deltasec, error = 0;
1565
1566 if (len == (3 * NFSX_UNSIGNED)) {
1567 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
1568 ktvin.tv_sec = *tl++;
1569 ktvin.tv_usec = *tl++;
1570 nick = fxdr_unsigned(u_long, *tl);
1571
1572 /*
1573 * Decrypt the timestamp in ecb mode.
1574 */
1575#if NFSKERB
1576 XXX
1577#endif
1578 ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
1579 ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
55e303ae
A
1580 microtime(&now);
1581 deltasec = now.tv_sec - ktvout.tv_sec;
1c79356b
A
1582 if (deltasec < 0)
1583 deltasec = -deltasec;
1584 /*
1585 * If ok, add it to the hash list for the mount point.
1586 */
1587 if (deltasec <= NFS_KERBCLOCKSKEW) {
1588 if (nmp->nm_numuids < nuidhash_max) {
1589 nmp->nm_numuids++;
1590 MALLOC_ZONE(nuidp, struct nfsuid *,
1591 sizeof (struct nfsuid),
1592 M_NFSUID, M_WAITOK);
1593 } else {
91447636
A
1594 nuidp = NULL;
1595 }
1596 if (!nuidp) {
1c79356b 1597 nuidp = nmp->nm_uidlruhead.tqh_first;
91447636
A
1598 if (!nuidp) {
1599 error = ENOMEM;
1600 goto nfsmout;
1601 }
1c79356b 1602 LIST_REMOVE(nuidp, nu_hash);
91447636
A
1603 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
1604 kauth_cred_rele(nuidp->nu_cr);
1c79356b
A
1605 }
1606 nuidp->nu_flag = 0;
91447636
A
1607 kauth_cred_ref(cred);
1608 nuidp->nu_cr = cred;
55e303ae 1609 nuidp->nu_expire = now.tv_sec + NFS_KERBTTL;
1c79356b
A
1610 nuidp->nu_timestamp = ktvout;
1611 nuidp->nu_nickname = nick;
1612 bcopy(key, nuidp->nu_key, sizeof (key));
91447636
A
1613 TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
1614 LIST_INSERT_HEAD(NMUIDHASH(nmp, kauth_cred_getuid(cred)),
1c79356b
A
1615 nuidp, nu_hash);
1616 }
1617 } else
1618 nfsm_adv(nfsm_rndup(len));
1619nfsmout:
1620 *mdp = md;
1621 *dposp = dpos;
1622 return (error);
1623}
1624
1625#ifndef NFS_NOSERVER
1626
1627/*
91447636 1628 * cleanup and release a server socket structure.
1c79356b 1629 */
743b1565 1630void
91447636 1631nfsrv_slpfree(struct nfssvc_sock *slp)
1c79356b 1632{
91447636
A
1633 struct nfsuid *nuidp, *nnuidp;
1634 struct nfsrv_descript *nwp, *nnwp;
1c79356b 1635
91447636
A
1636 if (slp->ns_so) {
1637 sock_release(slp->ns_so);
1638 slp->ns_so = NULL;
1639 }
1640 if (slp->ns_nam)
1641 mbuf_free(slp->ns_nam);
1642 if (slp->ns_raw)
1643 mbuf_freem(slp->ns_raw);
1644 if (slp->ns_rec)
1645 mbuf_freem(slp->ns_rec);
1646 slp->ns_nam = slp->ns_raw = slp->ns_rec = NULL;
1647
1648 for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0;
1649 nuidp = nnuidp) {
1650 nnuidp = nuidp->nu_lru.tqe_next;
1651 LIST_REMOVE(nuidp, nu_hash);
1652 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
1653 if (nuidp->nu_flag & NU_NAM)
1654 mbuf_freem(nuidp->nu_nam);
1655 kauth_cred_rele(nuidp->nu_cr);
1656 FREE_ZONE((caddr_t)nuidp,
1657 sizeof (struct nfsuid), M_NFSUID);
1658 }
55e303ae 1659
91447636
A
1660 for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) {
1661 nnwp = nwp->nd_tq.le_next;
1662 LIST_REMOVE(nwp, nd_tq);
1663 if (nwp->nd_cr)
1664 kauth_cred_rele(nwp->nd_cr);
1665 FREE_ZONE((caddr_t)nwp, sizeof *nwp, M_NFSRVDESC);
55e303ae 1666 }
91447636
A
1667 LIST_INIT(&slp->ns_tq);
1668
1669 lck_rw_destroy(&slp->ns_rwlock, nfs_slp_rwlock_group);
1670 lck_mtx_destroy(&slp->ns_wgmutex, nfs_slp_mutex_group);
1671 FREE(slp, M_NFSSVC);
55e303ae
A
1672}
1673
1674/*
91447636
A
1675 * Derefence a server socket structure. If it has no more references and
1676 * is no longer valid, you can throw it away.
55e303ae
A
1677 */
1678void
91447636 1679nfsrv_slpderef(struct nfssvc_sock *slp)
55e303ae 1680{
743b1565
A
1681 struct timeval now;
1682
91447636
A
1683 lck_mtx_lock(nfsd_mutex);
1684 lck_rw_lock_exclusive(&slp->ns_rwlock);
1685 slp->ns_sref--;
1686 if (slp->ns_sref || (slp->ns_flag & SLP_VALID)) {
1687 lck_rw_done(&slp->ns_rwlock);
1688 lck_mtx_unlock(nfsd_mutex);
1689 return;
55e303ae 1690 }
91447636 1691
743b1565
A
1692 /* queue the socket up for deletion */
1693 microuptime(&now);
1694 slp->ns_timestamp = now.tv_sec;
91447636 1695 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
743b1565
A
1696 TAILQ_INSERT_TAIL(&nfssvc_deadsockhead, slp, ns_chain);
1697 lck_rw_done(&slp->ns_rwlock);
91447636 1698 lck_mtx_unlock(nfsd_mutex);
55e303ae
A
1699}
1700
91447636 1701
1c79356b
A
1702/*
1703 * Initialize the data structures for the server.
1704 * Handshake with any new nfsds starting up to avoid any chance of
1705 * corruption.
1706 */
1707void
1708nfsrv_init(terminating)
1709 int terminating;
1710{
91447636 1711 struct nfssvc_sock *slp, *nslp;
743b1565 1712 struct timeval now;
1c79356b 1713
1c79356b 1714 if (terminating) {
743b1565 1715 microuptime(&now);
91447636
A
1716 for (slp = TAILQ_FIRST(&nfssvc_sockhead); slp != 0; slp = nslp) {
1717 nslp = TAILQ_NEXT(slp, ns_chain);
1718 if (slp->ns_flag & SLP_VALID) {
1719 lck_rw_lock_exclusive(&slp->ns_rwlock);
1c79356b 1720 nfsrv_zapsock(slp);
91447636
A
1721 lck_rw_done(&slp->ns_rwlock);
1722 }
743b1565
A
1723 /* queue the socket up for deletion */
1724 slp->ns_timestamp = now.tv_sec;
1c79356b 1725 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
743b1565 1726 TAILQ_INSERT_TAIL(&nfssvc_deadsockhead, slp, ns_chain);
1c79356b
A
1727 }
1728 nfsrv_cleancache(); /* And clear out server cache */
91447636
A
1729/* XXX Revisit when enabling WebNFS */
1730#ifdef WEBNFS_ENABLED
1c79356b
A
1731 } else
1732 nfs_pub.np_valid = 0;
1733#else
1734 }
1735#endif
1736
1737 TAILQ_INIT(&nfssvc_sockhead);
743b1565 1738 TAILQ_INIT(&nfssvc_deadsockhead);
1c79356b
A
1739
1740 TAILQ_INIT(&nfsd_head);
1741 nfsd_head_flag &= ~NFSD_CHECKSLP;
1742
1743 MALLOC(nfs_udpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock),
1744 M_NFSSVC, M_WAITOK);
91447636
A
1745 if (nfs_udpsock) {
1746 bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
1747 lck_rw_init(&nfs_udpsock->ns_rwlock, nfs_slp_rwlock_group, nfs_slp_lock_attr);
1748 TAILQ_INIT(&nfs_udpsock->ns_uidlruhead);
1749 TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
1750 } else {
1751 printf("nfsrv_init() failed to allocate UDP socket\n");
1752 }
1c79356b 1753
91447636 1754#if ISO
1c79356b
A
1755 MALLOC(nfs_cltpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock),
1756 M_NFSSVC, M_WAITOK);
91447636
A
1757 if (nfs_cltpsock) {
1758 bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
1759 lck_rw_init(&nfs_cltpsock->ns_rwlock, nfs_slp_rwlock_group, nfs_slp_lock_attr);
1760 TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead);
1761 TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain);
1762 } else {
1763 printf("nfsrv_init() failed to allocate CLTP socket\n");
1764 }
1765#endif
1c79356b
A
1766}
1767
1768/*
1769 * Add entries to the server monitor log.
1770 */
1771static void
1772nfsd_rt(sotype, nd, cacherep)
1773 int sotype;
1774 register struct nfsrv_descript *nd;
1775 int cacherep;
1776{
1777 register struct drt *rt;
55e303ae 1778 struct timeval now;
1c79356b
A
1779
1780 rt = &nfsdrt.drt[nfsdrt.pos];
1781 if (cacherep == RC_DOIT)
1782 rt->flag = 0;
1783 else if (cacherep == RC_REPLY)
1784 rt->flag = DRT_CACHEREPLY;
1785 else
1786 rt->flag = DRT_CACHEDROP;
1787 if (sotype == SOCK_STREAM)
1788 rt->flag |= DRT_TCP;
1c79356b
A
1789 else if (nd->nd_flag & ND_NFSV3)
1790 rt->flag |= DRT_NFSV3;
1791 rt->proc = nd->nd_procnum;
91447636
A
1792 if (((struct sockaddr *)mbuf_data(nd->nd_nam))->sa_family == AF_INET)
1793 rt->ipadr = ((struct sockaddr_in *)mbuf_data(nd->nd_nam))->sin_addr.s_addr;
1c79356b
A
1794 else
1795 rt->ipadr = INADDR_ANY;
55e303ae
A
1796 microuptime(&now);
1797 rt->resptime = ((now.tv_sec - nd->nd_starttime.tv_sec) * 1000000) +
1798 (now.tv_usec - nd->nd_starttime.tv_usec);
1799 microtime(&rt->tstamp); // XXX unused
1c79356b
A
1800 nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
1801}
1802#endif /* NFS_NOSERVER */