Annotation of src/usr.bin/ssh/canohost.c, Revision 1.3
1.1 deraadt 1: /*
2:
3: canohost.c
4:
5: Author: Tatu Ylonen <ylo@cs.hut.fi>
6:
7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8: All rights reserved
9:
10: Created: Sun Jul 2 17:52:22 1995 ylo
11:
12: Functions for returning the canonical host name of the remote site.
13:
14: */
15:
16: #include "includes.h"
1.3 ! deraadt 17: RCSID("$Id: canohost.c,v 1.2 1999/09/29 21:14:16 deraadt Exp $");
1.1 deraadt 18:
19: #include "packet.h"
20: #include "xmalloc.h"
21: #include "ssh.h"
22:
23: /* Return the canonical name of the host at the other end of the socket.
24: The caller should free the returned string with xfree. */
25:
26: char *get_remote_hostname(int socket)
27: {
28: struct sockaddr_in from;
29: int fromlen, i;
30: struct hostent *hp;
1.2 deraadt 31: char name[MAXHOSTNAMELEN];
1.1 deraadt 32:
33: /* Get IP address of client. */
34: fromlen = sizeof(from);
35: memset(&from, 0, sizeof(from));
36: if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
37: {
38: error("getpeername failed: %.100s", strerror(errno));
1.2 deraadt 39: strlcpy(name, "UNKNOWN", sizeof name);
1.1 deraadt 40: goto check_ip_options;
41: }
42:
43: /* Map the IP address to a host name. */
44: hp = gethostbyaddr((char *)&from.sin_addr, sizeof(struct in_addr),
45: from.sin_family);
46: if (hp)
47: {
48: /* Got host name, find canonic host name. */
49: if (strchr(hp->h_name, '.') != 0)
1.2 deraadt 50: strlcpy(name, hp->h_name, sizeof(name));
1.1 deraadt 51: else if (hp->h_aliases != 0
52: && hp->h_aliases[0] != 0
53: && strchr(hp->h_aliases[0], '.') != 0)
1.2 deraadt 54: strlcpy(name, hp->h_aliases[0], sizeof(name));
1.1 deraadt 55: else
1.2 deraadt 56: strlcpy(name, hp->h_name, sizeof(name));
1.1 deraadt 57:
58: /* Convert it to all lowercase (which is expected by the rest of this
59: software). */
60: for (i = 0; name[i]; i++)
61: if (isupper(name[i]))
62: name[i] = tolower(name[i]);
63:
64: /* Map it back to an IP address and check that the given address actually
65: is an address of this host. This is necessary because anyone with
66: access to a name server can define arbitrary names for an IP address.
67: Mapping from name to IP address can be trusted better (but can still
68: be fooled if the intruder has access to the name server of the
69: domain). */
70: hp = gethostbyname(name);
71: if (!hp)
72: {
73: log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
1.2 deraadt 74: strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
1.1 deraadt 75: goto check_ip_options;
76: }
77: /* Look for the address from the list of addresses. */
78: for (i = 0; hp->h_addr_list[i]; i++)
79: if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr))
80: == 0)
81: break;
82: /* If we reached the end of the list, the address was not there. */
83: if (!hp->h_addr_list[i])
84: {
85: /* Address not found for the host name. */
86: log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
87: inet_ntoa(from.sin_addr), name);
1.2 deraadt 88: strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
1.1 deraadt 89: goto check_ip_options;
90: }
91: /* Address was found for the host name. We accept the host name. */
92: }
93: else
94: {
95: /* Host name not found. Use ascii representation of the address. */
1.2 deraadt 96: strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
1.1 deraadt 97: log("Could not reverse map address %.100s.", name);
98: }
99:
100: check_ip_options:
101:
102: /* If IP options are supported, make sure there are none (log and clear
103: them if any are found). Basically we are worried about source routing;
104: it can be used to pretend you are somebody (ip-address) you are not.
105: That itself may be "almost acceptable" under certain circumstances,
106: but rhosts autentication is useless if source routing is accepted.
107: Notice also that if we just dropped source routing here, the other
108: side could use IP spoofing to do rest of the interaction and could still
109: bypass security. So we exit here if we detect any IP options. */
110: {
111: unsigned char options[200], *ucp;
112: char text[1024], *cp;
113: int option_size, ipproto;
114: struct protoent *ip;
115:
116: if ((ip = getprotobyname("ip")) != NULL)
117: ipproto = ip->p_proto;
118: else
119: ipproto = IPPROTO_IP;
120: option_size = sizeof(options);
121: if (getsockopt(0, ipproto, IP_OPTIONS, (char *)options,
122: &option_size) >= 0 && option_size != 0)
123: {
124: cp = text;
125: /* Note: "text" buffer must be at least 3x as big as options. */
126: for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
127: sprintf(cp, " %2.2x", *ucp);
128: log("Connection from %.100s with IP options:%.800s",
129: inet_ntoa(from.sin_addr), text);
130: packet_disconnect("Connection from %.100s with IP options:%.800s",
131: inet_ntoa(from.sin_addr), text);
132: }
133: }
134:
135: return xstrdup(name);
136: }
137:
138: static char *canonical_host_name = NULL;
139: static char *canonical_host_ip = NULL;
140:
141: /* Return the canonical name of the host in the other side of the current
142: connection. The host name is cached, so it is efficient to call this
143: several times. */
144:
145: const char *get_canonical_hostname()
146: {
147: /* Check if we have previously retrieved this same name. */
148: if (canonical_host_name != NULL)
149: return canonical_host_name;
150:
151: /* Get the real hostname if socket; otherwise return UNKNOWN. */
152: if (packet_get_connection_in() == packet_get_connection_out())
153: canonical_host_name = get_remote_hostname(packet_get_connection_in());
154: else
155: canonical_host_name = xstrdup("UNKNOWN");
156:
157: return canonical_host_name;
158: }
159:
160: /* Returns the IP-address of the remote host as a string. The returned
161: string need not be freed. */
162:
163: const char *get_remote_ipaddr()
164: {
165: struct sockaddr_in from;
166: int fromlen, socket;
167:
168: /* Check if we have previously retrieved this same name. */
169: if (canonical_host_ip != NULL)
170: return canonical_host_ip;
171:
172: /* If not a socket, return UNKNOWN. */
173: if (packet_get_connection_in() != packet_get_connection_out())
174: {
175: canonical_host_ip = xstrdup("UNKNOWN");
176: return canonical_host_ip;
177: }
178:
179: /* Get client socket. */
180: socket = packet_get_connection_in();
181:
182: /* Get IP address of client. */
183: fromlen = sizeof(from);
184: memset(&from, 0, sizeof(from));
185: if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
186: {
187: error("getpeername failed: %.100s", strerror(errno));
188: return NULL;
189: }
190:
191: /* Get the IP address in ascii. */
192: canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr));
193:
194: /* Return ip address string. */
195: return canonical_host_ip;
196: }
197:
198: /* Returns the port of the peer of the socket. */
199:
200: int get_peer_port(int sock)
201: {
202: struct sockaddr_in from;
203: int fromlen;
204:
205: /* Get IP address of client. */
206: fromlen = sizeof(from);
207: memset(&from, 0, sizeof(from));
208: if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0)
209: {
210: error("getpeername failed: %.100s", strerror(errno));
211: return 0;
212: }
213:
214: /* Return port number. */
215: return ntohs(from.sin_port);
216: }
217:
218: /* Returns the port number of the remote host. */
219:
220: int get_remote_port()
221: {
222: int socket;
223:
224: /* If the connection is not a socket, return 65535. This is intentionally
225: chosen to be an unprivileged port number. */
226: if (packet_get_connection_in() != packet_get_connection_out())
227: return 65535;
228:
229: /* Get client socket. */
230: socket = packet_get_connection_in();
231:
232: /* Get and return the peer port number. */
233: return get_peer_port(socket);
234: }