1 /* $NetBSD: rfc931.c,v 1.10 2012/03/22 22:59:43 joerg 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.10 2012/03/22 22:59:43 joerg 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(int, int, int);
48 static void timeout(int) __dead
;
50 /* fsocket - open stdio stream on top of socket */
53 fsocket(int domain
, int type
, int protocol
)
58 if ((s
= socket(domain
, type
, protocol
)) < 0) {
59 tcpd_warn("socket: %m");
62 if ((fp
= fdopen(s
, "r+")) == 0) {
63 tcpd_warn("fdopen: %m");
70 /* timeout - handle timeouts */
75 longjmp(timebuf
, sig
);
78 /* rfc931 - return remote user name, given socket structures */
81 rfc931(struct sockaddr
*rmt_sin
, struct sockaddr
*our_sin
, char *dest
)
85 struct sockaddr_storage rmt_query_sin
;
86 struct sockaddr_storage our_query_sin
;
87 char user
[256]; /* XXX */
88 char buffer
[512]; /* XXX */
90 char *result
= unknown
;
93 u_short
* volatile rmt_portp
;
94 u_short
* volatile our_portp
;
96 /* address family must be the same */
97 if (rmt_sin
->sa_family
!= our_sin
->sa_family
) {
98 strlcpy(dest
, result
, STRING_LENGTH
);
101 switch (rmt_sin
->sa_family
) {
103 salen
= sizeof(struct sockaddr_in
);
104 rmt_portp
= &(((struct sockaddr_in
*)rmt_sin
)->sin_port
);
108 salen
= sizeof(struct sockaddr_in6
);
109 rmt_portp
= &(((struct sockaddr_in6
*)rmt_sin
)->sin6_port
);
113 strlcpy(dest
, result
, STRING_LENGTH
);
116 switch (our_sin
->sa_family
) {
118 our_portp
= &(((struct sockaddr_in
*)our_sin
)->sin_port
);
122 our_portp
= &(((struct sockaddr_in6
*)our_sin
)->sin6_port
);
126 strlcpy(dest
, result
, STRING_LENGTH
);
131 (void)&result
; /* Avoid longjmp clobbering */
132 (void)&fp
; /* XXX gcc */
136 * Use one unbuffered stdio stream for writing to and for reading from
137 * the RFC931 etc. server. This is done because of a bug in the SunOS
138 * 4.1.x stdio library. The bug may live in other stdio implementations,
139 * too. When we use a single, buffered, bidirectional stdio stream ("r+"
140 * or "w+" mode) we read our own output. Such behaviour would make sense
141 * with resources that support random-access operations, but not with
145 if ((fp
= fsocket(rmt_sin
->sa_family
, SOCK_STREAM
, 0)) != 0) {
146 setbuf(fp
, (char *) 0);
149 * Set up a timer so we won't get stuck while waiting for the server.
152 if (setjmp(timebuf
) == 0) {
153 signal(SIGALRM
, timeout
);
154 alarm(rfc931_timeout
);
157 * Bind the local and remote ends of the query socket to the same
158 * IP addresses as the connection under investigation. We go
159 * through all this trouble because the local or remote system
160 * might have more than one network address. The RFC931 etc.
161 * client sends only port numbers; the server takes the IP
162 * addresses from the query socket.
165 memcpy(&our_query_sin
, our_sin
, salen
);
166 switch (our_query_sin
.ss_family
) {
168 ((struct sockaddr_in
*)&our_query_sin
)->sin_port
=
173 ((struct sockaddr_in6
*)&our_query_sin
)->sin6_port
=
178 memcpy(&rmt_query_sin
, rmt_sin
, salen
);
179 switch (rmt_query_sin
.ss_family
) {
181 ((struct sockaddr_in
*)&rmt_query_sin
)->sin_port
=
186 ((struct sockaddr_in6
*)&rmt_query_sin
)->sin6_port
=
192 if (bind(fileno(fp
), (struct sockaddr
*) & our_query_sin
,
194 connect(fileno(fp
), (struct sockaddr
*) & rmt_query_sin
,
198 * Send query to server. Neglect the risk that a 13-byte
199 * write would have to be fragmented by the local system and
200 * cause trouble with buggy System V stdio libraries.
203 fprintf(fp
, "%u,%u\r\n",
209 * Read response from server. Use fgets()/sscanf() so we can
210 * work around System V stdio libraries that incorrectly
211 * assume EOF when a read from a socket returns less than
215 if (fgets(buffer
, sizeof(buffer
), fp
) != 0
216 && ferror(fp
) == 0 && feof(fp
) == 0
217 && sscanf(buffer
, "%u , %u : USERID :%*[^:]:%255s",
218 &rmt_port
, &our_port
, user
) == 3
219 && ntohs(*rmt_portp
) == rmt_port
220 && ntohs(*our_portp
) == our_port
) {
223 * Strip trailing carriage return. It is part of the
224 * protocol, not part of the data.
227 if ((cp
= strchr(user
, '\r')) != NULL
)
236 strlcpy(dest
, result
, STRING_LENGTH
);