+2002-03-11 Ken Raeburn <raeburn@mit.edu>
+
+ Handle IPv6 sockets that are used to communicate over IPv4, and
+ permit use of non-IPv4 addresses if address checking is turned
+ off:
+ * mk_priv.c (krb4int_address_less): New function. Compares IPv4
+ addresses for ordering, but also handles the IPv6 v4-mapped form.
+ (krb_mk_priv): Use krb4int_address_less. Handle sender/receiver
+ addresses that are IPv6 v4-mapped like IPv4 addresses, or store
+ zero for other addresses.
+ * mk_safe.c (krb_mk_safe): Use krb4int_address_less. Handle
+ sender/receiver addresses that are IPv6 v4-mapped like IPv4
+ addresses, or store zero for other addresses.
+ * rd_priv.c (krb_rd_priv): Use krb4int_address_less. Deal with
+ socket addresses that are v4-mapped IPv6 addresses.
+ * rd_safe.c (krb_rd_safe): Use krb4int_address_less. Deal with
+ socket addresses that are v4-mapped IPv6 addresses.
+
2001-10-09 Ken Raeburn <raeburn@mit.edu>
* cr_tkt.c, decomp_tkt.c, g_in_tkt.c, tf_util.c: Make prototypes
#endif
*/
+/* Utility function:
+
+ Determine order of addresses, if SENDER less than RECEIVER return 1
+ so caller will negate timestamp. Return -1 for failure. */
+int
+krb4int_address_less (struct sockaddr_in *sender, struct sockaddr_in *receiver)
+{
+ unsigned long sender_addr, receiver_addr;
+ unsigned short sender_port, receiver_port;
+ switch (sender->sin_family) {
+ case AF_INET:
+ sender_addr = sender->sin_addr.s_addr;
+ sender_port = sender->sin_port;
+ break;
+#ifdef KRB5_USE_INET6
+ case AF_INET6:
+ struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sender;
+ if (IN6_IS_ADDR_V4MAPPED (s6)) {
+ struct sockaddr_in sintmp = { 0 };
+ memcpy (&sintmp.sin_addr.s_addr,
+ 12+(char*)&s6->sin6_addr.s6_addr,
+ 4);
+ sender_addr = sintmp.sin_addr.s_addr;
+ } else
+ return -1;
+ sender_port = s6->sin6_port;
+ break;
+#endif
+ default:
+ return -1;
+ }
+ switch (receiver->sin_family) {
+ case AF_INET:
+ receiver_addr = receiver->sin_addr.s_addr;
+ receiver_port = receiver->sin_port;
+ break;
+#ifdef KRB5_USE_INET6
+ case AF_INET6:
+ struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) receiver;
+ if (IN6_IS_ADDR_V4MAPPED (s6)) {
+ struct sockaddr_in sintmp = { 0 };
+ memcpy (&sintmp.sin_addr.s_addr,
+ 12+(char*)&s6->sin6_addr.s6_addr,
+ 4);
+ receiver_addr = sintmp.sin_addr.s_addr;
+ } else
+ return -1;
+ receiver_port = s6->sin6_port;
+ break;
+#endif
+ default:
+ return -1;
+ }
+ /* For compatibility with broken old code, compares are done in
+ VAX byte order (LSBFIRST). */
+ if (lsb_net_ulong_less(sender_addr, receiver_addr) == -1
+ || (lsb_net_ulong_less(sender_addr, receiver_addr) == 0
+ && lsb_net_ushort_less(sender_port, receiver_port) == -1))
+ return 1;
+ return 0;
+ /*
+ * all that for one tiny bit! Heaven help those that talk to
+ * themselves.
+ */
+}
+
long KRB5_CALLCONV
krb_mk_priv(in, out, length, schedule, key, sender, receiver)
u_char *in; /* application data */
*p++ = msg_time_5ms;
/* stuff source address */
- memcpy(p, &sender->sin_addr.s_addr,
- sizeof(sender->sin_addr.s_addr));
+ if (sender->sin_family == AF_INET)
+ memcpy(p, &sender->sin_addr.s_addr, sizeof(sender->sin_addr.s_addr));
+#ifdef KRB5_USE_INET6
+ else if (sender->sin_family == AF_INET6
+ && IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr))
+ memcpy(p, 12+(char*)&((struct sockaddr_in6 *)sender)->sin6_addr, 4);
+#endif
+ else
+ /* The address isn't one we can encode in 4 bytes -- but
+ that's okay if the receiver doesn't care. */
+ memset(p, 0, 4);
p += sizeof(sender->sin_addr.s_addr);
/*
* direction bit is the sign bit of the timestamp. Ok
* until 2038??
*/
- /* For compatibility with broken old code, compares are done in VAX
- byte order (LSBFIRST) */
- if (lsb_net_ulong_less(sender->sin_addr.s_addr, /* src < recv */
- receiver->sin_addr.s_addr) == -1)
- msg_time_sec = -msg_time_sec;
- else if (lsb_net_ulong_less(sender->sin_addr.s_addr,
- receiver->sin_addr.s_addr) == 0)
- if (lsb_net_ushort_less(sender->sin_port,
- receiver->sin_port) == -1)
- msg_time_sec = -msg_time_sec;
+ switch (krb4int_address_less (sender, receiver)) {
+ case 1:
+ msg_time_sec = -msg_time_sec;
+ break;
+ case -1:
+ /* Which way should we go in this case? */
+ case 0:
+ break;
+ }
+
/* stuff time sec */
KRB4_PUT32BE(p, msg_time_sec);
*p++ = msg_time_5ms;
/* stuff source address */
- memcpy(p, &sender->sin_addr.s_addr,
- sizeof(sender->sin_addr.s_addr));
+ if (sender->sin_family == AF_INET)
+ memcpy(p, &sender->sin_addr.s_addr, sizeof(sender->sin_addr.s_addr));
+#ifdef KRB5_USE_INET6
+ else if (sender->sin_family == AF_INET6
+ && IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr))
+ memcpy(p, 12+(char*)&((struct sockaddr_in6 *)sender)->sin6_addr, 4);
+#endif
+ else
+ /* The address isn't one we can encode in 4 bytes -- but
+ that's okay if the receiver doesn't care. */
+ memset(p, 0, 4);
p += sizeof(sender->sin_addr.s_addr);
/*
* direction bit is the sign bit of the timestamp. Ok until
* 2038??
*/
- /* For compatibility with broken old code, compares are done in VAX
- byte order (LSBFIRST) */
- if (lsb_net_ulong_less(sender->sin_addr.s_addr, /* src < recv */
- receiver->sin_addr.s_addr) == -1)
- msg_time_sec = -msg_time_sec;
- else if (lsb_net_ulong_less(sender->sin_addr.s_addr,
- receiver->sin_addr.s_addr) == 0)
- if (lsb_net_ushort_less(sender->sin_port,
- receiver->sin_port) == -1)
- msg_time_sec = -msg_time_sec;
- /*
- * all that for one tiny bit! Heaven help those that talk to
- * themselves.
- */
-
+ if (krb4int_address_less (sender, receiver) == 1)
+ msg_time_sec = -msg_time_sec;
/* stuff time sec */
KRB4_PUT32BE(p, msg_time_sec);
/* don't swap, net order always */
p += sizeof(src_addr.s_addr);
- if (!krb_ignore_ip_address
- && src_addr.s_addr != sender->sin_addr.s_addr)
- return RD_AP_MODIFIED;
+ if (!krb_ignore_ip_address) {
+ switch (sender->sin_family) {
+ case AF_INET:
+ if (src_addr.s_addr != sender->sin_addr.s_addr)
+ return RD_AP_MODIFIED;
+ break;
+#ifdef KRB5_USE_INET6
+ case AF_INET6:
+ if (IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr)
+ && !memcmp (&src_addr.s_addr,
+ 12 + (char *) &((struct sockaddr_in6 *)sender)->sin6_addr,
+ 4))
+ break;
+ /* Not v4 mapped? Not ignoring addresses? You lose. */
+ return RD_AP_MODIFIED;
+#endif
+ default:
+ return RD_AP_MODIFIED;
+ }
+ }
/* safely get time_sec */
KRB4_GET32(m_data->time_sec, p, le);
back to the receiver, but most higher level protocols can deal
with that more directly. */
if (krb_ignore_ip_address) {
- if (m_data->time_sec < 0)
- m_data->time_sec = -m_data->time_sec;
- } else if (lsb_net_ulong_less(sender->sin_addr.s_addr,
- receiver->sin_addr.s_addr) == -1)
- /* src < recv */
- m_data->time_sec = -m_data->time_sec;
- else if (lsb_net_ulong_less(sender->sin_addr.s_addr,
- receiver->sin_addr.s_addr) == 0)
- if (lsb_net_ushort_less(sender->sin_port,
- receiver->sin_port) == -1)
- /* src < recv */
+ if (m_data->time_sec < 0)
m_data->time_sec = -m_data->time_sec;
- /*
- * all that for one tiny bit!
- * Heaven help those that talk to themselves.
- */
+ } else
+ switch (krb4int_address_less (sender, receiver)) {
+ case 1:
+ m_data->time_sec = -m_data->time_sec;
+ break;
+ case -1:
+ if (m_data->time_sec < 0)
+ m_data->time_sec = -m_data->time_sec;
+ break;
+ }
/* check the time integrity of the msg */
t_local = TIME_GMT_UNIXSEC;
delta_t = t_local - m_data->time_sec;
if (delta_t < 0)
delta_t = -delta_t; /* Absolute value of difference */
- if (delta_t > CLOCK_SKEW) {
+ if (delta_t > CLOCK_SKEW)
return RD_AP_TIME; /* XXX should probably be better code */
- }
DEB(("\ndelta_t = %d", delta_t));
/*
/* don't swap, net order always */
p += sizeof(src_addr.s_addr);
- if (!krb_ignore_ip_address
- && src_addr.s_addr != sender->sin_addr.s_addr)
- return RD_AP_MODIFIED;
+ if (!krb_ignore_ip_address) {
+ switch (sender->sin_family) {
+ case AF_INET:
+ if (src_addr.s_addr != sender->sin_addr.s_addr)
+ return RD_AP_MODIFIED;
+ break;
+#ifdef KRB5_USE_INET6
+ case AF_INET6:
+ if (IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr)
+ && !memcmp (&src_addr.s_addr,
+ 12 + (char *) &((struct sockaddr_in6 *)sender)->sin6_addr,
+ 4))
+ break;
+ /* Not v4 mapped? Not ignoring addresses? You lose. */
+ return RD_AP_MODIFIED;
+#endif
+ default:
+ return RD_AP_MODIFIED;
+ }
+ }
/* safely get time_sec */
KRB4_GET32(m_data->time_sec, p, le);
back to the receiver, but most higher level protocols can deal
with that more directly. */
if (krb_ignore_ip_address) {
- if (m_data->time_sec <0)
- m_data->time_sec = -m_data->time_sec;
- } else if (lsb_net_ulong_less(sender->sin_addr.s_addr,
- receiver->sin_addr.s_addr)==-1)
- /* src < recv */
- m_data->time_sec = - m_data->time_sec;
- else if (lsb_net_ulong_less(sender->sin_addr.s_addr,
- receiver->sin_addr.s_addr)==0)
- if (lsb_net_ushort_less(sender->sin_port,receiver->sin_port)==-1)
- /* src < recv */
- m_data->time_sec = - m_data->time_sec;
-
- /*
- * All that for one tiny bit! Heaven help those that talk to
- * themselves.
- */
+ if (m_data->time_sec < 0)
+ m_data->time_sec = -m_data->time_sec;
+ } else
+ switch (krb4int_address_less (sender, receiver)) {
+ case 1:
+ m_data->time_sec = -m_data->time_sec;
+ break;
+ case -1:
+ if (m_data->time_sec < 0)
+ m_data->time_sec = -m_data->time_sec;
+ break;
+ }
/* check the time integrity of the msg */
t_local = TIME_GMT_UNIXSEC;