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