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