summaryrefslogtreecommitdiffstats
path: root/innbbsd/rfc931.c
blob: 33ee49fd783938c1479ba5af129b83bbfb6cc569 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * rfc931_user() speaks a common subset of the RFC 931, AUTH, TAP and IDENT
 * protocols. It consults an RFC 931 etc. compatible daemon on the client
 * host to look up the remote user name. The information should not be used
 * for authentication purposes.
 * 
 * Diagnostics are reported through syslog(3).
 * 
 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
 * 
 * Inspired by the authutil package (comp.sources.unix volume 22) by Dan
 * Bernstein (brnstnd@kramden.acf.nyu.edu).
 */

#ifndef lint
static char     sccsid[] = "@(#) rfc931.c 1.4 93/03/07 22:47:52";
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <signal.h>
#include "osdep.h"

/* #include "log_tcp.h" */

#define RFC931_PORT 113 /* Semi-well-known port */

#ifndef RFC931_TIMEOUT
#define RFC931_TIMEOUT  30  /* wait for at most 30 seconds */
#endif

extern char    *strchr();
extern char    *inet_ntoa();

static jmp_buf  timebuf;

/* timeout - handle timeouts */

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

/* rfc931_name - return remote user name */

char           *
my_rfc931_name(herefd, there)
    int             herefd;
    struct sockaddr_in *there;  /* remote link information */
{
    struct sockaddr_in here;    /* local link information */
    struct sockaddr_in sin; /* for talking to RFC931 daemon */
    int             length;
    int             s;
    unsigned        remote;
    unsigned        local;
    static char     user[256];  /* XXX */
    char            buffer[512];/* YYY */
    FILE           *fp;
    char           *cp;
    char           *result = "unknown";

    /* Find out local address and port number of stdin. */

    length = sizeof(here);
    if (getsockname(herefd, (struct sockaddr *) & here, &length) == -1) {
    syslog(LOG_ERR, "getsockname: %m");
    return (result);
    }
    /*
     * The socket that will be used for user name lookups should be bound to
     * the same local IP address as stdin. This will automagically happen on
     * hosts that have only one IP network address. When the local host has
     * more than one IP network address, we must do an explicit bind() call.
     */

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    return (result);

    sin = here;
    sin.sin_port = 0;
    if (bind(s, (struct sockaddr *) & sin, sizeof sin) < 0) {
    syslog(LOG_ERR, "bind: %s: %m", inet_ntoa(here.sin_addr));
    return (result);
    }
    /* Set up timer so we won't get stuck. */

    Signal(SIGALRM, timeout);
    if (setjmp(timebuf)) {
    close(s);       /* not: fclose(fp) */
    return (result);
    }
    alarm(RFC931_TIMEOUT);

    /* Connect to the RFC931 daemon. */

    sin = *there;
    sin.sin_port = htons(RFC931_PORT);
    if (connect(s, (struct sockaddr *) & sin, sizeof(sin)) == -1
    || (fp = fdopen(s, "w+")) == 0) {
    close(s);
    alarm(0);
    return (result);
    }
    /*
     * Use unbuffered I/O or we may read back our own query. setbuf() must be
     * called before doing any I/O on the stream. Thanks for the reminder,
     * Paul Kranenburg <pk@cs.few.eur.nl>!
     */

    setbuf(fp, (char *)0);

    /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */

    fprintf(fp, "%u,%u\r\n", ntohs(there->sin_port), ntohs(here.sin_port));
    fflush(fp);

    /*
     * Read response from server. Use fgets()/sscanf() instead of fscanf()
     * because there is no buffer for pushback. Thanks, Chris Turbeville
     * <turbo@cse.uta.edu>.
     */

    if (fgets(buffer, sizeof(buffer), fp) != 0
    && ferror(fp) == 0 && feof(fp) == 0
    && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
          &remote, &local, user) == 3
    && ntohs(there->sin_port) == remote
    && ntohs(here.sin_port) == local) {
    /* Strip trailing carriage return. */

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