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