home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: SysTools / SysTools.zip / pmcron03.zip / tcpip.c < prev    next >
C/C++ Source or Header  |  1996-05-09  |  19KB  |  407 lines

  1. /* Copyright (c) 1995 Florian Große-Coosmann, RCS section at the eof         */
  2. /* This module includes all functions exclusively related to the TCP/IP      */
  3. /* handling.                                                                 */
  4. #define INCL_NOCOMMON
  5. #define INCL_DOSSEMAPHORES
  6. #include <os2.h>
  7.  
  8. #include <stdio.h>
  9. #include <errno.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <ctype.h>
  13. #include <fcntl.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <sys/socket.h>
  17. #include <sys/ioctl.h>
  18. #include <sys/param.h>
  19. #include <netinet/in.h>
  20. #include <arpa/inet.h>
  21. #include <netdb.h>
  22. #include <share.h>
  23. #include <io.h>
  24. #include "server.h"
  25.  
  26. #ifndef MAXHOSTNAMELEN
  27. #  define MAXHOSTNAMELEN (256+64)       /* be save!                          */
  28. #endif
  29.  
  30. typedef struct {
  31.    unsigned    entries;
  32.    u_long     *hosts;
  33. } TCPIP_ALLOW;
  34.  
  35. volatile int CommSock = -1;             /* currenty opened socket to a client*/
  36. static int MainSock = -1;               /* main communication socket         */
  37. static int NameServerProblem = 0;       /* flag used to determine problems   */
  38. static u_long IPofThisHost = INADDR_NONE; /* IP number of your adapter       */
  39. static TCPIP_ALLOW AccessList = {0,NULL}; /* current access list             */
  40.  
  41. /*****************************************************************************/
  42. /*  function name : CheckTCPIPAvail                                          */
  43. /*                                                                           */
  44. /*  description   : checks the availability of TCP/IP and sets the global    */
  45. /*                  flag. Opens the MainSock.                                */
  46. /*****************************************************************************/
  47. void CheckTCPIPAvail(void)
  48. {
  49.    struct sockaddr_in si;
  50.    int on = 1;
  51.  
  52.    TCPIPAvail = 0;                      /* TCP/IP not supported on default   */
  53.    if ((MainSock = socket(AF_INET,SOCK_STREAM,PF_UNSPEC)) < 0)
  54.       return;
  55.    if (setsockopt(MainSock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) {
  56.       close(MainSock);
  57.       return;
  58.    }
  59.    memset(&si,0,sizeof(si));
  60.    si.sin_family      = AF_INET;
  61.    si.sin_port        = htons(CRON_TCPIP_PORT);
  62.    si.sin_addr.s_addr = INADDR_ANY;
  63.    if (bind(MainSock,(struct sockaddr *) &si,sizeof(si)) < 0) {
  64.       close(MainSock);
  65.       return;
  66.    }
  67.    if (listen(MainSock,1) < 0) {        /* allow only one host to await a    */
  68.       close(MainSock);                  /* connection                        */
  69.       return;
  70.    }
  71.    IPofThisHost = gethostid();
  72.    TCPIPAvail = 1;                      /* TCP/IP supported                  */
  73. }
  74.  
  75. /*****************************************************************************/
  76. /*  function name : ResolveIPNumberFromHost                                  */
  77. /*                                                                           */
  78. /*  arguments     : hostname, buffer to receive the corresponding IP         */
  79. /*                  number of the host                                       */
  80. /*                                                                           */
  81. /*  return value  : 0 on success, -1 on error, 1 in case of problems with    */
  82. /*                  the name server                                          */
  83. /*                                                                           */
  84. /*  description   : tries to get the IP number of the host given in          */
  85. /*                  hostname. Sets the buffer of the IP number on success.   */
  86. /*****************************************************************************/
  87. static int ResolveIPNumberFromHost(const char *hostname,u_long *ipno)
  88. {
  89.    u_long retval;
  90.    struct hostent *host;
  91.    extern int h_errno;                  /* currently not found in any include*/
  92.                                         /* file                              */
  93.  
  94.    if ((retval = inet_addr(hostname)) != INADDR_NONE) {
  95.       *ipno = retval;
  96.       return(0);
  97.    }
  98.                                         /* hostname is not a number sequence?*/
  99.    host = gethostbyname(hostname);
  100.    if ((host != NULL) && (host->h_length >= sizeof(u_long))) {
  101.       *ipno = *((u_long*) host->h_addr_list[0]);
  102.       return(0);
  103.    }
  104.                                         /* maybe, the nameserver or the      */
  105.                                         /* nameservice is down. In this case */
  106.                                         /*we return a 1 to show an acceptable*/
  107.                                         /* error                             */
  108.    if (h_errno != HOST_NOT_FOUND)
  109.       return(1);
  110.    return(-1);
  111. }
  112.  
  113. /*****************************************************************************/
  114. /*  function name : ResolveHostFromIP                                        */
  115. /*                                                                           */
  116. /*  arguments     : IP number of the host, buffer to hold the human          */
  117. /*                  readable host name.                                      */
  118. /*                                                                           */
  119. /*  description   : fills the buffer with the host name of the given IP      */
  120. /*                  address.                                                 */
  121. /*                                                                           */
  122. /*  note          : the buffer should be large enough (MAXHOSTNAMELEN)       */
  123. /*****************************************************************************/
  124. static void ResolveHostFromIP(u_long ipno,char *fullname)
  125. {
  126.    char *p;
  127.    struct in_addr ia;
  128.    struct hostent *host;
  129.  
  130.    host = gethostbyaddr((char *) &ipno,sizeof(u_long),AF_INET);
  131.    if (host != NULL)
  132.       strcpy(fullname,host->h_name);
  133.    else {
  134.       ia.s_addr = ipno;
  135.       if ((p = inet_ntoa(ia)) != NULL)
  136.          strcpy(fullname,p);
  137.       else
  138.          strcpy(fullname,Get(IDS_UnknownHost));
  139.    }
  140. }
  141.  
  142. /*****************************************************************************/
  143. /*  function name : InsertIPEntry                                            */
  144. /*                                                                           */
  145. /*  arguments     : string with a new TCP/IP host, its length, head of the   */
  146. /*                  list of allowed host names.                              */
  147. /*                                                                           */
  148. /*  return value  : 0 on success, errno otherwise                            */
  149. /*                                                                           */
  150. /*  description   : duplicates and parses the string and appends it to the   */
  151. /*                  list. This function checks the validity and sets all     */
  152. /*                  necessary entry values, too.                             */
  153. /*****************************************************************************/
  154. static int InsertIPEntry(const char *s,size_t len,TCPIP_ALLOW *head)
  155. {
  156.    int err;
  157.    char c;
  158.    u_long ipno;
  159.    char ReadInBuf[MAXHOSTNAMELEN];
  160.  
  161.    while (isspace(*s) && (len > 0)) {   /* cut off leading and trailing      */
  162.       s++;                              /* whitespaces                       */
  163.       len--;
  164.    }
  165.    while (len > 0) {
  166.       if (isspace(s[len - 1]))
  167.          len--;
  168.       else
  169.          break;
  170.    }
  171.    if (len == 0)                        /* empty line?                       */
  172.       return(0);
  173.    if ((*s == '#') || (*s == ';'))      /* comment line?                     */
  174.       return(0);
  175.    if (len >= MAXHOSTNAMELEN)
  176.       return(EINVAL);
  177.  
  178.    memcpy(ReadInBuf,s,len);             /* may be valid, copy and check for  */
  179.    ReadInBuf[len] = 0;                  /* spaces, only one entry per line   */
  180.    s = ReadInBuf;                       /* is allowed                        */
  181.    while ((c = *s++) != 0)
  182.       if (isspace(c))
  183.          return(EINVAL);
  184.  
  185.    if ((err = ResolveIPNumberFromHost(ReadInBuf,&ipno)) != 0) {
  186.       if (err == 1) {
  187.          NameServerProblem = 1;
  188.          return(0);
  189.       }
  190.       return(EINVAL);
  191.    }
  192.                                         /* the ipno is valid, insert it into */
  193.                                         /* the list                          */
  194.    if (head->hosts == NULL) {           /* never allocated?                  */
  195.       if ((head->hosts = malloc(64 * sizeof(u_long))) == NULL)
  196.          return(ENOMEM);
  197.    } else if (head->entries >= 64) {    /* default list is full?             */
  198.       if ((head->hosts = realloc(head->hosts,(head->entries + 1) *
  199.                                                       sizeof(u_long))) == NULL)
  200.          return(ENOMEM);
  201.    }
  202.    head->hosts[head->entries++] = ipno;
  203.    return(0);
  204. }
  205.  
  206. /*****************************************************************************/
  207. /*  function name : ReadIPNames                                              */
  208. /*                                                                           */
  209. /*  arguments     : handle of an open file, head of the list of hosts        */
  210. /*                  which are allowed to use this cron daemon via TCP/IP.    */
  211. /*                                                                           */
  212. /*  return value  : 0 on success, errno otherwise (will be set!)             */
  213. /*                                                                           */
  214. /*  description   : reads a TCP/IP allow file and builds a new list. The     */
  215. /*                  file must be opened in O_BINARY mode.                    */
  216. /*****************************************************************************/
  217. static int ReadIPNames(int handle,TCPIP_ALLOW *head)
  218. {
  219.    char *buf;
  220.    const char *ptr;
  221.    long flen;
  222.    size_t pos,len;
  223.    int err,htype;
  224.  
  225.    ioctl(handle,FGETHTYPE,&htype);
  226.    if (htype == HT_DEV_NUL)             /* we don't have to do anything      */
  227.       return(0);                        /* while reading the "nul" device    */
  228.    if ((flen = filelength(handle)) == -1l)      /* device?                   */
  229.       return(errno);
  230.    if ((lseek(handle,0l,SEEK_SET)) == -1l)      /* device?                   */
  231.       return(errno);
  232.    if (flen == 0)                       /* empty file?                       */
  233.       return(0);
  234.    if (flen >= MAX_CRONFILESIZE)        /* potential mistake of the user?    */
  235.       return(errno = EACCES);
  236.    if ((buf = malloc((size_t) flen + 1)) == NULL)  /* read the complete file */
  237.       return(errno = ENOMEM);           /* in one operation                  */
  238.    errno = 0;
  239.    if ((long) read(handle,buf,(size_t) flen) != flen) {  /* do the operation */
  240.       if (errno == 0)
  241.          errno = EIO;
  242.       free(buf);
  243.       return(errno);
  244.    }
  245.    buf[(size_t) flen] = 0;              /* terminate the buffer              */
  246.                                         /* now we can use our fast function  */
  247.    pos = 0;
  248.    while ((ptr = ParseLine(buf,(size_t) flen,&pos,&len)) != NULL) {
  249.       if ((err = InsertIPEntry(ptr,len,head)) != 0) {
  250.          free(buf);                     /* error? free up the buffer and     */
  251.          if (head->hosts != NULL) {     /* the host list                     */
  252.             free(head->hosts);
  253.             head->hosts = NULL;
  254.          }
  255.          return(errno = err);
  256.       }
  257.    }
  258.    free(buf);
  259.    return(0);
  260. }
  261.  
  262. /*****************************************************************************/
  263. /*  function name : ReadAllow                                                */
  264. /*                                                                           */
  265. /*  arguments     : new name of the TCP/IP-Access-Allow-File                 */
  266. /*                                                                           */
  267. /*  return value  : 1 on success, 0 otherwise                                */
  268. /*                                                                           */
  269. /*  description   : reads a file of TCP/IP host names. If this is done       */
  270. /*                  sucessfully, the default list is set to the new one      */
  271. /*                  and the old one is deleted.                              */
  272. /*                                                                           */
  273. /*  note          : only "nul" and regular files are allowed.                */
  274. /*****************************************************************************/
  275. int ReadAllow(char *s)
  276. {
  277.    TCPIP_ALLOW NewHead, oldhead;
  278.    int handle,htype = HT_DEV_OTHER;
  279.  
  280.    if ((handle = sopen(s,O_BINARY | O_RDONLY | O_NOINHERIT,SH_DENYWR)) == -1)
  281.       return(0);
  282.    ioctl(handle,FGETHTYPE,&htype);
  283.    if ((htype != HT_FILE) && (htype != HT_DEV_NUL)) { /* not "nul" or regular*/
  284.       close(handle);                    /* file? We won't read "KBD$" !!!    */
  285.       return(0);
  286.    }
  287.    NameServerProblem = 0;               /* reset this flag                   */
  288.    memset(&NewHead,0,sizeof(NewHead));  /* build the new list                */
  289.    if (ReadIPNames(handle,&NewHead) != 0) {  /* error interpreting file?     */
  290.       close(handle);
  291.       return(0);
  292.    }
  293.    close(handle);
  294.  
  295.    oldhead = AccessList;
  296.    AccessList = NewHead;
  297.    if (oldhead.hosts != NULL)
  298.       free(oldhead.hosts);
  299.    if (NameServerProblem)
  300.       PMError(Get(IDS_NameServerProblem),(HWND) 0);
  301.    return(1);
  302. }
  303.  
  304. /*****************************************************************************/
  305. /*  function name : IsHostInAccessList                                       */
  306. /*                                                                           */
  307. /*  arguments     : IP number of a host                                      */
  308. /*                                                                           */
  309. /*  return value  : 1 if the host is in the access list, 0 otherwise         */
  310. /*                                                                           */
  311. /*  description   : checks wether the IP-Number of the host is within        */
  312. /*                  the access list of TCP/IP hosts.                         */
  313. /*                                                                           */
  314. /*  note          : the localhost (127.0.0.1) and the IP number of the       */
  315. /*                  current host return 1 always                             */
  316. /*****************************************************************************/
  317. static int IsHostInAccessList(u_long ipno)
  318. {
  319.    unsigned i;
  320.    if (ipno == INADDR_LOOPBACK)
  321.       return(1);
  322.    if ((ipno == IPofThisHost) && (IPofThisHost != INADDR_NONE))
  323.       return(1);
  324.    if ((ProgramFlags & PRG_ALLOW_TCPIP) == 0)
  325.       return(0);
  326.    for (i = 0;i < AccessList.entries;i++)
  327.       if (ipno == AccessList.hosts[i])
  328.          return(1);
  329.    return(0);
  330. }
  331.  
  332. /*****************************************************************************/
  333. /*  function name : SocketThread                                             */
  334. /*                                                                           */
  335. /*  arguments     : not needed, must be void *                               */
  336. /*                                                                           */
  337. /*  description   : this is a thread function. It processes all requests     */
  338. /*                  to the already opened main socket.                       */
  339. /*                  Stops running if GlobalStop is set. The function         */
  340. /*                  requests an automatic disconnect by the cron thread      */
  341. /*                  avoiding any user to block the socket for a long time.   */
  342. /*                                                                           */
  343. /*  note          : should be called via _beginthread                        */
  344. /*****************************************************************************/
  345. void SocketThread(void *dummy)
  346. {
  347.    int size;
  348.    struct sockaddr_in partner;
  349.    char partner_name[MAXHOSTNAMELEN];
  350.    static struct linger linger = {1 /* l_onoff */, 5 /* l_linger=5 sec */ };
  351.  
  352.  
  353.    do {                                 /* while (!GlobalStop)               */
  354.       if (GlobalStop)                   /* check at mostly every place...    */
  355.          break;
  356.       size = sizeof(partner);
  357.                                         /* wait for a client                 */
  358.       CommSock = accept(MainSock,(struct sockaddr *) &partner,&size);
  359.       if (CommSock < 0) {               /* interrupted?                      */
  360.          if (GlobalStop)
  361.             break;
  362.          continue;
  363.       }
  364.       ResolveHostFromIP(partner.sin_addr.s_addr,partner_name);
  365.       if (IsHostInAccessList(partner.sin_addr.s_addr))
  366.          Message(Get(IDS_TCPIPConnection),partner_name);
  367.       else {
  368.          Message(Get(IDS_TCPIPRejected),partner_name);
  369.          close(CommSock);
  370.          CommSock = -1;
  371.          continue;
  372.       }
  373.       NewProgramStatus(IDS_StatusCommunication);
  374.       AutoCloseSocket = time(NULL) + 60;  /* let the socket close after a    */
  375.                                         /* minute                            */
  376.       DosPostEventSem(CronSem);         /* cron thread shall kill the pipe   */
  377.                                         /* after AutoDisConnect              */
  378.       ProcessRequest(&CommSock,partner_name);   /* do the work               */
  379.       if ((AutoCloseSocket != (time_t) -1l) && (!GlobalStop))
  380.          setsockopt(CommSock,SOL_SOCKET,SO_LINGER,&linger,sizeof(linger));
  381.                                         /* wait for the client to close the  */
  382.                                         /* socket. Otherwise, the client may */
  383.                                         /* loose some data send.             */
  384.       AutoCloseSocket = (time_t) -1l;   /* don't let close the socket        */
  385.       NewProgramStatus(IDS_StatusNormal);
  386.       if (GlobalStop)
  387.          break;
  388.       close(CommSock);
  389.       CommSock = -1;
  390.       DosPostEventSem(CronSem);         /* inform the cron thread that there */
  391.                                         /* is no need to close the socket    */
  392.                                         /* any longer                        */
  393.    } while (!GlobalStop);
  394. }
  395.  
  396. /* RCS depending informations
  397.  *
  398.  * $Name: Version121 $
  399.  *
  400.  * $Log: tcpip.c $
  401.  * Revision 1.1  1995/03/15 09:07:34  Florian
  402.  * Initial revision
  403.  *
  404.  *
  405.  */
  406. static char rcsid[] = "@(#)$Id: tcpip.c 1.1 1995/03/15 09:07:34 Florian Rel $";
  407.