diff options
Diffstat (limited to 'auth.c')
-rw-r--r-- | auth.c | 151 |
1 files changed, 138 insertions, 13 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.c,v 1.113 2015/08/21 03:42:19 djm Exp $ */ | 1 | /* $OpenBSD: auth.c,v 1.115 2016/06/15 00:40:40 dtucker Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <sys/types.h> | 28 | #include <sys/types.h> |
29 | #include <sys/stat.h> | 29 | #include <sys/stat.h> |
30 | #include <sys/socket.h> | ||
30 | 31 | ||
31 | #include <netinet/in.h> | 32 | #include <netinet/in.h> |
32 | 33 | ||
@@ -50,6 +51,7 @@ | |||
50 | #include <string.h> | 51 | #include <string.h> |
51 | #include <unistd.h> | 52 | #include <unistd.h> |
52 | #include <limits.h> | 53 | #include <limits.h> |
54 | #include <netdb.h> | ||
53 | 55 | ||
54 | #include "xmalloc.h" | 56 | #include "xmalloc.h" |
55 | #include "match.h" | 57 | #include "match.h" |
@@ -97,6 +99,7 @@ int auth_debug_init; | |||
97 | int | 99 | int |
98 | allowed_user(struct passwd * pw) | 100 | allowed_user(struct passwd * pw) |
99 | { | 101 | { |
102 | struct ssh *ssh = active_state; /* XXX */ | ||
100 | struct stat st; | 103 | struct stat st; |
101 | const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; | 104 | const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; |
102 | u_int i; | 105 | u_int i; |
@@ -182,8 +185,8 @@ allowed_user(struct passwd * pw) | |||
182 | 185 | ||
183 | if (options.num_deny_users > 0 || options.num_allow_users > 0 || | 186 | if (options.num_deny_users > 0 || options.num_allow_users > 0 || |
184 | options.num_deny_groups > 0 || options.num_allow_groups > 0) { | 187 | options.num_deny_groups > 0 || options.num_allow_groups > 0) { |
185 | hostname = get_canonical_hostname(options.use_dns); | 188 | hostname = auth_get_canonical_hostname(ssh, options.use_dns); |
186 | ipaddr = get_remote_ipaddr(); | 189 | ipaddr = ssh_remote_ipaddr(ssh); |
187 | } | 190 | } |
188 | 191 | ||
189 | /* Return false if user is listed in DenyUsers */ | 192 | /* Return false if user is listed in DenyUsers */ |
@@ -274,6 +277,7 @@ void | |||
274 | auth_log(Authctxt *authctxt, int authenticated, int partial, | 277 | auth_log(Authctxt *authctxt, int authenticated, int partial, |
275 | const char *method, const char *submethod) | 278 | const char *method, const char *submethod) |
276 | { | 279 | { |
280 | struct ssh *ssh = active_state; /* XXX */ | ||
277 | void (*authlog) (const char *fmt,...) = verbose; | 281 | void (*authlog) (const char *fmt,...) = verbose; |
278 | char *authmsg; | 282 | char *authmsg; |
279 | 283 | ||
@@ -300,8 +304,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, | |||
300 | submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, | 304 | submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, |
301 | authctxt->valid ? "" : "invalid user ", | 305 | authctxt->valid ? "" : "invalid user ", |
302 | authctxt->user, | 306 | authctxt->user, |
303 | get_remote_ipaddr(), | 307 | ssh_remote_ipaddr(ssh), |
304 | get_remote_port(), | 308 | ssh_remote_port(ssh), |
305 | compat20 ? "ssh2" : "ssh1", | 309 | compat20 ? "ssh2" : "ssh1", |
306 | authctxt->info != NULL ? ": " : "", | 310 | authctxt->info != NULL ? ": " : "", |
307 | authctxt->info != NULL ? authctxt->info : ""); | 311 | authctxt->info != NULL ? authctxt->info : ""); |
@@ -314,11 +318,12 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, | |||
314 | strncmp(method, "keyboard-interactive", 20) == 0 || | 318 | strncmp(method, "keyboard-interactive", 20) == 0 || |
315 | strcmp(method, "challenge-response") == 0)) | 319 | strcmp(method, "challenge-response") == 0)) |
316 | record_failed_login(authctxt->user, | 320 | record_failed_login(authctxt->user, |
317 | get_canonical_hostname(options.use_dns), "ssh"); | 321 | auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); |
318 | # ifdef WITH_AIXAUTHENTICATE | 322 | # ifdef WITH_AIXAUTHENTICATE |
319 | if (authenticated) | 323 | if (authenticated) |
320 | sys_auth_record_login(authctxt->user, | 324 | sys_auth_record_login(authctxt->user, |
321 | get_canonical_hostname(options.use_dns), "ssh", &loginmsg); | 325 | auth_get_canonical_hostname(ssh, options.use_dns), "ssh", |
326 | &loginmsg); | ||
322 | # endif | 327 | # endif |
323 | #endif | 328 | #endif |
324 | #ifdef SSH_AUDIT_EVENTS | 329 | #ifdef SSH_AUDIT_EVENTS |
@@ -331,12 +336,14 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, | |||
331 | void | 336 | void |
332 | auth_maxtries_exceeded(Authctxt *authctxt) | 337 | auth_maxtries_exceeded(Authctxt *authctxt) |
333 | { | 338 | { |
339 | struct ssh *ssh = active_state; /* XXX */ | ||
340 | |||
334 | error("maximum authentication attempts exceeded for " | 341 | error("maximum authentication attempts exceeded for " |
335 | "%s%.100s from %.200s port %d %s", | 342 | "%s%.100s from %.200s port %d %s", |
336 | authctxt->valid ? "" : "invalid user ", | 343 | authctxt->valid ? "" : "invalid user ", |
337 | authctxt->user, | 344 | authctxt->user, |
338 | get_remote_ipaddr(), | 345 | ssh_remote_ipaddr(ssh), |
339 | get_remote_port(), | 346 | ssh_remote_port(ssh), |
340 | compat20 ? "ssh2" : "ssh1"); | 347 | compat20 ? "ssh2" : "ssh1"); |
341 | packet_disconnect("Too many authentication failures"); | 348 | packet_disconnect("Too many authentication failures"); |
342 | /* NOTREACHED */ | 349 | /* NOTREACHED */ |
@@ -348,6 +355,8 @@ auth_maxtries_exceeded(Authctxt *authctxt) | |||
348 | int | 355 | int |
349 | auth_root_allowed(const char *method) | 356 | auth_root_allowed(const char *method) |
350 | { | 357 | { |
358 | struct ssh *ssh = active_state; /* XXX */ | ||
359 | |||
351 | switch (options.permit_root_login) { | 360 | switch (options.permit_root_login) { |
352 | case PERMIT_YES: | 361 | case PERMIT_YES: |
353 | return 1; | 362 | return 1; |
@@ -364,7 +373,8 @@ auth_root_allowed(const char *method) | |||
364 | } | 373 | } |
365 | break; | 374 | break; |
366 | } | 375 | } |
367 | logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); | 376 | logit("ROOT LOGIN REFUSED FROM %.200s port %d", |
377 | ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); | ||
368 | return 0; | 378 | return 0; |
369 | } | 379 | } |
370 | 380 | ||
@@ -604,6 +614,7 @@ auth_openprincipals(const char *file, struct passwd *pw, int strict_modes) | |||
604 | struct passwd * | 614 | struct passwd * |
605 | getpwnamallow(const char *user) | 615 | getpwnamallow(const char *user) |
606 | { | 616 | { |
617 | struct ssh *ssh = active_state; /* XXX */ | ||
607 | #ifdef HAVE_LOGIN_CAP | 618 | #ifdef HAVE_LOGIN_CAP |
608 | extern login_cap_t *lc; | 619 | extern login_cap_t *lc; |
609 | #ifdef BSD_AUTH | 620 | #ifdef BSD_AUTH |
@@ -639,11 +650,11 @@ getpwnamallow(const char *user) | |||
639 | } | 650 | } |
640 | #endif | 651 | #endif |
641 | if (pw == NULL) { | 652 | if (pw == NULL) { |
642 | logit("Invalid user %.100s from %.100s", | 653 | logit("Invalid user %.100s from %.100s port %d", |
643 | user, get_remote_ipaddr()); | 654 | user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); |
644 | #ifdef CUSTOM_FAILED_LOGIN | 655 | #ifdef CUSTOM_FAILED_LOGIN |
645 | record_failed_login(user, | 656 | record_failed_login(user, |
646 | get_canonical_hostname(options.use_dns), "ssh"); | 657 | auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); |
647 | #endif | 658 | #endif |
648 | #ifdef SSH_AUDIT_EVENTS | 659 | #ifdef SSH_AUDIT_EVENTS |
649 | audit_event(SSH_INVALID_USER); | 660 | audit_event(SSH_INVALID_USER); |
@@ -773,3 +784,117 @@ fakepw(void) | |||
773 | 784 | ||
774 | return (&fake); | 785 | return (&fake); |
775 | } | 786 | } |
787 | |||
788 | /* | ||
789 | * Returns the remote DNS hostname as a string. The returned string must not | ||
790 | * be freed. NB. this will usually trigger a DNS query the first time it is | ||
791 | * called. | ||
792 | * This function does additional checks on the hostname to mitigate some | ||
793 | * attacks on legacy rhosts-style authentication. | ||
794 | * XXX is RhostsRSAAuthentication vulnerable to these? | ||
795 | * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?) | ||
796 | */ | ||
797 | |||
798 | static char * | ||
799 | remote_hostname(struct ssh *ssh) | ||
800 | { | ||
801 | struct sockaddr_storage from; | ||
802 | socklen_t fromlen; | ||
803 | struct addrinfo hints, *ai, *aitop; | ||
804 | char name[NI_MAXHOST], ntop2[NI_MAXHOST]; | ||
805 | const char *ntop = ssh_remote_ipaddr(ssh); | ||
806 | |||
807 | /* Get IP address of client. */ | ||
808 | fromlen = sizeof(from); | ||
809 | memset(&from, 0, sizeof(from)); | ||
810 | if (getpeername(ssh_packet_get_connection_in(ssh), | ||
811 | (struct sockaddr *)&from, &fromlen) < 0) { | ||
812 | debug("getpeername failed: %.100s", strerror(errno)); | ||
813 | return strdup(ntop); | ||
814 | } | ||
815 | |||
816 | ipv64_normalise_mapped(&from, &fromlen); | ||
817 | if (from.ss_family == AF_INET6) | ||
818 | fromlen = sizeof(struct sockaddr_in6); | ||
819 | |||
820 | debug3("Trying to reverse map address %.100s.", ntop); | ||
821 | /* Map the IP address to a host name. */ | ||
822 | if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), | ||
823 | NULL, 0, NI_NAMEREQD) != 0) { | ||
824 | /* Host name not found. Use ip address. */ | ||
825 | return strdup(ntop); | ||
826 | } | ||
827 | |||
828 | /* | ||
829 | * if reverse lookup result looks like a numeric hostname, | ||
830 | * someone is trying to trick us by PTR record like following: | ||
831 | * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 | ||
832 | */ | ||
833 | memset(&hints, 0, sizeof(hints)); | ||
834 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ | ||
835 | hints.ai_flags = AI_NUMERICHOST; | ||
836 | if (getaddrinfo(name, NULL, &hints, &ai) == 0) { | ||
837 | logit("Nasty PTR record \"%s\" is set up for %s, ignoring", | ||
838 | name, ntop); | ||
839 | freeaddrinfo(ai); | ||
840 | return strdup(ntop); | ||
841 | } | ||
842 | |||
843 | /* Names are stored in lowercase. */ | ||
844 | lowercase(name); | ||
845 | |||
846 | /* | ||
847 | * Map it back to an IP address and check that the given | ||
848 | * address actually is an address of this host. This is | ||
849 | * necessary because anyone with access to a name server can | ||
850 | * define arbitrary names for an IP address. Mapping from | ||
851 | * name to IP address can be trusted better (but can still be | ||
852 | * fooled if the intruder has access to the name server of | ||
853 | * the domain). | ||
854 | */ | ||
855 | memset(&hints, 0, sizeof(hints)); | ||
856 | hints.ai_family = from.ss_family; | ||
857 | hints.ai_socktype = SOCK_STREAM; | ||
858 | if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { | ||
859 | logit("reverse mapping checking getaddrinfo for %.700s " | ||
860 | "[%s] failed.", name, ntop); | ||
861 | return strdup(ntop); | ||
862 | } | ||
863 | /* Look for the address from the list of addresses. */ | ||
864 | for (ai = aitop; ai; ai = ai->ai_next) { | ||
865 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, | ||
866 | sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && | ||
867 | (strcmp(ntop, ntop2) == 0)) | ||
868 | break; | ||
869 | } | ||
870 | freeaddrinfo(aitop); | ||
871 | /* If we reached the end of the list, the address was not there. */ | ||
872 | if (ai == NULL) { | ||
873 | /* Address not found for the host name. */ | ||
874 | logit("Address %.100s maps to %.600s, but this does not " | ||
875 | "map back to the address.", ntop, name); | ||
876 | return strdup(ntop); | ||
877 | } | ||
878 | return strdup(name); | ||
879 | } | ||
880 | |||
881 | /* | ||
882 | * Return the canonical name of the host in the other side of the current | ||
883 | * connection. The host name is cached, so it is efficient to call this | ||
884 | * several times. | ||
885 | */ | ||
886 | |||
887 | const char * | ||
888 | auth_get_canonical_hostname(struct ssh *ssh, int use_dns) | ||
889 | { | ||
890 | static char *dnsname; | ||
891 | |||
892 | if (!use_dns) | ||
893 | return ssh_remote_ipaddr(ssh); | ||
894 | else if (dnsname != NULL) | ||
895 | return dnsname; | ||
896 | else { | ||
897 | dnsname = remote_hostname(ssh); | ||
898 | return dnsname; | ||
899 | } | ||
900 | } | ||