#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include "ntp_types.h"
#include "ntp_fp.h"
#include "ntp.h"
#include "ntpd.h"
#include "ntp_string.h"
#include "ntp_malloc.h"
#include "ntp_stdlib.h"
struct savekey {
struct savekey *next;
union {
u_char MD5_key[64];
} k;
keyid_t keyid;
int type;
u_short flags;
u_long lifetime;
int keylen;
};
#define KEY_TRUSTED 0x001
#define HASHSIZE 64
#define HASHMASK ((HASHSIZE)-1)
#define KEYHASH(keyid) ((keyid) & HASHMASK)
struct savekey *key_hash[HASHSIZE];
u_long authkeynotfound;
u_long authkeylookups;
u_long authnumkeys;
u_long authkeyexpired;
u_long authkeyuncached;
u_long authnokey;
u_long authencryptions;
u_long authdecryptions;
struct savekey *authfreekeys;
int authnumfreekeys;
#define MEMINC 12
keyid_t cache_keyid;
u_char *cache_key;
u_int cache_keylen;
int cache_type;
u_short cache_flags;
void
init_auth(void)
{
memset((char *)key_hash, 0, sizeof key_hash);
}
struct savekey *
auth_findkey(
keyid_t keyno
)
{
struct savekey *sk;
sk = key_hash[KEYHASH(keyno)];
while (sk != 0) {
if (keyno == sk->keyid)
return (sk);
sk = sk->next;
}
return (0);
}
int
auth_havekey(
keyid_t keyno
)
{
struct savekey *sk;
if (keyno == 0 || (keyno == cache_keyid))
return (1);
sk = key_hash[KEYHASH(keyno)];
while (sk != 0) {
if (keyno == sk->keyid)
return (1);
sk = sk->next;
}
return (0);
}
int
authhavekey(
keyid_t keyno
)
{
struct savekey *sk;
authkeylookups++;
if (keyno == 0 || keyno == cache_keyid)
return (1);
authkeyuncached++;
sk = key_hash[KEYHASH(keyno)];
while (sk != NULL) {
if (keyno == sk->keyid) {
if (sk->type == 0) {
authkeynotfound++;
return (0);
}
break;
}
sk = sk->next;
}
if (sk == NULL) {
authkeynotfound++;
return (0);
}
if (!(sk->flags & KEY_TRUSTED)) {
authnokey++;
return (0);
}
cache_keyid = sk->keyid;
cache_type = sk->type;
cache_flags = sk->flags;
cache_key = sk->k.MD5_key;
cache_keylen = sk->keylen;
return (1);
}
int
auth_moremem(void)
{
struct savekey *sk;
int i;
sk = (struct savekey *)calloc(MEMINC, sizeof(struct savekey));
if (sk == 0)
return (0);
for (i = MEMINC; i > 0; i--) {
sk->next = authfreekeys;
authfreekeys = sk++;
}
authnumfreekeys += MEMINC;
return (authnumfreekeys);
}
void
authtrust(
keyid_t keyno,
u_long trust
)
{
struct savekey *sk;
sk = key_hash[KEYHASH(keyno)];
while (sk != 0) {
if (keyno == sk->keyid)
break;
sk = sk->next;
}
if (sk == 0 && !trust)
return;
if (sk != 0) {
if (cache_keyid == keyno) {
cache_flags = 0;
cache_keyid = 0;
}
if (trust > 0) {
sk->flags |= KEY_TRUSTED;
if (trust > 1)
sk->lifetime = current_time + trust;
else
sk->lifetime = 0;
return;
}
sk->flags &= ~KEY_TRUSTED; {
struct savekey *skp;
skp = key_hash[KEYHASH(keyno)];
if (skp == sk) {
key_hash[KEYHASH(keyno)] = sk->next;
} else {
while (skp->next != sk)
skp = skp->next;
skp->next = sk->next;
}
authnumkeys--;
sk->next = authfreekeys;
authfreekeys = sk;
authnumfreekeys++;
}
return;
}
if (authnumfreekeys == 0)
if (auth_moremem() == 0)
return;
sk = authfreekeys;
authfreekeys = sk->next;
authnumfreekeys--;
sk->keyid = keyno;
sk->type = 0;
sk->keylen = 0;
sk->flags = KEY_TRUSTED;
sk->next = key_hash[KEYHASH(keyno)];
key_hash[KEYHASH(keyno)] = sk;
authnumkeys++;
return;
}
int
authistrusted(
keyid_t keyno
)
{
struct savekey *sk;
if (keyno == cache_keyid)
return ((cache_flags & KEY_TRUSTED) != 0);
authkeyuncached++;
sk = key_hash[KEYHASH(keyno)];
while (sk != 0) {
if (keyno == sk->keyid)
break;
sk = sk->next;
}
if (sk == 0) {
authkeynotfound++;
return (0);
} else if (!(sk->flags & KEY_TRUSTED)) {
authkeynotfound++;
return (0);
}
return (1);
}
void
MD5auth_setkey(
keyid_t keyno,
int keytype,
const u_char *key,
const int len
)
{
struct savekey *sk;
sk = key_hash[KEYHASH(keyno)];
while (sk != NULL) {
if (keyno == sk->keyid) {
sk->type = keytype;
sk->keylen = min(len, sizeof(sk->k.MD5_key));
#ifndef DISABLE_BUG1243_FIX
memcpy(sk->k.MD5_key, key, sk->keylen);
#else
strncpy((char *)sk->k.MD5_key, (const char *)key,
sizeof(sk->k.MD5_key));
#endif
if (cache_keyid == keyno) {
cache_flags = 0;
cache_keyid = 0;
}
return;
}
sk = sk->next;
}
if (0 == authnumfreekeys && !auth_moremem())
return;
sk = authfreekeys;
authfreekeys = sk->next;
authnumfreekeys--;
sk->keyid = keyno;
sk->type = keytype;
sk->flags = 0;
sk->lifetime = 0;
sk->keylen = min(len, sizeof(sk->k.MD5_key));
#ifndef DISABLE_BUG1243_FIX
memcpy(sk->k.MD5_key, key, sk->keylen);
#else
strncpy((char *)sk->k.MD5_key, (const char *)key,
sizeof(sk->k.MD5_key));
#endif
sk->next = key_hash[KEYHASH(keyno)];
key_hash[KEYHASH(keyno)] = sk;
#ifdef DEBUG
if (debug > 1) {
char hex[] = "0123456789abcdef";
int j;
printf("auth_setkey: key %d type %d len %d ", sk->keyid,
sk->type, sk->keylen);
for (j = 0; j < sk->keylen; j++)
printf("%c%c", hex[key[j] >> 4],
hex[key[j] & 0xf]);
printf("\n");
}
#endif
authnumkeys++;
}
void
auth_delkeys(void)
{
struct savekey *sk;
struct savekey **skp;
int i;
for (i = 0; i < HASHSIZE; i++) {
skp = &(key_hash[i]);
sk = key_hash[i];
while (sk != 0 && sk->keyid <= NTP_MAXKEY) {
if (sk->flags & KEY_TRUSTED) {
skp = &(sk->next);
memset(&sk->k, 0, sizeof(sk->k));
sk->lifetime = 0;
sk->keylen = 0;
sk = sk->next;
} else {
*skp = sk->next;
authnumkeys--;
sk->next = authfreekeys;
authfreekeys = sk;
authnumfreekeys++;
sk = *skp;
}
}
}
}
void
auth_agekeys(void)
{
struct savekey *sk;
struct savekey *skp;
int i;
for (i = 0; i < HASHSIZE; i++) {
sk = skp = key_hash[i];
while (sk != 0) {
skp = sk->next;
if (sk->lifetime > 0 && current_time >
sk->lifetime) {
authtrust(sk->keyid, 0);
authkeyexpired++;
}
sk = skp;
}
}
#ifdef DEBUG
if (debug)
printf("auth_agekeys: at %lu keys %lu expired %lu\n",
current_time, authnumkeys, authkeyexpired);
#endif
}
int
authencrypt(
keyid_t keyno,
u_int32 *pkt,
int length
)
{
authencryptions++;
pkt[length / 4] = htonl(keyno);
if (keyno == 0) {
return (4);
}
if (!authhavekey(keyno))
return (0);
return (MD5authencrypt(cache_type, cache_key, pkt, length));
}
int
authdecrypt(
keyid_t keyno,
u_int32 *pkt,
int length,
int size
)
{
authdecryptions++;
if (keyno == 0)
return (0);
if (!authhavekey(keyno) || size < 4)
return (0);
return (MD5authdecrypt(cache_type, cache_key, pkt, length,
size));
}