1 /* $MirOS: src/usr.sbin/httpd/src/main/rfc1413.c,v 1.3 2005/04/17 04:38:35 tg Exp $ */
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" must
29 * not be used to endorse or promote products derived from this
30 * software without prior written permission. For written
31 * permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * nor may "Apache" appear in their name, without prior written
35 * permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 *
56 * Portions of this software are based upon public domain software
57 * originally written at the National Center for Supercomputing Applications,
58 * University of Illinois, Urbana-Champaign.
59 */
60
61 /*
62 * rfc1413() speaks a common subset of the RFC 1413, AUTH, TAP and IDENT
63 * protocols. The code queries an RFC 1413 etc. compatible daemon on a remote
64 * host to look up the owner of a connection. The information should not be
65 * used for authentication purposes. This routine intercepts alarm signals.
66 *
67 * Diagnostics are reported through syslog(3).
68 *
69 * Author: Wietse Venema, Eindhoven University of Technology,
70 * The Netherlands.
71 */
72
73 /* Some small additions for Apache --- ditch the "sccsid" var if
74 * compiling with gcc (it *has* changed), include ap_config.h for the
75 * prototypes it defines on at least one system (SunlOSs) which has
76 * them missing from the standard header files, and one minor change
77 * below (extra parens around assign "if (foo = bar) ..." to shut up
78 * gcc -Wall).
79 */
80
81 /* Rewritten by David Robinson */
82
83 #include "httpd.h" /* for server_rec, conn_rec, ap_longjmp, etc. */
84 #include "http_log.h" /* for aplog_error */
85 #include "rfc1413.h"
86 #include "http_main.h" /* set_callback_and_alarm */
87 #include "sa_len.h"
88
89 /* Local stuff. */
90 /* Semi-well-known port */
91 #define RFC1413_PORT 113
92 /* maximum allowed length of userid */
93 #define RFC1413_USERLEN 512
94 /* rough limit on the amount of data we accept. */
95 #define RFC1413_MAXDATA 1000
96
97 #ifndef RFC1413_TIMEOUT
98 #define RFC1413_TIMEOUT 30
99 #endif
100 #define ANY_PORT 0 /* Any old port will do */
101 #define FROM_UNKNOWN "unknown"
102
103 int ap_rfc1413_timeout = RFC1413_TIMEOUT; /* Global so it can be changed */
104
105 #define RFC_USER_STATIC static
106 static JMP_BUF timebuf;
107
108 /* ident_timeout - handle timeouts */
ident_timeout(int sig)109 static void ident_timeout(int sig)
110 {
111 ap_longjmp(timebuf, sig);
112 }
113
114 /* bind_connect - bind both ends of a socket */
115 /* Ambarish fix this. Very broken */
get_rfc1413(int sock,const struct sockaddr * our_sin,const struct sockaddr * rmt_sin,char user[RFC1413_USERLEN+1],server_rec * srv)116 static int get_rfc1413(int sock, const struct sockaddr *our_sin,
117 const struct sockaddr *rmt_sin,
118 char user[RFC1413_USERLEN+1], server_rec *srv)
119 {
120 struct sockaddr_storage rmt_query_sin, our_query_sin;
121 unsigned int o_rmt_port, o_our_port; /* original port pair */
122 unsigned int rmt_port, our_port; /* replied port pair */
123 int i;
124 char *cp;
125 char buffer[RFC1413_MAXDATA + 1];
126 int buflen;
127
128 /*
129 * Bind the local and remote ends of the query socket to the same
130 * IP addresses as the connection under investigation. We go
131 * through all this trouble because the local or remote system
132 * might have more than one network address. The RFC1413 etc.
133 * client sends only port numbers; the server takes the IP
134 * addresses from the query socket.
135 */
136
137 #ifndef SIN6_LEN
138 memcpy(&our_query_sin, our_sin, SA_LEN(our_sin));
139 memcpy(&rmt_query_sin, rmt_sin, SA_LEN(rmt_sin));
140 #else
141 memcpy(&our_query_sin, our_sin, our_sin->sa_len);
142 memcpy(&rmt_query_sin, rmt_sin, rmt_sin->sa_len);
143 #endif
144 switch (our_sin->sa_family) {
145 case AF_INET:
146 ((struct sockaddr_in *)&our_query_sin)->sin_port = htons(ANY_PORT);
147 o_our_port = ntohs(((struct sockaddr_in *)our_sin)->sin_port);
148 ((struct sockaddr_in *)&rmt_query_sin)->sin_port = htons(RFC1413_PORT);
149 o_rmt_port = ntohs(((struct sockaddr_in *)rmt_sin)->sin_port);
150 break;
151 #ifdef INET6
152 case AF_INET6:
153 ((struct sockaddr_in6 *)&our_query_sin)->sin6_port = htons(ANY_PORT);
154 o_our_port = ntohs(((struct sockaddr_in6 *)our_sin)->sin6_port);
155 ((struct sockaddr_in6 *)&rmt_query_sin)->sin6_port = htons(RFC1413_PORT);
156 o_rmt_port = ntohs(((struct sockaddr_in6 *)rmt_sin)->sin6_port);
157 break;
158 #endif
159 default:
160 /* unsupported AF */
161 return -1;
162 }
163
164 if (bind(sock, (struct sockaddr *) &our_query_sin,
165 #ifndef SIN6_LEN
166 SA_LEN((struct sockaddr *) &our_query_sin)
167 #else
168 our_query_sin.ss_len
169 #endif
170 ) < 0) {
171 ap_log_error(APLOG_MARK, APLOG_CRIT, srv,
172 "bind: rfc1413: Error binding to local port");
173 return -1;
174 }
175
176 /*
177 * errors from connect usually imply the remote machine doesn't support
178 * the service
179 */
180 if (connect(sock, (struct sockaddr *) &rmt_query_sin,
181 #ifndef SIN6_LEN
182 SA_LEN((struct sockaddr *) &rmt_query_sin)
183 #else
184 rmt_query_sin.ss_len
185 #endif
186 ) < 0) {
187 return -1;
188 }
189
190 /* send the data */
191 buflen = snprintf(buffer, sizeof(buffer), "%u,%u\r\n", o_rmt_port,
192 o_our_port);
193
194 /* send query to server. Handle short write. */
195 i = 0;
196 while(i < (int)strlen(buffer)) {
197 int j;
198 j = write(sock, buffer+i, (strlen(buffer+i)));
199 if (j < 0 && errno != EINTR) {
200 ap_log_error(APLOG_MARK, APLOG_CRIT, srv,
201 "write: rfc1413: error sending request");
202 return -1;
203 }
204 else if (j > 0) {
205 i+=j;
206 }
207 }
208
209 /*
210 * Read response from server. - the response should be newline
211 * terminated according to rfc - make sure it doesn't stomp it's
212 * way out of the buffer.
213 */
214
215 i = 0;
216 memset(buffer, '\0', sizeof(buffer));
217 /*
218 * Note that the strchr function below checks for \012 instead of '\n'
219 * this allows it to work on both ASCII and EBCDIC machines.
220 */
221 while((cp = strchr(buffer, '\012')) == NULL && i < sizeof(buffer) - 1) {
222 int j;
223
224 j = read(sock, buffer+i, (sizeof(buffer) - 1) - i);
225 if (j < 0 && errno != EINTR) {
226 ap_log_error(APLOG_MARK, APLOG_CRIT, srv,
227 "read: rfc1413: error reading response");
228 return -1;
229 }
230 else if (j > 0) {
231 i+=j;
232 }
233 }
234
235 /* RFC1413_USERLEN = 512 */
236 if (sscanf(buffer, "%u , %u : USERID :%*[^:]:%512s", &rmt_port, &our_port,
237 user) != 3 || o_rmt_port != rmt_port || o_our_port != our_port) {
238 return -1;
239 }
240
241 /*
242 * Strip trailing carriage return. It is part of the
243 * protocol, not part of the data.
244 */
245
246 if ((cp = strchr(user, '\r')))
247 *cp = '\0';
248
249 return 0;
250 }
251
252 /* rfc1413 - return remote user name, given socket structures */
ap_rfc1413(conn_rec * conn,server_rec * srv)253 API_EXPORT(char *) ap_rfc1413(conn_rec *conn, server_rec *srv)
254 {
255 RFC_USER_STATIC char user[RFC1413_USERLEN + 1]; /* XXX */
256 RFC_USER_STATIC char *result;
257 RFC_USER_STATIC int sock;
258
259 result = FROM_UNKNOWN;
260
261 sock = ap_psocket_ex(conn->pool, conn->remote_addr.ss_family, SOCK_STREAM, IPPROTO_TCP, 1);
262 if (sock < 0) {
263 ap_log_error(APLOG_MARK, APLOG_CRIT, srv,
264 "socket: rfc1413: error creating socket");
265 conn->remote_logname = result;
266 }
267
268 /*
269 * Set up a timer so we won't get stuck while waiting for the server.
270 */
271 if (ap_setjmp(timebuf) == 0) {
272 ap_set_callback_and_alarm(ident_timeout, ap_rfc1413_timeout);
273
274 if (get_rfc1413(sock, (struct sockaddr *)&conn->local_addr,
275 (struct sockaddr *)&conn->remote_addr, user, srv) >= 0) {
276 result = user;
277 }
278 }
279 ap_set_callback_and_alarm(NULL, 0);
280 ap_pclosesocket(conn->pool, sock);
281 conn->remote_logname = result;
282
283 return conn->remote_logname;
284 }
285