summaryrefslogtreecommitdiff
path: root/libntp/authkeys.c
diff options
context:
space:
mode:
Diffstat (limited to 'libntp/authkeys.c')
-rw-r--r--libntp/authkeys.c126
1 files changed, 114 insertions, 12 deletions
diff --git a/libntp/authkeys.c b/libntp/authkeys.c
index b2ff410cd476..7c1cbb0655ae 100644
--- a/libntp/authkeys.c
+++ b/libntp/authkeys.c
@@ -114,13 +114,16 @@ KeyAccT *cache_keyacclist; /* key access list */
KeyAccT*
keyacc_new_push(
KeyAccT * head,
- const sockaddr_u * addr
+ const sockaddr_u * addr,
+ unsigned int subnetbits
)
{
KeyAccT * node = emalloc(sizeof(KeyAccT));
memcpy(&node->addr, addr, sizeof(sockaddr_u));
+ node->subnetbits = subnetbits;
node->next = head;
+
return node;
}
@@ -165,7 +168,8 @@ keyacc_contains(
{
if (head) {
do {
- if (SOCK_EQ(&head->addr, addr))
+ if (keyacc_amatch(&head->addr, addr,
+ head->subnetbits))
return TRUE;
} while (NULL != (head = head->next));
return FALSE;
@@ -174,6 +178,98 @@ keyacc_contains(
}
}
+#if CHAR_BIT != 8
+# error "don't know how to handle bytes with that bit size"
+#endif
+
+/* ----------------------------------------------------------------- */
+/* check two addresses for a match, taking a prefix length into account
+ * when doing the compare.
+ *
+ * The ISC lib contains a similar function with not entirely specified
+ * semantics, so it seemed somewhat cleaner to do this from scratch.
+ *
+ * Note 1: It *is* assumed that the addresses are stored in network byte
+ * order, that is, most significant byte first!
+ *
+ * Note 2: "no address" compares unequal to all other addresses, even to
+ * itself. This has the same semantics as NaNs have for floats: *any*
+ * relational or equality operation involving a NaN returns FALSE, even
+ * equality with itself. "no address" is either a NULL pointer argument
+ * or an address of type AF_UNSPEC.
+ */
+int/*BOOL*/
+keyacc_amatch(
+ const sockaddr_u * a1,
+ const sockaddr_u * a2,
+ unsigned int mbits
+ )
+{
+ const uint8_t * pm1;
+ const uint8_t * pm2;
+ uint8_t msk;
+ unsigned int len;
+
+ /* 1st check: If any address is not an address, it's inequal. */
+ if ( !a1 || (AF_UNSPEC == AF(a1)) ||
+ !a2 || (AF_UNSPEC == AF(a2)) )
+ return FALSE;
+
+ /* We could check pointers for equality here and shortcut the
+ * other checks if we find object identity. But that use case is
+ * too rare to care for it.
+ */
+
+ /* 2nd check: Address families must be the same. */
+ if (AF(a1) != AF(a2))
+ return FALSE;
+
+ /* type check: address family determines buffer & size */
+ switch (AF(a1)) {
+ case AF_INET:
+ /* IPv4 is easy: clamp size, get byte pointers */
+ if (mbits > sizeof(NSRCADR(a1)) * 8)
+ mbits = sizeof(NSRCADR(a1)) * 8;
+ pm1 = (const void*)&NSRCADR(a1);
+ pm2 = (const void*)&NSRCADR(a2);
+ break;
+
+ case AF_INET6:
+ /* IPv6 is slightly different: Both scopes must match,
+ * too, before we even consider doing a match!
+ */
+ if ( ! SCOPE_EQ(a1, a2))
+ return FALSE;
+ if (mbits > sizeof(NSRCADR6(a1)) * 8)
+ mbits = sizeof(NSRCADR6(a1)) * 8;
+ pm1 = (const void*)&NSRCADR6(a1);
+ pm2 = (const void*)&NSRCADR6(a2);
+ break;
+
+ default:
+ /* don't know how to compare that!?! */
+ return FALSE;
+ }
+
+ /* Split bit length into byte length and partial byte mask.
+ * Note that the byte mask extends from the MSB of a byte down,
+ * and that zero shift (--> mbits % 8 == 0) results in an
+ * all-zero mask.
+ */
+ msk = 0xFFu ^ (0xFFu >> (mbits & 7));
+ len = mbits >> 3;
+
+ /* 3rd check: Do memcmp() over full bytes, if any */
+ if (len && memcmp(pm1, pm2, len))
+ return FALSE;
+
+ /* 4th check: compare last incomplete byte, if any */
+ if (msk && ((pm1[len] ^ pm2[len]) & msk))
+ return FALSE;
+
+ /* If none of the above failed, we're successfully through. */
+ return TRUE;
+}
/*
* init_auth - initialize internal data
@@ -316,6 +412,10 @@ auth_log2(size_t x)
return (u_short)r;
}
+int/*BOOL*/
+ipaddr_match_masked(const sockaddr_u *,const sockaddr_u *,
+ unsigned int mbits);
+
static void
authcache_flush_id(
keyid_t id
@@ -617,20 +717,19 @@ authistrusted(
{
symkey * sk;
- /* That specific key was already used to authenticate the
- * packet. Therefore, the key *must* exist... There's a chance
- * that is not trusted, though.
- */
if (keyno == cache_keyid) {
return (KEY_TRUSTED & cache_flags) &&
keyacc_contains(cache_keyacclist, sau, TRUE);
- } else {
+ }
+
+ if (NULL != (sk = auth_findkey(keyno))) {
authkeyuncached++;
- sk = auth_findkey(keyno);
- INSIST(NULL != sk);
return (KEY_TRUSTED & sk->flags) &&
keyacc_contains(sk->keyacclist, sau, TRUE);
}
+
+ authkeynotfound++;
+ return FALSE;
}
/* Note: There are two locations below where 'strncpy()' is used. While
@@ -795,7 +894,9 @@ authencrypt(
return 0;
}
- return MD5authencrypt(cache_type, cache_secret, pkt, length);
+ return MD5authencrypt(cache_type,
+ cache_secret, cache_secretsize,
+ pkt, length);
}
@@ -822,6 +923,7 @@ authdecrypt(
return FALSE;
}
- return MD5authdecrypt(cache_type, cache_secret, pkt, length,
- size);
+ return MD5authdecrypt(cache_type,
+ cache_secret, cache_secretsize,
+ pkt, length, size);
}