xref: /onnv-gate/usr/src/cmd/tcpd/socket.c.org (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * This module determines the type of socket (datagram, stream), the client
3*0Sstevel@tonic-gate  * socket address and port, the server socket address and port. In addition,
4*0Sstevel@tonic-gate  * it provides methods to map a transport address to a printable host name
5*0Sstevel@tonic-gate  * or address. Socket address information results are in static memory.
6*0Sstevel@tonic-gate  *
7*0Sstevel@tonic-gate  * The result from the hostname lookup method is STRING_PARANOID when a host
8*0Sstevel@tonic-gate  * pretends to have someone elses name, or when a host name is available but
9*0Sstevel@tonic-gate  * could not be verified.
10*0Sstevel@tonic-gate  *
11*0Sstevel@tonic-gate  * When lookup or conversion fails the result is set to STRING_UNKNOWN.
12*0Sstevel@tonic-gate  *
13*0Sstevel@tonic-gate  * Diagnostics are reported through syslog(3).
14*0Sstevel@tonic-gate  *
15*0Sstevel@tonic-gate  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
16*0Sstevel@tonic-gate  */
17*0Sstevel@tonic-gate
18*0Sstevel@tonic-gate#ifndef lint
19*0Sstevel@tonic-gatestatic char sccsid[] = "@(#) socket.c 1.15 97/03/21 19:27:24";
20*0Sstevel@tonic-gate#endif
21*0Sstevel@tonic-gate
22*0Sstevel@tonic-gate/* System libraries. */
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gate#include <sys/types.h>
25*0Sstevel@tonic-gate#include <sys/param.h>
26*0Sstevel@tonic-gate#include <sys/socket.h>
27*0Sstevel@tonic-gate#include <netinet/in.h>
28*0Sstevel@tonic-gate#include <netdb.h>
29*0Sstevel@tonic-gate#include <stdio.h>
30*0Sstevel@tonic-gate#include <syslog.h>
31*0Sstevel@tonic-gate#include <string.h>
32*0Sstevel@tonic-gate
33*0Sstevel@tonic-gateextern char *inet_ntoa();
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gate/* Local stuff. */
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate#include "tcpd.h"
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gate/* Forward declarations. */
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gatestatic void sock_sink();
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gate#ifdef APPEND_DOT
44*0Sstevel@tonic-gate
45*0Sstevel@tonic-gate /*
46*0Sstevel@tonic-gate  * Speed up DNS lookups by terminating the host name with a dot. Should be
47*0Sstevel@tonic-gate  * done with care. The speedup can give problems with lookups from sources
48*0Sstevel@tonic-gate  * that lack DNS-style trailing dot magic, such as local files or NIS maps.
49*0Sstevel@tonic-gate  */
50*0Sstevel@tonic-gate
51*0Sstevel@tonic-gatestatic struct hostent *gethostbyname_dot(name)
52*0Sstevel@tonic-gatechar   *name;
53*0Sstevel@tonic-gate{
54*0Sstevel@tonic-gate    char    dot_name[MAXHOSTNAMELEN + 1];
55*0Sstevel@tonic-gate
56*0Sstevel@tonic-gate    /*
57*0Sstevel@tonic-gate     * Don't append dots to unqualified names. Such names are likely to come
58*0Sstevel@tonic-gate     * from local hosts files or from NIS.
59*0Sstevel@tonic-gate     */
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gate    if (strchr(name, '.') == 0 || strlen(name) >= MAXHOSTNAMELEN - 1) {
62*0Sstevel@tonic-gate	return (gethostbyname(name));
63*0Sstevel@tonic-gate    } else {
64*0Sstevel@tonic-gate	sprintf(dot_name, "%s.", name);
65*0Sstevel@tonic-gate	return (gethostbyname(dot_name));
66*0Sstevel@tonic-gate    }
67*0Sstevel@tonic-gate}
68*0Sstevel@tonic-gate
69*0Sstevel@tonic-gate#define gethostbyname gethostbyname_dot
70*0Sstevel@tonic-gate#endif
71*0Sstevel@tonic-gate
72*0Sstevel@tonic-gate/* sock_host - look up endpoint addresses and install conversion methods */
73*0Sstevel@tonic-gate
74*0Sstevel@tonic-gatevoid    sock_host(request)
75*0Sstevel@tonic-gatestruct request_info *request;
76*0Sstevel@tonic-gate{
77*0Sstevel@tonic-gate    static struct sockaddr_in client;
78*0Sstevel@tonic-gate    static struct sockaddr_in server;
79*0Sstevel@tonic-gate    int     len;
80*0Sstevel@tonic-gate    char    buf[BUFSIZ];
81*0Sstevel@tonic-gate    int     fd = request->fd;
82*0Sstevel@tonic-gate
83*0Sstevel@tonic-gate    sock_methods(request);
84*0Sstevel@tonic-gate
85*0Sstevel@tonic-gate    /*
86*0Sstevel@tonic-gate     * Look up the client host address. Hal R. Brand <BRAND@addvax.llnl.gov>
87*0Sstevel@tonic-gate     * suggested how to get the client host info in case of UDP connections:
88*0Sstevel@tonic-gate     * peek at the first message without actually looking at its contents. We
89*0Sstevel@tonic-gate     * really should verify that client.sin_family gets the value AF_INET,
90*0Sstevel@tonic-gate     * but this program has already caused too much grief on systems with
91*0Sstevel@tonic-gate     * broken library code.
92*0Sstevel@tonic-gate     */
93*0Sstevel@tonic-gate
94*0Sstevel@tonic-gate    len = sizeof(client);
95*0Sstevel@tonic-gate    if (getpeername(fd, (struct sockaddr *) & client, &len) < 0) {
96*0Sstevel@tonic-gate	request->sink = sock_sink;
97*0Sstevel@tonic-gate	len = sizeof(client);
98*0Sstevel@tonic-gate	if (recvfrom(fd, buf, sizeof(buf), MSG_PEEK,
99*0Sstevel@tonic-gate		     (struct sockaddr *) & client, &len) < 0) {
100*0Sstevel@tonic-gate	    tcpd_warn("can't get client address: %m");
101*0Sstevel@tonic-gate	    return;				/* give up */
102*0Sstevel@tonic-gate	}
103*0Sstevel@tonic-gate#ifdef really_paranoid
104*0Sstevel@tonic-gate	memset(buf, 0 sizeof(buf));
105*0Sstevel@tonic-gate#endif
106*0Sstevel@tonic-gate    }
107*0Sstevel@tonic-gate    request->client->sin = &client;
108*0Sstevel@tonic-gate
109*0Sstevel@tonic-gate    /*
110*0Sstevel@tonic-gate     * Determine the server binding. This is used for client username
111*0Sstevel@tonic-gate     * lookups, and for access control rules that trigger on the server
112*0Sstevel@tonic-gate     * address or name.
113*0Sstevel@tonic-gate     */
114*0Sstevel@tonic-gate
115*0Sstevel@tonic-gate    len = sizeof(server);
116*0Sstevel@tonic-gate    if (getsockname(fd, (struct sockaddr *) & server, &len) < 0) {
117*0Sstevel@tonic-gate	tcpd_warn("getsockname: %m");
118*0Sstevel@tonic-gate	return;
119*0Sstevel@tonic-gate    }
120*0Sstevel@tonic-gate    request->server->sin = &server;
121*0Sstevel@tonic-gate}
122*0Sstevel@tonic-gate
123*0Sstevel@tonic-gate/* sock_hostaddr - map endpoint address to printable form */
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gatevoid    sock_hostaddr(host)
126*0Sstevel@tonic-gatestruct host_info *host;
127*0Sstevel@tonic-gate{
128*0Sstevel@tonic-gate    struct sockaddr_in *sin = host->sin;
129*0Sstevel@tonic-gate
130*0Sstevel@tonic-gate    if (sin != 0)
131*0Sstevel@tonic-gate	STRN_CPY(host->addr, inet_ntoa(sin->sin_addr), sizeof(host->addr));
132*0Sstevel@tonic-gate}
133*0Sstevel@tonic-gate
134*0Sstevel@tonic-gate/* sock_hostname - map endpoint address to host name */
135*0Sstevel@tonic-gate
136*0Sstevel@tonic-gatevoid    sock_hostname(host)
137*0Sstevel@tonic-gatestruct host_info *host;
138*0Sstevel@tonic-gate{
139*0Sstevel@tonic-gate    struct sockaddr_in *sin = host->sin;
140*0Sstevel@tonic-gate    struct hostent *hp;
141*0Sstevel@tonic-gate    int     i;
142*0Sstevel@tonic-gate
143*0Sstevel@tonic-gate    /*
144*0Sstevel@tonic-gate     * On some systems, for example Solaris 2.3, gethostbyaddr(0.0.0.0) does
145*0Sstevel@tonic-gate     * not fail. Instead it returns "INADDR_ANY". Unfortunately, this does
146*0Sstevel@tonic-gate     * not work the other way around: gethostbyname("INADDR_ANY") fails. We
147*0Sstevel@tonic-gate     * have to special-case 0.0.0.0, in order to avoid false alerts from the
148*0Sstevel@tonic-gate     * host name/address checking code below.
149*0Sstevel@tonic-gate     */
150*0Sstevel@tonic-gate    if (sin != 0 && sin->sin_addr.s_addr != 0
151*0Sstevel@tonic-gate	&& (hp = gethostbyaddr((char *) &(sin->sin_addr),
152*0Sstevel@tonic-gate			       sizeof(sin->sin_addr), AF_INET)) != 0) {
153*0Sstevel@tonic-gate
154*0Sstevel@tonic-gate	STRN_CPY(host->name, hp->h_name, sizeof(host->name));
155*0Sstevel@tonic-gate
156*0Sstevel@tonic-gate	/*
157*0Sstevel@tonic-gate	 * Verify that the address is a member of the address list returned
158*0Sstevel@tonic-gate	 * by gethostbyname(hostname).
159*0Sstevel@tonic-gate	 *
160*0Sstevel@tonic-gate	 * Verify also that gethostbyaddr() and gethostbyname() return the same
161*0Sstevel@tonic-gate	 * hostname, or rshd and rlogind may still end up being spoofed.
162*0Sstevel@tonic-gate	 *
163*0Sstevel@tonic-gate	 * On some sites, gethostbyname("localhost") returns "localhost.domain".
164*0Sstevel@tonic-gate	 * This is a DNS artefact. We treat it as a special case. When we
165*0Sstevel@tonic-gate	 * can't believe the address list from gethostbyname("localhost")
166*0Sstevel@tonic-gate	 * we're in big trouble anyway.
167*0Sstevel@tonic-gate	 */
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate	if ((hp = gethostbyname(host->name)) == 0) {
170*0Sstevel@tonic-gate
171*0Sstevel@tonic-gate	    /*
172*0Sstevel@tonic-gate	     * Unable to verify that the host name matches the address. This
173*0Sstevel@tonic-gate	     * may be a transient problem or a botched name server setup.
174*0Sstevel@tonic-gate	     */
175*0Sstevel@tonic-gate
176*0Sstevel@tonic-gate	    tcpd_warn("can't verify hostname: gethostbyname(%s) failed",
177*0Sstevel@tonic-gate		      host->name);
178*0Sstevel@tonic-gate
179*0Sstevel@tonic-gate	} else if (STR_NE(host->name, hp->h_name)
180*0Sstevel@tonic-gate		   && STR_NE(host->name, "localhost")) {
181*0Sstevel@tonic-gate
182*0Sstevel@tonic-gate	    /*
183*0Sstevel@tonic-gate	     * The gethostbyaddr() and gethostbyname() calls did not return
184*0Sstevel@tonic-gate	     * the same hostname. This could be a nameserver configuration
185*0Sstevel@tonic-gate	     * problem. It could also be that someone is trying to spoof us.
186*0Sstevel@tonic-gate	     */
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gate	    tcpd_warn("host name/name mismatch: %s != %.*s",
189*0Sstevel@tonic-gate		      host->name, STRING_LENGTH, hp->h_name);
190*0Sstevel@tonic-gate
191*0Sstevel@tonic-gate	} else {
192*0Sstevel@tonic-gate
193*0Sstevel@tonic-gate	    /*
194*0Sstevel@tonic-gate	     * The address should be a member of the address list returned by
195*0Sstevel@tonic-gate	     * gethostbyname(). We should first verify that the h_addrtype
196*0Sstevel@tonic-gate	     * field is AF_INET, but this program has already caused too much
197*0Sstevel@tonic-gate	     * grief on systems with broken library code.
198*0Sstevel@tonic-gate	     */
199*0Sstevel@tonic-gate
200*0Sstevel@tonic-gate	    for (i = 0; hp->h_addr_list[i]; i++) {
201*0Sstevel@tonic-gate		if (memcmp(hp->h_addr_list[i],
202*0Sstevel@tonic-gate			   (char *) &sin->sin_addr,
203*0Sstevel@tonic-gate			   sizeof(sin->sin_addr)) == 0)
204*0Sstevel@tonic-gate		    return;			/* name is good, keep it */
205*0Sstevel@tonic-gate	    }
206*0Sstevel@tonic-gate
207*0Sstevel@tonic-gate	    /*
208*0Sstevel@tonic-gate	     * The host name does not map to the initial address. Perhaps
209*0Sstevel@tonic-gate	     * someone has messed up. Perhaps someone compromised a name
210*0Sstevel@tonic-gate	     * server.
211*0Sstevel@tonic-gate	     */
212*0Sstevel@tonic-gate
213*0Sstevel@tonic-gate	    tcpd_warn("host name/address mismatch: %s != %.*s",
214*0Sstevel@tonic-gate		      inet_ntoa(sin->sin_addr), STRING_LENGTH, hp->h_name);
215*0Sstevel@tonic-gate	}
216*0Sstevel@tonic-gate	strcpy(host->name, paranoid);		/* name is bad, clobber it */
217*0Sstevel@tonic-gate    }
218*0Sstevel@tonic-gate}
219*0Sstevel@tonic-gate
220*0Sstevel@tonic-gate/* sock_sink - absorb unreceived IP datagram */
221*0Sstevel@tonic-gate
222*0Sstevel@tonic-gatestatic void sock_sink(fd)
223*0Sstevel@tonic-gateint     fd;
224*0Sstevel@tonic-gate{
225*0Sstevel@tonic-gate    char    buf[BUFSIZ];
226*0Sstevel@tonic-gate    struct sockaddr_in sin;
227*0Sstevel@tonic-gate    int     size = sizeof(sin);
228*0Sstevel@tonic-gate
229*0Sstevel@tonic-gate    /*
230*0Sstevel@tonic-gate     * Eat up the not-yet received datagram. Some systems insist on a
231*0Sstevel@tonic-gate     * non-zero source address argument in the recvfrom() call below.
232*0Sstevel@tonic-gate     */
233*0Sstevel@tonic-gate
234*0Sstevel@tonic-gate    (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & sin, &size);
235*0Sstevel@tonic-gate}
236