source: trunk/third/ssh/canohost.c @ 12646

Revision 12646, 9.4 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12645, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2
3canohost.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8                   All rights reserved
9
10Created: Sun Jul  2 17:52:22 1995 ylo
11
12Functions for returning the canonical host name of the remote site.
13
14*/
15
16/*
17 * $Id: canohost.c,v 1.1.1.2 1999-03-08 17:43:08 danw Exp $
18 * $Log: not supported by cvs2svn $
19 * Revision 1.4  1998/05/23  20:21:01  kivinen
20 *      Changed () -> (void).
21 *
22 * Revision 1.3  1997/03/19  15:59:45  kivinen
23 *      Limit hostname to 255 characters.
24 *
25 * Revision 1.2  1996/10/29 22:35:11  kivinen
26 *      log -> log_msg.
27 *
28 * Revision 1.1.1.1  1996/02/18 21:38:12  ylo
29 *      Imported ssh-1.2.13.
30 *
31 * Revision 1.5  1995/09/21  17:08:24  ylo
32 *      Added get_remote_port.
33 *
34 * Revision 1.4  1995/09/06  15:57:59  ylo
35 *      Fixed serious bugs.
36 *
37 * Revision 1.3  1995/08/29  22:20:12  ylo
38 *      Added code to get ip number as string.
39 *
40 * Revision 1.2  1995/07/13  01:19:18  ylo
41 *      Removed "Last modified" header.
42 *      Added cvs log.
43 *
44 * $Endlog$
45 */
46
47#include "includes.h"
48#include "packet.h"
49#include "xmalloc.h"
50#include "ssh.h"
51
52/* Return the canonical name of the host at the other end of the socket.
53   The caller should free the returned string with xfree. */
54
55char *get_remote_hostname(int socket)
56{
57  struct sockaddr_in from;
58  int fromlen, i;
59  struct hostent *hp;
60  char name[255];
61
62  /* Get IP address of client. */
63  fromlen = sizeof(from);
64  memset(&from, 0, sizeof(from));
65  if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
66    {
67      error("getpeername failed: %.100s", strerror(errno));
68      strcpy(name, "UNKNOWN");
69      goto check_ip_options;
70    }
71 
72  /* Map the IP address to a host name. */
73  hp = gethostbyaddr((char *)&from.sin_addr, sizeof(struct in_addr),
74                     from.sin_family);
75  if (hp)
76    {
77      /* Got host name. */
78      strncpy(name, hp->h_name, sizeof(name));
79      name[sizeof(name) - 1] = '\0';
80     
81      /* Convert it to all lowercase (which is expected by the rest of this
82         software). */
83      for (i = 0; name[i]; i++)
84        if (isupper(name[i]))
85          name[i] = tolower(name[i]);
86
87      /* Map it back to an IP address and check that the given address actually
88         is an address of this host.  This is necessary because anyone with
89         access to a name server can define arbitrary names for an IP address.
90         Mapping from name to IP address can be trusted better (but can still
91         be fooled if the intruder has access to the name server of the
92         domain). */
93      hp = gethostbyname(name);
94      if (!hp)
95        {
96          log_msg("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
97          strcpy(name, inet_ntoa(from.sin_addr));
98          goto check_ip_options;
99        }
100      /* Look for the address from the list of addresses. */
101      for (i = 0; hp->h_addr_list[i]; i++)
102        if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr))
103            == 0)
104          break;
105      /* If we reached the end of the list, the address was not there. */
106      if (!hp->h_addr_list[i])
107        {
108          /* Address not found for the host name. */
109          log_msg("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
110              inet_ntoa(from.sin_addr), name);
111          strcpy(name, inet_ntoa(from.sin_addr));
112          goto check_ip_options;
113        }
114      /* Address was found for the host name.  We accept the host name. */
115    }
116  else
117    {
118      /* Host name not found.  Use ascii representation of the address. */
119      strcpy(name, inet_ntoa(from.sin_addr));
120      log_msg("Could not reverse map address %.100s.", name);
121    }
122
123 check_ip_options:
124 
125#ifdef IP_OPTIONS
126  /* If IP options are supported, make sure there are none (log and clear
127     them if any are found).  Basically we are worried about source routing;
128     it can be used to pretend you are somebody (ip-address) you are not.
129     That itself may be "almost acceptable" under certain circumstances,
130     but rhosts autentication is useless if source routing is accepted.
131     Notice also that if we just dropped source routing here, the other
132     side could use IP spoofing to do rest of the interaction and could still
133     bypass security.  So we exit here if we detect any IP options. */
134  {
135    unsigned char options[200], *ucp;
136    char text[1024], *cp;
137    int option_size, ipproto;
138    struct protoent *ip;
139   
140    if ((ip = getprotobyname("ip")) != NULL)
141      ipproto = ip->p_proto;
142    else
143      ipproto = IPPROTO_IP;
144    option_size = sizeof(options);
145    if (getsockopt(socket, ipproto, IP_OPTIONS, (char *)options,
146                   &option_size) >= 0 && option_size != 0)
147      {
148        cp = text;
149        /* Note: "text" buffer must be at least 3x as big as options. */
150        for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
151          sprintf(cp, " %2.2x", *ucp);
152        log_msg("Connection from %.100s with IP options:%.800s",
153            inet_ntoa(from.sin_addr), text);
154        packet_disconnect("Connection from %.100s with IP options:%.800s",
155                          inet_ntoa(from.sin_addr), text);
156      }
157  }
158#endif
159
160  return xstrdup(name);
161}
162
163static char *canonical_host_name = NULL;
164static char *canonical_host_ip = NULL;
165
166/* Return the canonical name of the host in the other side of the current
167   connection.  The host name is cached, so it is efficient to call this
168   several times. */
169
170const char *get_canonical_hostname(void)
171{
172  int fromlen, tolen;
173  struct sockaddr_in from, to;
174
175  /* Check if we have previously retrieved this same name. */
176  if (canonical_host_name != NULL)
177    return canonical_host_name;
178
179  /* If using different descriptors for the two directions, check if
180     both have the same remote address.  If so, get the address; otherwise
181     return UNKNOWN. */
182  if (packet_get_connection_in() != packet_get_connection_out())
183    {
184      fromlen = sizeof(from);
185      memset(&from, 0, sizeof(from));
186      if (getpeername(packet_get_connection_in(), (struct sockaddr *)&from,
187                      &fromlen) < 0)
188        goto no_ip_addr;
189
190      tolen = sizeof(to);
191      memset(&to, 0, sizeof(to));
192      if (getpeername(packet_get_connection_out(), (struct sockaddr *)&to,
193                      &tolen) < 0)
194        goto no_ip_addr;
195     
196      if (from.sin_family == AF_INET && to.sin_family == AF_INET &&
197          memcmp(&from, &to, sizeof(from)) == 0)
198        goto return_ip_addr;
199
200    no_ip_addr:
201      canonical_host_name = xstrdup("UNKNOWN");
202      return canonical_host_name;
203    }
204
205 return_ip_addr:
206
207  /* Get the real hostname. */
208  canonical_host_name = get_remote_hostname(packet_get_connection_in());
209  return canonical_host_name;
210}
211
212/* Returns the IP-address of the remote host as a string.  The returned
213   string need not be freed. */
214
215const char *get_remote_ipaddr(void)
216{
217  struct sockaddr_in from, to;
218  int fromlen, tolen, socket;
219
220  /* Check if we have previously retrieved this same name. */
221  if (canonical_host_ip != NULL)
222    return canonical_host_ip;
223
224  /* If using different descriptors for the two directions, check if
225     both have the same remote address.  If so, get the address; otherwise
226     return UNKNOWN. */
227  if (packet_get_connection_in() != packet_get_connection_out())
228    {
229      fromlen = sizeof(from);
230      memset(&from, 0, sizeof(from));
231      if (getpeername(packet_get_connection_in(), (struct sockaddr *)&from,
232                      &fromlen) < 0)
233        goto no_ip_addr;
234
235      tolen = sizeof(to);
236      memset(&to, 0, sizeof(to));
237      if (getpeername(packet_get_connection_out(), (struct sockaddr *)&to,
238                      &tolen) < 0)
239        goto no_ip_addr;
240     
241      if (from.sin_family == AF_INET && to.sin_family == AF_INET &&
242          memcmp(&from, &to, sizeof(from)) == 0)
243        goto return_ip_addr;
244
245    no_ip_addr:
246      canonical_host_ip = xstrdup("UNKNOWN");
247      return canonical_host_ip;
248    }
249
250 return_ip_addr:
251
252  /* Get client socket. */
253  socket = packet_get_connection_in();
254
255  /* Get IP address of client. */
256  fromlen = sizeof(from);
257  memset(&from, 0, sizeof(from));
258  if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
259    {
260      error("getpeername failed: %.100s", strerror(errno));
261      return NULL;
262    }
263
264  /* Get the IP address in ascii. */
265  canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr));
266
267  /* Return ip address string. */
268  return canonical_host_ip;
269}
270
271/* Returns the port of the peer of the socket. */
272
273int get_peer_port(int sock)
274{
275  struct sockaddr_in from;
276  int fromlen;
277
278  /* Get IP address of client. */
279  fromlen = sizeof(from);
280  memset(&from, 0, sizeof(from));
281  if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0)
282    {
283      error("getpeername failed: %.100s", strerror(errno));
284      return 0;
285    }
286
287  /* Return port number. */
288  return ntohs(from.sin_port);
289}
290
291/* Returns the port number of the remote host.  */
292
293int get_remote_port(void)
294{
295  int socket;
296  int fromlen, tolen;
297  struct sockaddr_in from, to;
298
299  /* If two different descriptors, check if they are internet-domain, and
300     have the same address. */
301  if (packet_get_connection_in() != packet_get_connection_out())
302    {
303      fromlen = sizeof(from);
304      memset(&from, 0, sizeof(from));
305      if (getpeername(packet_get_connection_in(), (struct sockaddr *)&from,
306                      &fromlen) < 0)
307        goto no_ip_addr;
308
309      tolen = sizeof(to);
310      memset(&to, 0, sizeof(to));
311      if (getpeername(packet_get_connection_out(), (struct sockaddr *)&to,
312                      &tolen) < 0)
313        goto no_ip_addr;
314     
315      if (from.sin_family == AF_INET && to.sin_family == AF_INET &&
316          memcmp(&from, &to, sizeof(from)) == 0)
317        goto return_port;
318
319    no_ip_addr:
320      return 65535;
321    }
322
323 return_port:
324
325  /* Get client socket. */
326  socket = packet_get_connection_in();
327
328  /* Get and return the peer port number. */
329  return get_peer_port(socket);
330}
Note: See TracBrowser for help on using the repository browser.