2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * rfc931() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and RFC
8 * 1413 protocols. It queries an RFC 931 etc. compatible daemon on a remote
9 * host to look up the owner of a connection. The information should not be
10 * used for authentication purposes. This routine intercepts alarm signals.
12 * Diagnostics are reported through syslog(3).
14 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
17 /* System libraries. */
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
34 #define RFC931_PORT 113 /* Semi-well-known port */
35 #define ANY_PORT 0 /* Any old port will do */
37 int rfc931_timeout
= RFC931_TIMEOUT
;/* Global so it can be changed */
39 static jmp_buf timebuf
;
41 /* fsocket - open stdio stream on top of socket */
43 static FILE *fsocket(domain
, type
, protocol
)
51 if ((s
= socket(domain
, type
, protocol
)) < 0) {
52 tcpd_warn("socket: %m");
55 if ((fp
= fdopen(s
, "r+")) == 0) {
56 tcpd_warn("fdopen: %m");
63 /* timeout - handle timeouts */
65 static void timeout(sig
)
68 longjmp(timebuf
, sig
);
71 /* rfc931 - return remote user name, given socket structures */
73 void rfc931(rmt_sin
, our_sin
, dest
)
74 struct sockaddr_gen
*rmt_sin
;
75 struct sockaddr_gen
*our_sin
;
80 struct sockaddr_gen rmt_query_sin
;
81 struct sockaddr_gen our_query_sin
;
82 char user
[256]; /* XXX */
83 char buffer
[512]; /* XXX */
85 char *volatile result
= unknown
;
87 volatile unsigned saved_timeout
= 0;
88 struct sigaction nact
, oact
;
91 * Use one unbuffered stdio stream for writing to and for reading from
92 * the RFC931 etc. server. This is done because of a bug in the SunOS
93 * 4.1.x stdio library. The bug may live in other stdio implementations,
94 * too. When we use a single, buffered, bidirectional stdio stream ("r+"
95 * or "w+" mode) we read our own output. Such behaviour would make sense
96 * with resources that support random-access operations, but not with
100 if ((fp
= fsocket(SGFAM(rmt_sin
), SOCK_STREAM
, 0)) != 0) {
104 * Set up a timer so we won't get stuck while waiting for the server.
107 if (setjmp(timebuf
) == 0) {
109 * save the pending time in case the caller has armed an alarm.
112 saved_timeout
= alarm(0);
115 * It's guaranteed to enter this 'if' condition on the direct
116 * invocation of setjmp and hence no additional checks while
117 * restoring the signal handler.
118 * Now, get the old handler and set the new one
120 nact
.sa_handler
= timeout
;
122 (void) sigemptyset(&nact
.sa_mask
);
123 (void) sigaction(SIGALRM
, &nact
, &oact
);
124 alarm(rfc931_timeout
);
127 * Bind the local and remote ends of the query socket to the same
128 * IP addresses as the connection under investigation. We go
129 * through all this trouble because the local or remote system
130 * might have more than one network address. The RFC931 etc.
131 * client sends only port numbers; the server takes the IP
132 * addresses from the query socket.
135 our_query_sin
= *our_sin
;
136 SGPORT(&our_query_sin
) = htons(ANY_PORT
);
137 rmt_query_sin
= *rmt_sin
;
138 SGPORT(&rmt_query_sin
) = htons(RFC931_PORT
);
140 if (bind(fileno(fp
), (struct sockaddr
*) &our_query_sin
,
141 SGSOCKADDRSZ(&our_query_sin
)) >= 0 &&
142 connect(fileno(fp
), (struct sockaddr
*) &rmt_query_sin
,
143 SGSOCKADDRSZ(&rmt_query_sin
)) >= 0) {
146 * Send query to server. Neglect the risk that a 13-byte
147 * write would have to be fragmented by the local system and
148 * cause trouble with buggy System V stdio libraries.
151 fprintf(fp
, "%u,%u\r\n",
152 ntohs(SGPORT(rmt_sin
)),
153 ntohs(SGPORT(our_sin
)));
157 * Read response from server. Use fgets()/sscanf() so we can
158 * work around System V stdio libraries that incorrectly
159 * assume EOF when a read from a socket returns less than
163 if (fgets(buffer
, sizeof(buffer
), fp
) != 0
164 && ferror(fp
) == 0 && feof(fp
) == 0
165 && sscanf(buffer
, "%u , %u : USERID :%*[^:]:%255s",
166 &rmt_port
, &our_port
, user
) == 3
167 && ntohs(SGPORT(rmt_sin
)) == rmt_port
168 && ntohs(SGPORT(our_sin
)) == our_port
) {
171 * Strip trailing carriage return. It is part of the
172 * protocol, not part of the data.
175 if (cp
= strchr(user
, '\r'))
182 /* Restore the old handler */
183 (void) sigaction(SIGALRM
, &oact
, NULL
);
184 if (saved_timeout
> 0)
185 alarm(saved_timeout
);
188 STRN_CPY(dest
, result
, STRING_LENGTH
);