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