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