The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_syscalls.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 18a06bdc2aaff93a4d7b1637da6c3998


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.