xref: /minix3/lib/libwrap/rfc931.c (revision f1fab66e7dda396e0a899dafaddb9c3ac4edfcfe)
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