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