source: trunk/third/tcp_wrappers/rfc931.c @ 11717

Revision 11717, 4.3 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r11716, which included commits to RCS files with non-trunk default branches.
Line 
1 /*
2  * rfc931() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and RFC
3  * 1413 protocols. It 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
13static char sccsid[] = "@(#) rfc931.c 1.10 95/01/02 16:11:34";
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#include <string.h>
26
27/* Local stuff. */
28
29#include "tcpd.h"
30
31#define RFC931_PORT     113             /* Semi-well-known port */
32#define ANY_PORT        0               /* Any old port will do */
33
34int     rfc931_timeout = RFC931_TIMEOUT;/* Global so it can be changed */
35
36static jmp_buf timebuf;
37
38/* fsocket - open stdio stream on top of socket */
39
40static FILE *fsocket(domain, type, protocol)
41int     domain;
42int     type;
43int     protocol;
44{
45    int     s;
46    FILE   *fp;
47
48    if ((s = socket(domain, type, protocol)) < 0) {
49        tcpd_warn("socket: %m");
50        return (0);
51    } else {
52        if ((fp = fdopen(s, "r+")) == 0) {
53            tcpd_warn("fdopen: %m");
54            close(s);
55        }
56        return (fp);
57    }
58}
59
60/* timeout - handle timeouts */
61
62static void timeout(sig)
63int     sig;
64{
65    longjmp(timebuf, sig);
66}
67
68/* rfc931 - return remote user name, given socket structures */
69
70void    rfc931(rmt_sin, our_sin, dest)
71struct sockaddr_in *rmt_sin;
72struct sockaddr_in *our_sin;
73char   *dest;
74{
75    unsigned rmt_port;
76    unsigned our_port;
77    struct sockaddr_in rmt_query_sin;
78    struct sockaddr_in our_query_sin;
79    char    user[256];                  /* XXX */
80    char    buffer[512];                /* XXX */
81    char   *cp;
82    char   *result = unknown;
83    FILE   *fp;
84
85    /*
86     * Use one unbuffered stdio stream for writing to and for reading from
87     * the RFC931 etc. server. This is done because of a bug in the SunOS
88     * 4.1.x stdio library. The bug may live in other stdio implementations,
89     * too. When we use a single, buffered, bidirectional stdio stream ("r+"
90     * or "w+" mode) we read our own output. Such behaviour would make sense
91     * with resources that support random-access operations, but not with
92     * sockets.
93     */
94
95    if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) {
96        setbuf(fp, (char *) 0);
97
98        /*
99         * Set up a timer so we won't get stuck while waiting for the server.
100         */
101
102        if (setjmp(timebuf) == 0) {
103            signal(SIGALRM, timeout);
104            alarm(rfc931_timeout);
105
106            /*
107             * Bind the local and remote ends of the query socket to the same
108             * IP addresses as the connection under investigation. We go
109             * through all this trouble because the local or remote system
110             * might have more than one network address. The RFC931 etc.
111             * client sends only port numbers; the server takes the IP
112             * addresses from the query socket.
113             */
114
115            our_query_sin = *our_sin;
116            our_query_sin.sin_port = htons(ANY_PORT);
117            rmt_query_sin = *rmt_sin;
118            rmt_query_sin.sin_port = htons(RFC931_PORT);
119
120            if (bind(fileno(fp), (struct sockaddr *) & our_query_sin,
121                     sizeof(our_query_sin)) >= 0 &&
122                connect(fileno(fp), (struct sockaddr *) & rmt_query_sin,
123                        sizeof(rmt_query_sin)) >= 0) {
124
125                /*
126                 * Send query to server. Neglect the risk that a 13-byte
127                 * write would have to be fragmented by the local system and
128                 * cause trouble with buggy System V stdio libraries.
129                 */
130
131                fprintf(fp, "%u,%u\r\n",
132                        ntohs(rmt_sin->sin_port),
133                        ntohs(our_sin->sin_port));
134                fflush(fp);
135
136                /*
137                 * Read response from server. Use fgets()/sscanf() so we can
138                 * work around System V stdio libraries that incorrectly
139                 * assume EOF when a read from a socket returns less than
140                 * requested.
141                 */
142
143                if (fgets(buffer, sizeof(buffer), fp) != 0
144                    && ferror(fp) == 0 && feof(fp) == 0
145                    && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
146                              &rmt_port, &our_port, user) == 3
147                    && ntohs(rmt_sin->sin_port) == rmt_port
148                    && ntohs(our_sin->sin_port) == our_port) {
149
150                    /*
151                     * Strip trailing carriage return. It is part of the
152                     * protocol, not part of the data.
153                     */
154
155                    if (cp = strchr(user, '\r'))
156                        *cp = 0;
157                    result = user;
158                }
159            }
160            alarm(0);
161        }
162        fclose(fp);
163    }
164    STRN_CPY(dest, result, STRING_LENGTH);
165}
Note: See TracBrowser for help on using the repository browser.