1 /* $NetBSD: rfc931.c,v 1.7 2001/02/27 04:13:13 itojun Exp $ */
4 * rfc931() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and RFC
5 * 1413 protocols. It queries an RFC 931 etc. compatible daemon on a remote
6 * host to look up the owner of a connection. The information should not be
7 * used for authentication purposes. This routine intercepts alarm signals.
9 * Diagnostics are reported through syslog(3).
11 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
14 #include <sys/cdefs.h>
17 static char sccsid
[] = "@(#) rfc931.c 1.10 95/01/02 16:11:34";
19 __RCSID("$NetBSD: rfc931.c,v 1.7 2001/02/27 04:13:13 itojun Exp $");
23 /* System libraries. */
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
40 #define RFC931_PORT 113 /* Semi-well-known port */
41 #define ANY_PORT 0 /* Any old port will do */
43 int rfc931_timeout
= RFC931_TIMEOUT
;/* Global so it can be changed */
45 static jmp_buf timebuf
;
47 static FILE *fsocket
__P((int, int, int));
48 static void timeout
__P((int));
50 /* fsocket - open stdio stream on top of socket */
52 static FILE *fsocket(domain
, type
, protocol
)
60 if ((s
= socket(domain
, type
, protocol
)) < 0) {
61 tcpd_warn("socket: %m");
64 if ((fp
= fdopen(s
, "r+")) == 0) {
65 tcpd_warn("fdopen: %m");
72 /* timeout - handle timeouts */
74 static void timeout(sig
)
77 longjmp(timebuf
, sig
);
80 /* rfc931 - return remote user name, given socket structures */
82 void rfc931(rmt_sin
, our_sin
, dest
)
83 struct sockaddr
*rmt_sin
;
84 struct sockaddr
*our_sin
;
89 struct sockaddr_storage rmt_query_sin
;
90 struct sockaddr_storage our_query_sin
;
91 char user
[256]; /* XXX */
92 char buffer
[512]; /* XXX */
94 char *result
= unknown
;
100 /* address family must be the same */
101 if (rmt_sin
->sa_family
!= our_sin
->sa_family
) {
102 strlcpy(dest
, result
, STRING_LENGTH
);
105 switch (rmt_sin
->sa_family
) {
107 salen
= sizeof(struct sockaddr_in
);
108 rmt_portp
= &(((struct sockaddr_in
*)rmt_sin
)->sin_port
);
112 salen
= sizeof(struct sockaddr_in6
);
113 rmt_portp
= &(((struct sockaddr_in6
*)rmt_sin
)->sin6_port
);
117 strlcpy(dest
, result
, STRING_LENGTH
);
120 switch (our_sin
->sa_family
) {
122 our_portp
= &(((struct sockaddr_in
*)our_sin
)->sin_port
);
126 our_portp
= &(((struct sockaddr_in6
*)our_sin
)->sin6_port
);
130 strlcpy(dest
, result
, STRING_LENGTH
);
135 (void)&result
; /* Avoid longjmp clobbering */
136 (void)&fp
; /* XXX gcc */
140 * Use one unbuffered stdio stream for writing to and for reading from
141 * the RFC931 etc. server. This is done because of a bug in the SunOS
142 * 4.1.x stdio library. The bug may live in other stdio implementations,
143 * too. When we use a single, buffered, bidirectional stdio stream ("r+"
144 * or "w+" mode) we read our own output. Such behaviour would make sense
145 * with resources that support random-access operations, but not with
149 if ((fp
= fsocket(rmt_sin
->sa_family
, SOCK_STREAM
, 0)) != 0) {
150 setbuf(fp
, (char *) 0);
153 * Set up a timer so we won't get stuck while waiting for the server.
156 if (setjmp(timebuf
) == 0) {
157 signal(SIGALRM
, timeout
);
158 alarm(rfc931_timeout
);
161 * Bind the local and remote ends of the query socket to the same
162 * IP addresses as the connection under investigation. We go
163 * through all this trouble because the local or remote system
164 * might have more than one network address. The RFC931 etc.
165 * client sends only port numbers; the server takes the IP
166 * addresses from the query socket.
169 memcpy(&our_query_sin
, our_sin
, salen
);
170 switch (our_query_sin
.ss_family
) {
172 ((struct sockaddr_in
*)&our_query_sin
)->sin_port
=
177 ((struct sockaddr_in6
*)&our_query_sin
)->sin6_port
=
182 memcpy(&rmt_query_sin
, rmt_sin
, salen
);
183 switch (rmt_query_sin
.ss_family
) {
185 ((struct sockaddr_in
*)&rmt_query_sin
)->sin_port
=
190 ((struct sockaddr_in6
*)&rmt_query_sin
)->sin6_port
=
196 if (bind(fileno(fp
), (struct sockaddr
*) & our_query_sin
,
198 connect(fileno(fp
), (struct sockaddr
*) & rmt_query_sin
,
202 * Send query to server. Neglect the risk that a 13-byte
203 * write would have to be fragmented by the local system and
204 * cause trouble with buggy System V stdio libraries.
207 fprintf(fp
, "%u,%u\r\n",
213 * Read response from server. Use fgets()/sscanf() so we can
214 * work around System V stdio libraries that incorrectly
215 * assume EOF when a read from a socket returns less than
219 if (fgets(buffer
, sizeof(buffer
), fp
) != 0
220 && ferror(fp
) == 0 && feof(fp
) == 0
221 && sscanf(buffer
, "%u , %u : USERID :%*[^:]:%255s",
222 &rmt_port
, &our_port
, user
) == 3
223 && ntohs(*rmt_portp
) == rmt_port
224 && ntohs(*our_portp
) == our_port
) {
227 * Strip trailing carriage return. It is part of the
228 * protocol, not part of the data.
231 if ((cp
= strchr(user
, '\r')) != NULL
)
240 strlcpy(dest
, result
, STRING_LENGTH
);