Logo Search packages:      
Sourcecode: tcp-wrappers version File versions  Download package

rfc931.c

 /*
  * rfc931() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and RFC
  * 1413 protocols. It queries an RFC 931 etc. compatible daemon on a remote
  * host to look up the owner of a connection. The information should not be
  * used for authentication purposes. This routine intercepts alarm signals.
  * 
  * Diagnostics are reported through syslog(3).
  * 
  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  */

#ifndef lint
static char sccsid[] = "@(#) rfc931.c 1.10 95/01/02 16:11:34";
#endif

/* System libraries. */

#include <stdio.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <signal.h>
#include <string.h>

/* Local stuff. */

#include "tcpd.h"

#define     RFC931_PORT 113         /* Semi-well-known port */
#define     ANY_PORT    0           /* Any old port will do */

int     rfc931_timeout = RFC931_TIMEOUT;/* Global so it can be changed */

static jmp_buf timebuf;

/* fsocket - open stdio stream on top of socket */

static FILE *fsocket(domain, type, protocol)
int     domain;
int     type;
int     protocol;
{
    int     s;
    FILE   *fp;

    if ((s = socket(domain, type, protocol)) < 0) {
      tcpd_warn("socket: %m");
      return (0);
    } else {
      if ((fp = fdopen(s, "r+")) == 0) {
          tcpd_warn("fdopen: %m");
          close(s);
      }
      return (fp);
    }
}

/* timeout - handle timeouts */

static void timeout(sig)
int     sig;
{
    longjmp(timebuf, sig);
}

/* rfc931 - return remote user name, given socket structures */

void    rfc931(rmt_sin, our_sin, dest)
struct sockaddr_in *rmt_sin;
struct sockaddr_in *our_sin;
char   *dest;
{
    unsigned rmt_port;
    unsigned our_port;
    struct sockaddr_in rmt_query_sin;
    struct sockaddr_in our_query_sin;
    char    user[256];              /* XXX */
    char    buffer[512];            /* XXX */
    char   *cp;
    char   *result = unknown;
    FILE   *fp;

    /*
     * Use one unbuffered stdio stream for writing to and for reading from
     * the RFC931 etc. server. This is done because of a bug in the SunOS
     * 4.1.x stdio library. The bug may live in other stdio implementations,
     * too. When we use a single, buffered, bidirectional stdio stream ("r+"
     * or "w+" mode) we read our own output. Such behaviour would make sense
     * with resources that support random-access operations, but not with
     * sockets.
     */

    if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) {
      setbuf(fp, (char *) 0);

      /*
       * Set up a timer so we won't get stuck while waiting for the server.
       */

      if (setjmp(timebuf) == 0) {
          signal(SIGALRM, timeout);
          alarm(rfc931_timeout);

          /*
           * Bind the local and remote ends of the query socket to the same
           * IP addresses as the connection under investigation. We go
           * through all this trouble because the local or remote system
           * might have more than one network address. The RFC931 etc.
           * client sends only port numbers; the server takes the IP
           * addresses from the query socket.
           */

          our_query_sin = *our_sin;
          our_query_sin.sin_port = htons(ANY_PORT);
          rmt_query_sin = *rmt_sin;
          rmt_query_sin.sin_port = htons(RFC931_PORT);

          if (bind(fileno(fp), (struct sockaddr *) & our_query_sin,
                 sizeof(our_query_sin)) >= 0 &&
            connect(fileno(fp), (struct sockaddr *) & rmt_query_sin,
                  sizeof(rmt_query_sin)) >= 0) {

            /*
             * Send query to server. Neglect the risk that a 13-byte
             * write would have to be fragmented by the local system and
             * cause trouble with buggy System V stdio libraries.
             */

            fprintf(fp, "%u,%u\r\n",
                  ntohs(rmt_sin->sin_port),
                  ntohs(our_sin->sin_port));
            fflush(fp);

            /*
             * Read response from server. Use fgets()/sscanf() so we can
             * work around System V stdio libraries that incorrectly
             * assume EOF when a read from a socket returns less than
             * requested.
             */

            if (fgets(buffer, sizeof(buffer), fp) != 0
                && ferror(fp) == 0 && feof(fp) == 0
                && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
                        &rmt_port, &our_port, user) == 3
                && ntohs(rmt_sin->sin_port) == rmt_port
                && ntohs(our_sin->sin_port) == our_port) {

                /*
                 * Strip trailing carriage return. It is part of the
                 * protocol, not part of the data.
                 */

                if (cp = strchr(user, '\r'))
                  *cp = 0;
                result = user;
            }
          }
          alarm(0);
      }
      fclose(fp);
    }
    STRN_CPY(dest, result, STRING_LENGTH);
}

Generated by  Doxygen 1.6.0   Back to index