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