1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netdb.h>
30 #include <netinet/in.h>
31 #include <string.h>
32 #include <syslog.h>
33 #include <addr_match.h>
34
35 /*
36 * Function to compare IP addresses. It walks the list provided in
37 * the res parameter, comparing to the original address in sin or sin6,
38 * with some addition guidance provided by fromp. It returns B_TRUE
39 * if a match is found, otherwise B_FALSE.
40 */
41
42 static boolean_t
find_match(const struct addrinfo * res,const struct sockaddr_storage * fromp,const struct sockaddr_in * sin,const struct sockaddr_in6 * sin6)43 find_match(const struct addrinfo *res,
44 const struct sockaddr_storage *fromp,
45 const struct sockaddr_in *sin,
46 const struct sockaddr_in6 *sin6)
47 {
48 const struct addrinfo *ai;
49
50 /* This is the moral equivalent of an assert. */
51 if ((fromp->ss_family == AF_INET && sin == NULL) ||
52 (fromp->ss_family == AF_INET6 && sin6 == NULL))
53 return (B_FALSE);
54
55 for (ai = res; ai != NULL; ai = ai->ai_next) {
56 struct sockaddr_in *s4;
57 struct sockaddr_in6 *s6;
58 void *addr1, *addr2;
59 size_t size;
60
61 if (ai->ai_family != fromp->ss_family)
62 continue;
63 if (ai->ai_family == AF_INET) {
64 /* LINTED E_BAD_PTR_CAST_ALIGN */
65 s4 = (struct sockaddr_in *)ai->ai_addr;
66 addr1 = &s4->sin_addr;
67 addr2 = &((struct sockaddr_in *)sin)->sin_addr;
68 size = sizeof (struct in_addr);
69 } else if (ai->ai_family == AF_INET6) {
70 /* LINTED E_BAD_PTR_CAST_ALIGN */
71 s6 = (struct sockaddr_in6 *)ai->ai_addr;
72 addr1 = &s6->sin6_addr;
73 addr2 = &((struct sockaddr_in6 *)sin6)->sin6_addr;
74 size = sizeof (struct in6_addr);
75 } else {
76 continue;
77 }
78 if (memcmp(addr1, addr2, size) == 0)
79 return (B_TRUE);
80 }
81 return (B_FALSE);
82 }
83
84 void
check_address(const char * prog,const struct sockaddr_storage * fromp,const struct sockaddr_in * sin,const struct sockaddr_in6 * sin6,const char * printable_addr,char * hostname,size_t hostsize)85 check_address(const char *prog,
86 const struct sockaddr_storage *fromp,
87 const struct sockaddr_in *sin,
88 const struct sockaddr_in6 *sin6,
89 const char *printable_addr,
90 char *hostname,
91 size_t hostsize)
92 {
93 /*
94 * We have to check for spoofing. So take hostname, look up its
95 * address(es), and walk the list until we have a match with the
96 * original IP address. If no match is found, log a warning and
97 * use the original IP address for authentication purposes.
98 */
99 struct addrinfo *res, hints;
100 boolean_t match_found = B_FALSE;
101
102 (void) memset(&hints, 0, sizeof (hints));
103 hints.ai_flags = AI_CANONNAME|AI_V4MAPPED|AI_ADDRCONFIG|AI_ALL;
104 hints.ai_family = fromp->ss_family;
105 if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
106 match_found = find_match(res, fromp, sin, sin6);
107 freeaddrinfo(res);
108 }
109 if (!match_found) {
110 syslog(LOG_WARNING, "%s: IP address '%s' maps to host "
111 "name '%s',\r\n but that host name does not map to "
112 "the same IP address.", prog, printable_addr, hostname);
113 (void) strlcpy(hostname, printable_addr, hostsize);
114 }
115 }
116