home *** CD-ROM | disk | FTP | other *** search
/ GRIPS 2: Government Rast…rocessing Software & Data / GRIPS_2.cdr / dos / ncsa_tel / contribu / byu_tel2.hqx / tcpip / util.c < prev    next >
Text File  |  1989-11-09  |  24KB  |  1,044 lines

  1. /*
  2. *   Util.c
  3. *   utility library for use with the Network kernel
  4. *
  5. *   version 2, full session layer, TK started 6/17/87
  6. *
  7. ****************************************************************************
  8. *                                                                          *
  9. *      part of:                                                            *
  10. *      Network kernel for NCSA Telnet                                      *
  11. *      by Tim Krauskopf                                                    *
  12. *                                                                          *
  13. *      National Center for Supercomputing Applications                     *
  14. *      152 Computing Applications Building                                 *
  15. *      605 E. Springfield Ave.                                             *
  16. *      Champaign, IL  61820                                                *
  17. *                                                                          *
  18. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  19. *                                                                          *
  20. ****************************************************************************
  21. */
  22. #include "stdio.h"
  23. #include "whatami.h"
  24. #include "hostform.h"
  25.  
  26. #ifdef PC
  27. #include "string.h"
  28. #else
  29. char *index();
  30. #ifdef AZTEC
  31. #define strchr(A,B) index(A,B)
  32. #endif
  33. #endif
  34.  
  35. char                             /* special function types */
  36.             *neterrstring(),
  37.             *malloc();
  38. int32 time();                    /* don't forget this sucker! */
  39.  
  40. extern struct machinfo *Sns;
  41.  
  42. static unsigned char
  43.             *Ssstemps[] = {
  44.             "capfile",
  45.             "hp.out",
  46.             "ps.out",
  47.             "tek.out"
  48.             };
  49.  
  50. char Sptypes[NPORTS];        /* port types assigned for session use */
  51.  
  52.  
  53. extern struct config Scon;        /* hardware configuration */
  54.  
  55. #define NTIMES 30
  56.  
  57. /*
  58. *  timer queue of events which will be placed into the event queue
  59. *  when the time is up.
  60. */
  61. struct {
  62.     unsigned char
  63.         eclass,                    /* event queue data */
  64.         event;
  65.     int
  66.         next,                    /* next item in list */
  67.         idata;
  68.     int32 when;                /* when timer is to go off */
  69. } Stq[NTIMES];
  70.  
  71. static int
  72.         domwait = 0,            /* is domain waiting for nameserver? */
  73.         Stfirst,Stfree;            /* pointers for timer queue */
  74.  
  75. #define PFTP 1
  76. #define PRCP 2
  77. #define PDATA 3
  78. #define PDOMAIN 4
  79.  
  80. /************************************************************************/
  81. /*  Snetinit
  82. *   Do network initialization for those who want the defaults all
  83. *   set for them.  Recommend that neterrchange be called before
  84. *   initializing network stuff.
  85. */
  86. Snetinit()
  87.     {
  88.     int i;
  89.  
  90. /*
  91. *  set up the file names
  92. */
  93.     Scon.capture = Ssstemps[0];
  94.     Scon.hpfile = Ssstemps[1];
  95.     Scon.psfile = Ssstemps[2];
  96.     Scon.tekfile = Ssstemps[3];
  97.  
  98.     neteventinit();                /* initializes for error messages to count */
  99.  
  100.     for (i=0; i<NPORTS; i++)
  101.         Sptypes[i] = -1;            /* clear port type flags */
  102.  
  103.     for (i=0; i<NTIMES; i++)
  104.         Stq[i].next = i+1;            /* load linked list */
  105.     Stq[NTIMES-1].next = -1;        /* anchor end */
  106.     Stfirst = -1;
  107.     Stfree = 0;
  108.  
  109.     if (!Sreadhosts()) {             /* parses config file */
  110. #ifdef PC
  111.         netparms(Scon.irqnum,Scon.address,Scon.ioaddr);
  112. #endif
  113.         netconfig(Scon.hw);
  114.  
  115.         if (!netinit()) {            /* starts up hardware */
  116. /*
  117. *  Check for the need to RARP and do it
  118. */
  119.             netgetip(Scon.myipnum);    /* get stored ip num */
  120.             if (comparen(Scon.myipnum,"RARP",4)) {    /* need RARP */
  121.                 if (netgetrarp())    /* stores in nnipnum at lower layer */
  122.                     return(-2);
  123.                 netgetip(Scon.myipnum);
  124.                 netsetip(Scon.myipnum);    
  125.             }
  126.  
  127. /*
  128. *  Give the lower layers a chance to check to see if anyone else
  129. *  is using the same ip number.  Usually generates an ARP packet.
  130. */
  131.             netarpme(Scon.myipnum);        
  132.  
  133.             Ssetgates();            /* finishes IP inits */
  134.             Stask();
  135.             return(0);
  136.         }
  137.     }
  138.  
  139.     return(-1);    
  140. }
  141.  
  142. /**************************************************************************/
  143. /*  Snetopen
  144. *
  145. *   Takes a pointer to a machine record, looked up with Sgethost and
  146. *   initiates the TCP open call.
  147. *
  148. */
  149. Snetopen(m,tport)
  150.     struct machinfo *m;
  151.     int tport;
  152.     {
  153.     int j;
  154.  
  155.     if (!m || m->mstat < HAVEIP)
  156.         return(-1);
  157.  
  158.     j = netxopen(m->hostip,tport,m->retrans,m->mtu,m->maxseg,m->window);
  159.                                     /* do the open call */
  160.  
  161.     if (j >= 0) {
  162.         Sptypes[j] = -1;            /* is allocated to user */
  163.         Stimerset(CONCLASS,CONFAIL,j,m->conto);
  164.         Stimerset(SCLASS,RETRYCON,j,m->retrans/TICKSPERSEC+2);
  165.     }
  166.  
  167.     return(j);
  168. }
  169.  
  170.  
  171. /**************************************************************************/
  172. /*
  173. *  special domain data structures
  174. */
  175. #define DOMSIZE 512                /* maximum domain message size to mess with */
  176.  
  177. /*
  178. *  Header for the DOMAIN queries
  179. *  ALL OF THESE ARE BYTE SWAPPED QUANTITIES!
  180. *  We are the poor slobs who are incompatible with the world's byte order
  181. */
  182. struct dhead {
  183. uint16
  184.     ident,                /* unique identifier */
  185.     flags,    
  186.     qdcount,            /* question section, # of entries */
  187.     ancount,            /* answers, how many */
  188.     nscount,            /* count of name server RRs */
  189.     arcount;            /* number of "additional" records */
  190. };
  191.  
  192. /*
  193. *  flag masks for the flags field of the DOMAIN header
  194. */
  195. #define DQR        0x8000            /* query = 0, response = 1 */
  196. #define DOPCODE    0x7100            /* opcode, see below */
  197. #define DAA        0x0400            /* Authoritative answer */
  198. #define DTC        0x0200            /* Truncation, response was cut off at 512 */
  199. #define DRD        0x0100            /* Recursion desired */
  200. #define DRA        0x0080            /* Recursion available */
  201. #define DRCODE    0x000F            /* response code, see below */
  202.  
  203.                                 /* opcode possible values: */
  204. #define DOPQUERY    0            /* a standard query */
  205. #define DOPIQ        1            /* an inverse query */
  206. #define DOPCQM        2            /* a completion query, multiple reply */
  207. #define DOPCQU        3             /* a completion query, single reply */
  208. /* the rest reserved for future */
  209.  
  210.                                 /* legal response codes: */
  211. #define DROK    0                /* okay response */
  212. #define DRFORM    1                /* format error */
  213. #define DRFAIL    2                /* their problem, server failed */
  214. #define DRNAME    3                /* name error, we know name doesn't exist */
  215. #define DRNOPE    4                /* no can do request */
  216. #define DRNOWAY    5                /* name server refusing to do request */
  217.  
  218. #define DTYPEA    1                /* host address resource record (RR) */
  219. #define DTYPEPTR    12            /* a domain name ptr */
  220.  
  221. #define DIN        1                /* ARPA internet class */
  222. #define DWILD    255                /* wildcard for several of the classifications */
  223.  
  224. /*
  225. *  a resource record is made up of a compressed domain name followed by
  226. *  this structure.  All of these ints need to be byteswapped before use.
  227. */
  228. struct rrpart {
  229.     uint16
  230.         rtype,                    /* resource record type = DTYPEA */
  231.         rclass;                    /* RR class = DIN */
  232.     uint32
  233.         rttl;                    /* time-to-live, changed to 32 bits */
  234.     uint16
  235.         rdlength;                /* length of next field */
  236.     uint8
  237.         rdata[DOMSIZE];            /* data field */
  238. };
  239.  
  240. /*
  241. *  data for domain name lookup
  242. */
  243. struct useek {
  244.     struct dhead h;
  245.     uint8 x[DOMSIZE];
  246. } question;
  247.  
  248. qinit()
  249.     {
  250.     question.h.flags = intswap(DRD);
  251.     question.h.qdcount = intswap(1);
  252.     question.h.ancount = 0;
  253.     question.h.nscount = 0;
  254.     question.h.arcount = 0;
  255. }
  256.  
  257.  
  258. /*********************************************************************/
  259. /*  packdom
  260. *   pack a regular text string into a packed domain name, suitable
  261. *   for the name server.
  262. */
  263. packdom(dst,src)
  264.     char *src,*dst;
  265.     {
  266.     char *p,*q,*savedst;
  267.     int i,dotflag,defflag;
  268.  
  269.     p = src;
  270.     dotflag = defflag = 0;
  271.     savedst = dst;
  272.  
  273.     do {                            /* copy whole string */
  274.         *dst = 0;
  275.         q = dst + 1;
  276.  
  277. /*
  278. *  copy the next label along, char by char until it meets a period or
  279. *  end of string.
  280. */
  281.         while (*p && (*p != '.')) 
  282.             *q++ = *p++;
  283.  
  284.         i = p - src;
  285.         if (i > 0x3f)
  286.             return(-1);
  287.         *dst = i;
  288.         *q = 0;
  289.  
  290.         if (*p) {                    /* update pointers */
  291.             dotflag = 1;
  292.             src = ++p;
  293.             dst = q;
  294.         }
  295.         else if (!dotflag && !defflag && Scon.defdom) {
  296.             p = Scon.defdom;        /* continue packing with default */
  297.             defflag = 1;
  298.             src = p;
  299.             dst = q;
  300.             netposterr(801);        /* using default domain */
  301.         }
  302.  
  303.     } while (*p);
  304.  
  305.     q++;
  306.     return(q-savedst);            /* length of packed string */
  307. }
  308.  
  309. /*********************************************************************/
  310. /*  unpackdom
  311. *  Unpack a compressed domain name that we have received from another
  312. *  host.  Handles pointers to continuation domain names -- buf is used
  313. *  as the base for the offset of any pointer which is present.
  314. *  returns the number of bytes at src which should be skipped over.
  315. *  Includes the NULL terminator in its length count.
  316. */
  317. unpackdom(dst,src,buf)
  318.     char *src,*dst,buf[];
  319.     {
  320.     int i,j,retval;
  321.     char *savesrc;
  322.  
  323.     savesrc = src;
  324.     retval = 0;
  325.  
  326.     while (*src) {
  327.         j = *src;
  328.  
  329.         while ((j & 0xC0) == 0xC0) {
  330.             if (!retval)
  331.                 retval = src-savesrc+2;
  332.             src++;
  333.             src = &buf[(j & 0x3f)*256+*src];        /* pointer dereference */
  334.             j = *src;
  335.         }
  336.  
  337.         src++;
  338.         for (i=0; i < (j & 0x3f) ; i++)
  339.             *dst++ = *src++;
  340.  
  341.         *dst++ = '.';
  342.     }
  343.  
  344.     *(--dst) = 0;            /* add terminator */
  345.     src++;                    /* account for terminator on src */
  346.  
  347.     if (!retval)
  348.         retval = src-savesrc;
  349.  
  350.     return(retval);
  351. }
  352.  
  353. /*********************************************************************/
  354. /*  sendom
  355. *   put together a domain lookup packet and send it
  356. *   uses port 53
  357. */
  358. sendom(s,towho,num)
  359.     char *s,*towho;
  360.     int16 num;
  361.     {
  362.     uint16 i,j,ulen;
  363.     uint8 *psave,*p;
  364.  
  365.     psave = (uint8 *)question.x;
  366.  
  367.     i = packdom(question.x,s);
  368.  
  369. /*
  370. *  load the fields of the question structure a character at a time so
  371. *  that 68000 machines won't barf.
  372. */
  373.     p = &question.x[i];
  374.     *p++ = 0;                /* high byte of qtype */
  375.     *p++ = DTYPEA;            /* number is < 256, so we know high byte=0 */
  376.     *p++ = 0;                /* high byte of qclass */
  377.     *p++ = DIN;                /* qtype is < 256 */
  378.  
  379.     question.h.ident = intswap(num);
  380.     ulen = sizeof(struct dhead)+(p-psave);
  381.  
  382.     netusend(towho,53,997,&question,ulen);
  383.     
  384. }
  385.  
  386. /**************************************************************************/
  387. /*  Sdomain
  388. *   DOMAIN based name lookup
  389. *   query a domain name server to get an IP number
  390. *    Returns the machine number of the machine record for future reference.
  391. *   Events generated will have this number tagged with them.
  392. *   Returns various negative numbers on error conditions.
  393. */
  394. Sdomain(mname)
  395.     char *mname;
  396.     {
  397.     struct machinfo *m;
  398.  
  399.     if (!Sns)                             /* no nameserver, give up now */
  400.         return(-1);
  401.  
  402.     while (*mname && *mname < 33)        /* kill leading spaces */
  403.         mname++;
  404.     if (!(*mname))
  405.         return(-1);
  406.  
  407.     if (!(m = Smadd(mname)))
  408.         return(-1);                        /* adds the number to the machlist */
  409.  
  410.     if (domwait < Scon.domto)
  411.         domwait = Scon.domto;            /* set the minimum timeout */
  412.  
  413.     qinit();                            /* initialize some flag fields */
  414.  
  415.     netulisten(997);                    /* pick a return port */
  416.     if (!m->hname)
  417.         m->hname = m->sname;            /* copy pointer to sname */
  418.  
  419.     sendom(m->hname,Sns->hostip,m->mno);    /* try UDP */
  420.  
  421.     Stimerset(SCLASS,UDPTO,m->mno,domwait);    /* time out quickly first time */
  422.     m->mstat = UDPDOM;
  423.  
  424.     return(m->mno);
  425.  
  426. }
  427.  
  428. /*********************************************************************/
  429. /*  getdomain
  430. *   Look at the results to see if our DOMAIN request is ready.
  431. *   It may be a timeout, which requires another query.
  432. */
  433.  
  434. udpdom()
  435.     {
  436.     struct machinfo *m;
  437.     int i,uret,num;
  438.     char *p;
  439.  
  440.     uret = neturead(&question);
  441.  
  442.     if (uret < 0) {
  443. /*        netputevent(USERCLASS,DOMFAIL,-1);  */
  444.         return(-1);
  445.     }
  446.  
  447.     num = intswap(question.h.ident);        /* get machine number */
  448. /*
  449. *  check to see if the necessary information was in the UDP response
  450. */
  451.     m = Slooknum(num);                /* get machine info record */
  452.     if (!m) {
  453.         netputevent(USERCLASS,DOMFAIL,num);
  454.         return(-1);
  455.     }
  456.  
  457. /*
  458. *  got a response, so reset timeout value to recommended minimum
  459. */
  460.     domwait = Scon.domto;
  461.  
  462.     i = ddextract(&question,m->hostip);
  463.  
  464.     switch (i) {
  465.         case 3:                        /* name does not exist */
  466.             netposterr(802);
  467.             p = neterrstring(-1);
  468.             strncpy(p,m->hname,78);        /* what name */
  469.             netposterr(-1);
  470.             netputevent(USERCLASS,DOMFAIL,num);
  471.             Stimerunset(SCLASS,UDPTO,num);
  472.             return(-1);
  473.         case 0:                        /* we found the IP number */
  474.             Stimerunset(SCLASS,UDPTO,num);
  475.             m->mstat = DOM;            /* mark that we have it from DOMAIN */
  476.             netputevent(USERCLASS,DOMOK,num);
  477.             return(0);
  478.         case -1:                    /* strange return code from ddextract */
  479.             netposterr(803);
  480.             break;
  481.         default:
  482.             netposterr(804);
  483.             break;
  484.     }
  485.  
  486.     return(0);
  487.  
  488. }
  489.  
  490. /**************************************************************************/
  491. /*  domto
  492. *   Handle time out for DOMAIN name lookup
  493. *   Retry as many times as recommended by config file
  494. */
  495. domto(num)
  496.     int num;
  497.     {
  498.     struct machinfo *m;
  499.  
  500.     m = Slooknum(num);
  501.     if (!m)
  502.         return(-1);
  503.  
  504.     if (m->mstat > UDPDOM + Scon.ndom) {    /* permanent timeout */
  505.         netputevent(USERCLASS,DOMFAIL,num);
  506.         return(-1);
  507.     }
  508.     else
  509.         m->mstat++;            /* one more timeout */
  510.     
  511.     if (domwait < 20)        /* exponential backoff */
  512.         domwait <<= 1;
  513.  
  514.     Snewns();                /* rotate to next nameserver */
  515.  
  516.     qinit();
  517.  
  518.     netulisten(997);                    /* pick a return port */
  519.     sendom(m->hname,Sns->hostip,num);        /* try UDP */
  520.  
  521.     Stimerset(SCLASS,UDPTO,num,domwait);    /* time out more slowly */
  522.  
  523.     return(num);
  524.     
  525. }
  526.  
  527. /*********************************************************************/
  528. /*  ddextract
  529. *   extract the ip number from a response message.
  530. *   returns the appropriate status code and if the ip number is available,
  531. *   copies it into mip
  532. */
  533. ddextract(qp,mip)
  534.     struct useek *qp;
  535.     unsigned char *mip;
  536.     {
  537.     uint16 i,j,nans,rcode;
  538.     struct rrpart *rrp;
  539.     uint8 *p,space[260];
  540.  
  541.     nans = intswap(qp->h.ancount);                /* number of answers */
  542.     rcode = DRCODE & intswap(qp->h.flags);        /* return code for this message*/
  543.     if (rcode > 0)
  544.         return(rcode);
  545.  
  546.     if (nans > 0 &&                                /* at least one answer */
  547.         (intswap(qp->h.flags) & DQR)) {            /* response flag is set */
  548.         p = (uint8 *)qp->x;                    /* where question starts */
  549.         i = unpackdom(space,p,qp);                /* unpack question name */
  550. /*  spec defines name then  QTYPE + QCLASS = 4 bytes */
  551.         p += i+4;
  552. /*
  553. *  at this point, there may be several answers.  We will take the first
  554. *  one which has an IP number.  There may be other types of answers that
  555. *  we want to support later.
  556. */
  557.         while (nans-- > 0) {                    /* look at each answer */
  558.             i = unpackdom(space,p,qp);            /* answer name to unpack */
  559. /*            n_puts(space);*/
  560.             p += i;                                /* account for string */
  561.             rrp = (struct rrpart *)p;            /* resource record here */
  562. /*
  563. *  check things which might not align on 68000 chip one byte at a time
  564. */
  565.             if (!*p && *(p+1) == DTYPEA &&         /* correct type and class */
  566.                 !*(p+2) && *(p+3) == DIN) {
  567.                 movebytes(mip,rrp->rdata,4);    /* save IP #         */
  568.                 return(0);                        /* successful return */
  569.             }
  570.             movebytes(&j,&rrp->rdlength,2);        /* 68000 alignment */
  571.             p += 10+intswap(j);                    /* length of rest of RR */
  572.         }
  573.     }
  574.  
  575.     return(-1);                        /* generic failed to parse */
  576. }
  577.  
  578.  
  579. /***********************************************************************/
  580. static int son=1;
  581.  
  582. Scwritemode(mode)
  583.     int mode;
  584.     {
  585.         son = mode;
  586.         return(0);
  587. }
  588.  
  589. /***********************************************************************/
  590. Scmode()
  591.     {
  592.     return(son);
  593. }
  594.  
  595. /***********************************************************************/
  596. static int tekon=1;
  597.  
  598. Stekmode(mode)
  599.     int mode;
  600.     {
  601.         tekon = mode;
  602.         return(0);
  603. }
  604.  
  605. /***********************************************************************/
  606. Stmode()
  607.     {
  608.     return(tekon);
  609. }
  610.  
  611. /***********************************************************************/
  612. #ifdef PC
  613. static int rcpon=1;
  614.  
  615. Srcpmode(mode)
  616.     int mode;
  617.     {
  618.         rcpon = mode;
  619.         if (rcpon)
  620.             setrshd();
  621.         else
  622.             unsetrshd();
  623.         return(0);
  624. }
  625.  
  626. /***********************************************************************/
  627. Srmode()
  628.     {
  629.     return(rcpon);
  630. }
  631. #endif
  632.  
  633. /***********************************************************************/
  634. static int ftpon=0;
  635.  
  636. Sftpmode(mode)
  637.     int mode;
  638.     {
  639.         if (ftpon && mode)
  640.             return(-1);
  641.  
  642.         ftpon = mode;
  643.         if (ftpon)
  644.             setftp();
  645.         else
  646.             unsetftp();
  647.         return(0);
  648. }
  649.  
  650. /***********************************************************************/
  651. Sfmode()
  652.     {
  653.     return(ftpon);
  654. }
  655.  
  656. /***********************************************************************/
  657. /*  Snewcap
  658. *   set a new capture file name
  659. */
  660. Snewcap(s)
  661.     char *s;
  662.     {
  663.     if (NULL == (Scon.capture = malloc(strlen(s)+1)))
  664.         return(1);
  665.     strcpy(Scon.capture,s);
  666.     return(0);
  667. }
  668.  
  669. /***********************************************************************/
  670. /*  Snewps
  671. *   set a new ps file name
  672. */
  673. Snewpsfile(s)
  674.     char *s;
  675.     {
  676.     if (NULL == (Scon.psfile = malloc(strlen(s)+1)))
  677.         return(1);
  678.     strcpy(Scon.psfile,s);
  679.     return(0);
  680. }
  681.  
  682. /***********************************************************************/
  683. /*  Snewhpfile
  684. *   set a new HPGL file name
  685. */
  686. Snewhpfile(s)
  687.     char *s;
  688.     {
  689.     if (NULL == (Scon.hpfile = malloc(strlen(s)+1)))
  690.         return(1);
  691.     strcpy(Scon.hpfile,s);
  692.     return(0);
  693. }
  694.  
  695. /***********************************************************************/
  696. /*  Snewtekfile
  697. *   set a new tek file name
  698. */
  699. Snewtekfile(s)
  700.     char *s;
  701.     {
  702.     if (NULL == (Scon.tekfile = malloc(strlen(s)+1)))
  703.         return(1);
  704.     strcpy(Scon.tekfile,s);
  705.     return(0);
  706. }
  707.  
  708. /***********************************************************************/
  709. /*  Sopencap
  710. *   returns a file handle to an open capture file
  711. *   Uses the locally stored capture file name.
  712. */
  713. FILE *
  714. Sopencap()
  715.     {
  716.     FILE *retfp;
  717.  
  718.     if (NULL == (retfp = fopen(Scon.capture,"ab"))) 
  719.         return(NULL);
  720.  
  721.     fseek(retfp,0L,2);        /* seek to end */
  722.  
  723.     return(retfp);
  724. }
  725.  
  726. /**************************************************************************/
  727. /*  Stask
  728. *   A higher level version of netsleep
  729. *
  730. *   This manages the timer queue
  731. */
  732.  
  733. static int32 recent=0L;
  734.  
  735. Stask()
  736.     {
  737.     long t;
  738.     int i;
  739.  
  740. #ifndef APPLE_DRIVERS
  741.     netsleep(0);
  742. #endif APPLE_DRIVERS
  743.  
  744. /*
  745. *  Check the timer queue to see if something should be posted
  746. *  First check for timer wraparound
  747. */
  748.     t = time(NULL);
  749. #ifdef PC
  750.     if (t < recent) {
  751.         i = Stfirst;
  752.         while (i >= 0) {
  753.             Stq[i].when -= WRAPTIME;
  754.             i = Stq[i].next;
  755.         }
  756.     }
  757. #endif
  758.     recent = t;                            /* save most recent time */
  759.  
  760.     while (Stfirst >= 0 && t > Stq[Stfirst].when) {        
  761.                                 /* Q is not empty and timer is going off */
  762.         i = Stfirst;
  763.         netputevent(Stq[i].eclass,Stq[i].event,Stq[i].idata);
  764.         Stfirst = Stq[Stfirst].next;    /* remove from q */
  765.         Stq[i].next = Stfree;
  766.         Stfree = i;                        /* add to free list */
  767.     }
  768.  
  769.  
  770. }
  771.  
  772. /**************************************************************************/
  773. /*  Stimerset
  774. *  Sets an asynchronous timer which is checked in Stask()
  775. *  usage:
  776. *  Time is in seconds
  777. *  Stimerset(class,event,dat,time)
  778. *    int class,event,dat,time;
  779. *    class,event,dat is the event which should be posted at the specified
  780. *    time.  Accuracy is dependent on how often Stask is called.
  781. */
  782.  
  783. Stimerset(class,event,dat,howlong)
  784.     int class,event,dat,howlong;
  785.     {
  786.     int i,j,jlast,retval;
  787.     int32 gooff;
  788.  
  789.     retval = 0;
  790.     gooff = time(NULL) + howlong;
  791.  
  792.     if (Stfree < 0) {                /* queue is full, post first event */
  793.         Stfree = Stfirst;
  794.         Stfirst = Stq[Stfirst].next;
  795.         Stq[Stfree].next = -1;
  796.         netputevent(Stq[Stfree].eclass,Stq[Stfree].event,Stq[Stfree].idata);
  797.         retval = -1;
  798.     }
  799.  
  800.     Stq[Stfree].idata = dat;                /* event to occur at that time */
  801.     Stq[Stfree].event = event;
  802.     Stq[Stfree].eclass = class;
  803.     Stq[Stfree].when = gooff;
  804.     i = Stfree;                            /* remove from free list */
  805.     Stfree = Stq[i].next;
  806.  
  807.     if (Stfirst < 0) {                    /* if no queue yet */
  808.         Stfirst = i;
  809.         Stq[i].next = -1;                /* anchor active q */
  810.     }
  811.  
  812.     else if (gooff < Stq[Stfirst].when) {    /* goes first on list */
  813.         Stq[i].next = Stfirst;                /* at beginning of list */
  814.         Stfirst = i;
  815.     }
  816.  
  817.     else {                                    /* goes in middle */
  818.  
  819.         j = jlast = Stfirst;                /* search q from beginning */
  820.  
  821.         while (gooff >= Stq[j].when && j >= 0) {
  822.             jlast = j;
  823.             j = Stq[j].next;
  824.         }
  825.         Stq[i].next = j;                    /* insert in q */
  826.         Stq[jlast].next = i;
  827.     }
  828.  
  829.     return(retval);
  830. }
  831.  
  832. /****************************************************************************/
  833. /*  Stimerunset
  834. *   Remove all such timer events from the queue
  835. *   They must match all three fields, event, class and optional data
  836. *
  837. */
  838. Stimerunset(class,event,dat)
  839.     unsigned char event,class;
  840.     int dat;
  841.     {
  842.     int i,ilast,retval;
  843.  
  844.     retval = ilast = -1;
  845.     i = Stfirst;
  846.     while (i >= 0 ) {                    /* search list */
  847.  
  848.         if (Stq[i].idata == dat &&         /* this one matches */
  849.             Stq[i].eclass == class && Stq[i].event == event) {
  850.  
  851.             retval = 0;                    /* found at least one */
  852. /*
  853. * major bug fix -- if first element matched, old code could crash
  854. */
  855.             if (i == Stfirst) {
  856.                 Stfirst = Stq[i].next;            /* first one matches */
  857.                 Stq[i].next = Stfree;            /* attach to free list */
  858.                 Stfree = i;
  859.                 i = Stfirst;
  860.                 continue;                        /* start list over */
  861.             }
  862.             else {
  863.                 Stq[ilast].next = Stq[i].next;    /* remove this entry */
  864.                 Stq[i].next = Stfree;            /* attach to free list */
  865.                 Stfree = i;
  866.                 i = ilast;
  867.             }
  868.         }
  869.  
  870.         ilast = i;
  871.         i = Stq[i].next;
  872.     }
  873.  
  874.     return(retval);
  875. }
  876.  
  877. /****************************************************************************/
  878. /*  Scheckpass
  879. *   Check the password file for the user,password combination
  880. *   Returns valid or invalid
  881. */
  882. Scheckpass(us,ps)
  883.     char *us,*ps;
  884.     {
  885.     char buf[81],*p;
  886.     FILE *fp;
  887.     int i;
  888.     
  889.     if (NULL == (fp = fopen(Scon.pass,"r"))) {
  890.     
  891. #ifdef MAC
  892. /*
  893. *  failed open, so try to find file in the system folder.
  894. */
  895.  
  896.         sysdir();                            /* change to system folder */
  897.         fp = fopen(Scon.pass,"r");
  898.         
  899.         setmydir();                            /* reset back to default dir */
  900.         
  901.         if (NULL == fp)                        /* still didn't work? */
  902. #endif
  903.             return(0);
  904.     }
  905.  
  906.     while (NULL != fgets(buf,80,fp)) {
  907.         p = strchr(buf,'\n');
  908.         *p = '\0';                            /* remove \n */
  909.  
  910.         p = strchr(buf,':');                /* find delimiter */
  911.         *p++ = '\0';
  912.         if (!strcmp(buf,us) &&            /* found user */
  913.             Scompass(ps,p)) {            /* does password check ?*/
  914.             fclose(fp);
  915.             return(1);
  916.         }
  917.     }
  918.  
  919.     fclose(fp);
  920.     return(0);
  921. }
  922.  
  923. /****************************************************************************/
  924. /* Sneedpass
  925. *  For other routines to call and find out if a password is required
  926. */
  927. Sneedpass()
  928.     {
  929.     if (Scon.pass == NULL)
  930.         return(0);
  931.  
  932.     return(1);
  933. }
  934.  
  935. /****************************************************************************/
  936. /* Scompass
  937. *  compute and check the encrypted password
  938. */
  939. Scompass(ps,en)
  940.     char *ps,*en;
  941.     {
  942.     int ck;
  943.     char *p,c;
  944.  
  945.     ck = 0;
  946.     p = ps;
  947.     while (*p)                /* checksum the string */
  948.         ck += *p++;
  949.  
  950.     c = ck;
  951.  
  952.     while (*en) {
  953.         if ((((*ps ^ c) | 32) & 127) != *en)    /* XOR with checksum */
  954.             return(0);
  955.         if (*ps)
  956.             ps++;
  957.         else
  958.             c++;            /* increment checksum to hide length */
  959.         en++;
  960.     }
  961.  
  962.     return(1);
  963. }
  964.  
  965. /****************************************************************************/
  966. /*  Sgetevent
  967. *   gets events from the network and filters those for session related
  968. *   activity.  Returns any other events to the caller.
  969. */
  970. Sgetevent(class,what,datp)
  971.     int class,*what,*datp;
  972.     {
  973.     int retval;
  974.  
  975.     if (retval = netgetevent(SCLASS,what,datp)) {    /* session event */
  976.         switch (retval) {
  977.             case FTPACT:
  978.                 ftpd(0,*datp);
  979.                 break;
  980. #ifdef PC
  981.             case RCPACT:                /* give CPU to rsh for rcp */
  982.                 rshd(0);
  983.                 break;
  984. #endif
  985. #ifdef MAC
  986.             case CLOSEDONE:                /* Used in the drivers */
  987.                 netclose( *datp);
  988.                 break;
  989.             case CLOSEDONE+1:                /* Used in the drivers */
  990.                 netclose( *datp);
  991.                 break;
  992. #endif MAC
  993.             case UDPTO:                    /* name server not responding */
  994.                 domto(*datp);
  995.                 break;
  996.             case RETRYCON:
  997.                 if (0 < netopen2(*datp))     /* connection open yet? */
  998.                     Stimerset(SCLASS,RETRYCON,*datp,4);  /* 4 is a kludge */
  999.                 break;
  1000.  
  1001.             default:
  1002.                 break;
  1003.         }
  1004.     }
  1005.  
  1006.     Stask();                        /* allow net and timers to take place */
  1007.  
  1008.     if (!(retval = netgetevent(class,what,datp)))
  1009.         return(0);
  1010.         
  1011.     if (retval == CONOPEN) 
  1012.         Stimerunset(CONCLASS,CONFAIL,*datp);   /* kill this timer */
  1013.  
  1014.     if ((*datp == 997) && (retval == UDPDATA)) {
  1015.         udpdom();
  1016.     }
  1017.     else if ((*what == CONCLASS) && (Sptypes[*datp] >= 0)) {
  1018.                                         /* might be for session layer */
  1019.         switch (Sptypes[*datp]) {
  1020.             case PFTP:
  1021.                 rftpd(retval);
  1022.                 break;
  1023.             case PDATA:
  1024.                 ftpd(retval,*datp);
  1025.                 break;
  1026.             case UDATA:                        /* BYU mod */
  1027.                 userftpd(retval,*datp);        /* BYU mod */
  1028.                 break;                        /* BYU mod */
  1029. #ifdef PC
  1030.             case PRCP:
  1031.                 rshd(retval);
  1032.                 break;
  1033. #endif
  1034.             default:
  1035.                 break;
  1036.         }
  1037.     }
  1038.     else
  1039.         return(retval);                /* let higher layer have it */
  1040.  
  1041.     return(0);
  1042. }
  1043.  
  1044.