home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume39 / tcp_wrappers / part03 / rfc931.c < prev    next >
C/C++ Source or Header  |  1993-09-29  |  6KB  |  228 lines

  1.  /*
  2.   * rfc931() speaks a common subset of the RFC 931, AUTH, TAP and IDENT
  3.   * protocols. The code queries an RFC 931 etc. compatible daemon on a remote
  4.   * host to look up the owner of a connection. The information should not be
  5.   * used for authentication purposes. This routine intercepts alarm signals.
  6.   * 
  7.   * Diagnostics are reported through syslog(3).
  8.   * 
  9.   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  10.   */
  11.  
  12. #ifndef lint
  13. static char sccsid[] = "@(#) rfc931.c 1.7 93/09/11 20:45:30";
  14. #endif
  15.  
  16. /* System libraries. */
  17.  
  18. #include <stdio.h>
  19. #include <syslog.h>
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <netinet/in.h>
  23. #include <setjmp.h>
  24. #include <signal.h>
  25.  
  26. extern char *strchr();
  27. extern char *inet_ntoa();
  28.  
  29. /* Local stuff. */
  30.  
  31. #include "log_tcp.h"
  32.  
  33. #define    RFC931_PORT    113        /* Semi-well-known port */
  34. #define    ANY_PORT    0        /* Any old port will do */
  35.  
  36. static jmp_buf timebuf;
  37.  
  38. typedef struct {
  39.     FILE   *ifp;
  40.     FILE   *ofp;
  41. } FILE_PAIR;
  42.  
  43. /* fdup - duplicate a stdio stream */
  44.  
  45. static FILE *fdup(stream, mode)
  46. FILE   *stream;
  47. char   *mode;
  48. {
  49.     int     fd;
  50.     FILE   *fp = 0;
  51.  
  52.     if ((fd = dup(fileno(stream))) < 0) {
  53.     syslog(LOG_ERR, "dup: %m");
  54.     } else if ((fp = fdopen(fd, mode)) == 0) {
  55.     syslog(LOG_ERR, "fdopen: %m");
  56.     close(fd);
  57.     }
  58.     return (fp);
  59. }
  60.  
  61. /* fsocket - open stdio stream on top of socket */
  62.  
  63. static FILE *fsocket(domain, type, protocol, mode)
  64. int     domain;
  65. int     type;
  66. int     protocol;
  67. char   *mode;
  68. {
  69.     int     s;
  70.     FILE   *fp = 0;
  71.  
  72.     if ((s = socket(domain, type, protocol)) < 0) {
  73.     syslog(LOG_ERR, "socket: %m");
  74.     } else if ((fp = fdopen(s, mode)) == 0) {
  75.     syslog(LOG_ERR, "fdopen: %m");
  76.     close(s);
  77.     }
  78.     return (fp);
  79. }
  80.  
  81. /* ffsocket - open stdio stream pair on top of socket */
  82.  
  83. static FILE_PAIR *ffsocket(domain, type, protocol)
  84. int     domain;
  85. int     type;
  86. int     protocol;
  87. {
  88.     static FILE_PAIR ffp;
  89.  
  90.     if ((ffp.ifp = fsocket(domain, type, protocol, "r")) != 0) {
  91.     if ((ffp.ofp = fdup(ffp.ifp, "w")) != 0)
  92.         return (&ffp);
  93.     fclose(ffp.ifp);
  94.     }
  95.     return (0);
  96. }
  97.  
  98. /* ffclose - close stdio stream pair */
  99.  
  100. static int ffclose(ffp)
  101. FILE_PAIR *ffp;
  102. {
  103.     int     ret;
  104.  
  105.     ret = fclose(ffp->ifp);
  106.     return (fclose(ffp->ofp) || ret);
  107. }
  108.  
  109. /* bind_connect - bind both ends of a socket */
  110.  
  111. int     bind_connect(s, local, remote, length)
  112. int     s;
  113. struct sockaddr *local;
  114. struct sockaddr *remote;
  115. int     length;
  116. {
  117.     if (bind(s, local, length) < 0) {
  118.     syslog(LOG_ERR, "bind: %m");
  119.     return (-1);
  120.     } else {
  121.     return (connect(s, remote, length));
  122.     }
  123. }
  124.  
  125. /* timeout - handle timeouts */
  126.  
  127. static void timeout(sig)
  128. int     sig;
  129. {
  130.     longjmp(timebuf, sig);
  131. }
  132.  
  133. /* rfc931 - return remote user name, given socket structures */
  134.  
  135. char   *rfc931(rmt_sin, our_sin)
  136. struct sockaddr_in *rmt_sin;
  137. struct sockaddr_in *our_sin;
  138. {
  139.     unsigned rmt_port;
  140.     unsigned our_port;
  141.     struct sockaddr_in rmt_query_sin;
  142.     struct sockaddr_in our_query_sin;
  143.     static char user[256];        /* XXX */
  144.     char    buffer[512];        /* XXX */
  145.     char   *cp;
  146.     char   *result = FROM_UNKNOWN;    /* XXX */
  147.     FILE_PAIR *ffp;
  148.  
  149.     /*
  150.      * Use separate stdio streams for writing to and for reading from the
  151.      * RFC931 etc. server. This is done because of a bug in the SunOS 4.1.x
  152.      * stdio library. The bug may live in other stdio implementations, too.
  153.      * When we use a single bidirectional stdio stream ("r+" or "w+" mode) we
  154.      * read our own output. Such behaviour would make sense with resources
  155.      * that support random-access operations, but not with sockets.
  156.      */
  157.  
  158.     if ((ffp = ffsocket(AF_INET, SOCK_STREAM, 0)) != 0) {
  159.  
  160.     /*
  161.      * Set up a timer so we won't get stuck while waiting for the server.
  162.      */
  163.  
  164.     if (setjmp(timebuf) == 0) {
  165.         signal(SIGALRM, timeout);
  166.         alarm(RFC931_TIMEOUT);
  167.  
  168.         /*
  169.          * Bind the local and remote ends of the query socket to the same
  170.          * IP addresses as the connection under investigation. We go
  171.          * through all this trouble because the local or remote system
  172.          * might have more than one network address. The RFC931 etc.
  173.          * client sends only port numbers; the server takes the IP
  174.          * addresses from the query socket.
  175.          */
  176.  
  177.         our_query_sin = *our_sin;
  178.         our_query_sin.sin_port = htons(ANY_PORT);
  179.         rmt_query_sin = *rmt_sin;
  180.         rmt_query_sin.sin_port = htons(RFC931_PORT);
  181.  
  182.         if (bind_connect(fileno(ffp->ifp),
  183.                  (struct sockaddr *) & our_query_sin,
  184.                  (struct sockaddr *) & rmt_query_sin,
  185.                  sizeof(our_query_sin)) >= 0) {
  186.  
  187.         /*
  188.          * Send query to server. Neglect the risk that a 13-byte
  189.          * write would have to be fragmented by the local system and
  190.          * cause trouble with buggy System V stdio libraries.
  191.          */
  192.  
  193.         fprintf(ffp->ofp, "%u,%u\r\n",
  194.             ntohs(rmt_sin->sin_port),
  195.             ntohs(our_sin->sin_port));
  196.         fflush(ffp->ofp);
  197.  
  198.         /*
  199.          * Read response from server. Use fgets()/sscanf() so we can
  200.          * work around System V stdio libraries that incorrectly
  201.          * assume EOF when a read from a socket returns less than
  202.          * requested.
  203.          */
  204.  
  205.         if (fgets(buffer, sizeof(buffer), ffp->ifp) != 0
  206.             && ferror(ffp->ifp) == 0 && feof(ffp->ifp) == 0
  207.             && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
  208.                   &rmt_port, &our_port, user) == 3
  209.             && ntohs(rmt_sin->sin_port) == rmt_port
  210.             && ntohs(our_sin->sin_port) == our_port) {
  211.  
  212.             /*
  213.              * Strip trailing carriage return. It is part of the
  214.              * protocol, not part of the data.
  215.              */
  216.  
  217.             if (cp = strchr(user, '\r'))
  218.             *cp = 0;
  219.             result = user;
  220.         }
  221.         }
  222.         alarm(0);
  223.     }
  224.     ffclose(ffp);
  225.     }
  226.     return (result);
  227. }
  228.