diff options
author | Colin Watson <cjwatson@debian.org> | 2016-08-06 10:49:59 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2016-08-07 12:18:58 +0100 |
commit | 477bb7636238c106f8cd7c868a8c0c5eabcfb3db (patch) | |
tree | 601176af2ecf358c36b766776a86845ad7a3cd6f /canohost.c | |
parent | 747fac2de0d889183f67f6900194c0462c558544 (diff) | |
parent | 4c914ccd85bbf391c4dc61b85e3c178fef465e3f (diff) |
New upstream release (7.3p1).
Diffstat (limited to 'canohost.c')
-rw-r--r-- | canohost.c | 215 |
1 files changed, 33 insertions, 182 deletions
diff --git a/canohost.c b/canohost.c index 223964ea3..404731d24 100644 --- a/canohost.c +++ b/canohost.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: canohost.c,v 1.72 2015/03/01 15:44:40 millert Exp $ */ | 1 | /* $OpenBSD: canohost.c,v 1.73 2016/03/07 19:02:43 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -35,52 +35,44 @@ | |||
35 | #include "canohost.h" | 35 | #include "canohost.h" |
36 | #include "misc.h" | 36 | #include "misc.h" |
37 | 37 | ||
38 | static void check_ip_options(int, char *); | ||
39 | static char *canonical_host_ip = NULL; | ||
40 | static int cached_port = -1; | ||
41 | |||
42 | /* | 38 | /* |
43 | * Return the canonical name of the host at the other end of the socket. The | 39 | * Returns the remote DNS hostname as a string. The returned string must not |
44 | * caller should free the returned string. | 40 | * be freed. NB. this will usually trigger a DNS query the first time it is |
41 | * called. | ||
42 | * This function does additional checks on the hostname to mitigate some | ||
43 | * attacks on legacy rhosts-style authentication. | ||
44 | * XXX is RhostsRSAAuthentication vulnerable to these? | ||
45 | * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?) | ||
45 | */ | 46 | */ |
46 | 47 | ||
47 | static char * | 48 | char * |
48 | get_remote_hostname(int sock, int use_dns) | 49 | remote_hostname(struct ssh *ssh) |
49 | { | 50 | { |
50 | struct sockaddr_storage from; | 51 | struct sockaddr_storage from; |
51 | socklen_t fromlen; | 52 | socklen_t fromlen; |
52 | struct addrinfo hints, *ai, *aitop; | 53 | struct addrinfo hints, *ai, *aitop; |
53 | char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST]; | 54 | char name[NI_MAXHOST], ntop2[NI_MAXHOST]; |
55 | const char *ntop = ssh_remote_ipaddr(ssh); | ||
54 | 56 | ||
55 | /* Get IP address of client. */ | 57 | /* Get IP address of client. */ |
56 | fromlen = sizeof(from); | 58 | fromlen = sizeof(from); |
57 | memset(&from, 0, sizeof(from)); | 59 | memset(&from, 0, sizeof(from)); |
58 | if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) { | 60 | if (getpeername(ssh_packet_get_connection_in(ssh), |
61 | (struct sockaddr *)&from, &fromlen) < 0) { | ||
59 | debug("getpeername failed: %.100s", strerror(errno)); | 62 | debug("getpeername failed: %.100s", strerror(errno)); |
60 | cleanup_exit(255); | 63 | return strdup(ntop); |
61 | } | 64 | } |
62 | 65 | ||
63 | if (from.ss_family == AF_INET) | ||
64 | check_ip_options(sock, ntop); | ||
65 | |||
66 | ipv64_normalise_mapped(&from, &fromlen); | 66 | ipv64_normalise_mapped(&from, &fromlen); |
67 | |||
68 | if (from.ss_family == AF_INET6) | 67 | if (from.ss_family == AF_INET6) |
69 | fromlen = sizeof(struct sockaddr_in6); | 68 | fromlen = sizeof(struct sockaddr_in6); |
70 | 69 | ||
71 | if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), | ||
72 | NULL, 0, NI_NUMERICHOST) != 0) | ||
73 | fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed"); | ||
74 | |||
75 | if (!use_dns) | ||
76 | return xstrdup(ntop); | ||
77 | |||
78 | debug3("Trying to reverse map address %.100s.", ntop); | 70 | debug3("Trying to reverse map address %.100s.", ntop); |
79 | /* Map the IP address to a host name. */ | 71 | /* Map the IP address to a host name. */ |
80 | if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), | 72 | if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), |
81 | NULL, 0, NI_NAMEREQD) != 0) { | 73 | NULL, 0, NI_NAMEREQD) != 0) { |
82 | /* Host name not found. Use ip address. */ | 74 | /* Host name not found. Use ip address. */ |
83 | return xstrdup(ntop); | 75 | return strdup(ntop); |
84 | } | 76 | } |
85 | 77 | ||
86 | /* | 78 | /* |
@@ -95,10 +87,10 @@ get_remote_hostname(int sock, int use_dns) | |||
95 | logit("Nasty PTR record \"%s\" is set up for %s, ignoring", | 87 | logit("Nasty PTR record \"%s\" is set up for %s, ignoring", |
96 | name, ntop); | 88 | name, ntop); |
97 | freeaddrinfo(ai); | 89 | freeaddrinfo(ai); |
98 | return xstrdup(ntop); | 90 | return strdup(ntop); |
99 | } | 91 | } |
100 | 92 | ||
101 | /* Names are stores in lowercase. */ | 93 | /* Names are stored in lowercase. */ |
102 | lowercase(name); | 94 | lowercase(name); |
103 | 95 | ||
104 | /* | 96 | /* |
@@ -115,8 +107,8 @@ get_remote_hostname(int sock, int use_dns) | |||
115 | hints.ai_socktype = SOCK_STREAM; | 107 | hints.ai_socktype = SOCK_STREAM; |
116 | if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { | 108 | if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { |
117 | logit("reverse mapping checking getaddrinfo for %.700s " | 109 | logit("reverse mapping checking getaddrinfo for %.700s " |
118 | "[%s] failed - POSSIBLE BREAK-IN ATTEMPT!", name, ntop); | 110 | "[%s] failed.", name, ntop); |
119 | return xstrdup(ntop); | 111 | return strdup(ntop); |
120 | } | 112 | } |
121 | /* Look for the address from the list of addresses. */ | 113 | /* Look for the address from the list of addresses. */ |
122 | for (ai = aitop; ai; ai = ai->ai_next) { | 114 | for (ai = aitop; ai; ai = ai->ai_next) { |
@@ -127,53 +119,13 @@ get_remote_hostname(int sock, int use_dns) | |||
127 | } | 119 | } |
128 | freeaddrinfo(aitop); | 120 | freeaddrinfo(aitop); |
129 | /* If we reached the end of the list, the address was not there. */ | 121 | /* If we reached the end of the list, the address was not there. */ |
130 | if (!ai) { | 122 | if (ai == NULL) { |
131 | /* Address not found for the host name. */ | 123 | /* Address not found for the host name. */ |
132 | logit("Address %.100s maps to %.600s, but this does not " | 124 | logit("Address %.100s maps to %.600s, but this does not " |
133 | "map back to the address - POSSIBLE BREAK-IN ATTEMPT!", | 125 | "map back to the address.", ntop, name); |
134 | ntop, name); | 126 | return strdup(ntop); |
135 | return xstrdup(ntop); | ||
136 | } | ||
137 | return xstrdup(name); | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * If IP options are supported, make sure there are none (log and | ||
142 | * disconnect them if any are found). Basically we are worried about | ||
143 | * source routing; it can be used to pretend you are somebody | ||
144 | * (ip-address) you are not. That itself may be "almost acceptable" | ||
145 | * under certain circumstances, but rhosts autentication is useless | ||
146 | * if source routing is accepted. Notice also that if we just dropped | ||
147 | * source routing here, the other side could use IP spoofing to do | ||
148 | * rest of the interaction and could still bypass security. So we | ||
149 | * exit here if we detect any IP options. | ||
150 | */ | ||
151 | /* IPv4 only */ | ||
152 | static void | ||
153 | check_ip_options(int sock, char *ipaddr) | ||
154 | { | ||
155 | #ifdef IP_OPTIONS | ||
156 | u_char options[200]; | ||
157 | char text[sizeof(options) * 3 + 1]; | ||
158 | socklen_t option_size, i; | ||
159 | int ipproto; | ||
160 | struct protoent *ip; | ||
161 | |||
162 | if ((ip = getprotobyname("ip")) != NULL) | ||
163 | ipproto = ip->p_proto; | ||
164 | else | ||
165 | ipproto = IPPROTO_IP; | ||
166 | option_size = sizeof(options); | ||
167 | if (getsockopt(sock, ipproto, IP_OPTIONS, options, | ||
168 | &option_size) >= 0 && option_size != 0) { | ||
169 | text[0] = '\0'; | ||
170 | for (i = 0; i < option_size; i++) | ||
171 | snprintf(text + i*3, sizeof(text) - i*3, | ||
172 | " %2.2x", options[i]); | ||
173 | fatal("Connection from %.100s with IP options:%.800s", | ||
174 | ipaddr, text); | ||
175 | } | 127 | } |
176 | #endif /* IP_OPTIONS */ | 128 | return strdup(name); |
177 | } | 129 | } |
178 | 130 | ||
179 | void | 131 | void |
@@ -202,38 +154,6 @@ ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) | |||
202 | } | 154 | } |
203 | 155 | ||
204 | /* | 156 | /* |
205 | * Return the canonical name of the host in the other side of the current | ||
206 | * connection. The host name is cached, so it is efficient to call this | ||
207 | * several times. | ||
208 | */ | ||
209 | |||
210 | const char * | ||
211 | get_canonical_hostname(int use_dns) | ||
212 | { | ||
213 | char *host; | ||
214 | static char *canonical_host_name = NULL; | ||
215 | static char *remote_ip = NULL; | ||
216 | |||
217 | /* Check if we have previously retrieved name with same option. */ | ||
218 | if (use_dns && canonical_host_name != NULL) | ||
219 | return canonical_host_name; | ||
220 | if (!use_dns && remote_ip != NULL) | ||
221 | return remote_ip; | ||
222 | |||
223 | /* Get the real hostname if socket; otherwise return UNKNOWN. */ | ||
224 | if (packet_connection_is_on_socket()) | ||
225 | host = get_remote_hostname(packet_get_connection_in(), use_dns); | ||
226 | else | ||
227 | host = "UNKNOWN"; | ||
228 | |||
229 | if (use_dns) | ||
230 | canonical_host_name = host; | ||
231 | else | ||
232 | remote_ip = host; | ||
233 | return host; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * Returns the local/remote IP-address/hostname of socket as a string. | 157 | * Returns the local/remote IP-address/hostname of socket as a string. |
238 | * The returned string must be freed. | 158 | * The returned string must be freed. |
239 | */ | 159 | */ |
@@ -250,12 +170,10 @@ get_socket_address(int sock, int remote, int flags) | |||
250 | memset(&addr, 0, sizeof(addr)); | 170 | memset(&addr, 0, sizeof(addr)); |
251 | 171 | ||
252 | if (remote) { | 172 | if (remote) { |
253 | if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) | 173 | if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) != 0) |
254 | < 0) | ||
255 | return NULL; | 174 | return NULL; |
256 | } else { | 175 | } else { |
257 | if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) | 176 | if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) != 0) |
258 | < 0) | ||
259 | return NULL; | 177 | return NULL; |
260 | } | 178 | } |
261 | 179 | ||
@@ -271,7 +189,7 @@ get_socket_address(int sock, int remote, int flags) | |||
271 | /* Get the address in ascii. */ | 189 | /* Get the address in ascii. */ |
272 | if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop, | 190 | if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop, |
273 | sizeof(ntop), NULL, 0, flags)) != 0) { | 191 | sizeof(ntop), NULL, 0, flags)) != 0) { |
274 | error("get_socket_address: getnameinfo %d failed: %s", | 192 | error("%s: getnameinfo %d failed: %s", __func__, |
275 | flags, ssh_gai_strerror(r)); | 193 | flags, ssh_gai_strerror(r)); |
276 | return NULL; | 194 | return NULL; |
277 | } | 195 | } |
@@ -316,7 +234,8 @@ get_local_name(int fd) | |||
316 | 234 | ||
317 | /* Handle the case where we were passed a pipe */ | 235 | /* Handle the case where we were passed a pipe */ |
318 | if (gethostname(myname, sizeof(myname)) == -1) { | 236 | if (gethostname(myname, sizeof(myname)) == -1) { |
319 | verbose("get_local_name: gethostname: %s", strerror(errno)); | 237 | verbose("%s: gethostname: %s", __func__, strerror(errno)); |
238 | host = xstrdup("UNKNOWN"); | ||
320 | } else { | 239 | } else { |
321 | host = xstrdup(myname); | 240 | host = xstrdup(myname); |
322 | } | 241 | } |
@@ -324,51 +243,9 @@ get_local_name(int fd) | |||
324 | return host; | 243 | return host; |
325 | } | 244 | } |
326 | 245 | ||
327 | void | ||
328 | clear_cached_addr(void) | ||
329 | { | ||
330 | free(canonical_host_ip); | ||
331 | canonical_host_ip = NULL; | ||
332 | cached_port = -1; | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * Returns the IP-address of the remote host as a string. The returned | ||
337 | * string must not be freed. | ||
338 | */ | ||
339 | |||
340 | const char * | ||
341 | get_remote_ipaddr(void) | ||
342 | { | ||
343 | /* Check whether we have cached the ipaddr. */ | ||
344 | if (canonical_host_ip == NULL) { | ||
345 | if (packet_connection_is_on_socket()) { | ||
346 | canonical_host_ip = | ||
347 | get_peer_ipaddr(packet_get_connection_in()); | ||
348 | if (canonical_host_ip == NULL) | ||
349 | cleanup_exit(255); | ||
350 | } else { | ||
351 | /* If not on socket, return UNKNOWN. */ | ||
352 | canonical_host_ip = xstrdup("UNKNOWN"); | ||
353 | } | ||
354 | } | ||
355 | return canonical_host_ip; | ||
356 | } | ||
357 | |||
358 | const char * | ||
359 | get_remote_name_or_ip(u_int utmp_len, int use_dns) | ||
360 | { | ||
361 | static const char *remote = ""; | ||
362 | if (utmp_len > 0) | ||
363 | remote = get_canonical_hostname(use_dns); | ||
364 | if (utmp_len == 0 || strlen(remote) > utmp_len) | ||
365 | remote = get_remote_ipaddr(); | ||
366 | return remote; | ||
367 | } | ||
368 | |||
369 | /* Returns the local/remote port for the socket. */ | 246 | /* Returns the local/remote port for the socket. */ |
370 | 247 | ||
371 | int | 248 | static int |
372 | get_sock_port(int sock, int local) | 249 | get_sock_port(int sock, int local) |
373 | { | 250 | { |
374 | struct sockaddr_storage from; | 251 | struct sockaddr_storage from; |
@@ -402,27 +279,11 @@ get_sock_port(int sock, int local) | |||
402 | /* Return port number. */ | 279 | /* Return port number. */ |
403 | if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, | 280 | if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, |
404 | strport, sizeof(strport), NI_NUMERICSERV)) != 0) | 281 | strport, sizeof(strport), NI_NUMERICSERV)) != 0) |
405 | fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed: %s", | 282 | fatal("%s: getnameinfo NI_NUMERICSERV failed: %s", __func__, |
406 | ssh_gai_strerror(r)); | 283 | ssh_gai_strerror(r)); |
407 | return atoi(strport); | 284 | return atoi(strport); |
408 | } | 285 | } |
409 | 286 | ||
410 | /* Returns remote/local port number for the current connection. */ | ||
411 | |||
412 | static int | ||
413 | get_port(int local) | ||
414 | { | ||
415 | /* | ||
416 | * If the connection is not a socket, return 65535. This is | ||
417 | * intentionally chosen to be an unprivileged port number. | ||
418 | */ | ||
419 | if (!packet_connection_is_on_socket()) | ||
420 | return 65535; | ||
421 | |||
422 | /* Get socket and return the port number. */ | ||
423 | return get_sock_port(packet_get_connection_in(), local); | ||
424 | } | ||
425 | |||
426 | int | 287 | int |
427 | get_peer_port(int sock) | 288 | get_peer_port(int sock) |
428 | { | 289 | { |
@@ -430,17 +291,7 @@ get_peer_port(int sock) | |||
430 | } | 291 | } |
431 | 292 | ||
432 | int | 293 | int |
433 | get_remote_port(void) | 294 | get_local_port(int sock) |
434 | { | ||
435 | /* Cache to avoid getpeername() on a dead connection */ | ||
436 | if (cached_port == -1) | ||
437 | cached_port = get_port(0); | ||
438 | |||
439 | return cached_port; | ||
440 | } | ||
441 | |||
442 | int | ||
443 | get_local_port(void) | ||
444 | { | 295 | { |
445 | return get_port(1); | 296 | return get_sock_port(sock, 1); |
446 | } | 297 | } |