freebsd-nq/libntp/authreadkeys.c
Ollivier Robert 2b45e011ca Virgin import of ntpd 4.2.6p5.
When the series of commits is complete, things like
https://cert.litnet.lt/en/docs/ntp-distributed-reflection-dos-attacks
should be fixed.

PR:		bin/148836 (except that we import a newer version)
Asked by:	Too many
MFC after:	2 weeks
2013-12-04 21:33:17 +00:00

205 lines
3.9 KiB
C

/*
* authreadkeys.c - routines to support the reading of the key file
*/
#include <config.h>
#include <stdio.h>
#include <ctype.h>
#include "ntp_fp.h"
#include "ntp.h"
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
#ifdef OPENSSL
#include "openssl/objects.h"
#endif /* OPENSSL */
/* Forwards */
static char *nexttok (char **);
/*
* nexttok - basic internal tokenizing routine
*/
static char *
nexttok(
char **str
)
{
register char *cp;
char *starttok;
cp = *str;
/*
* Space past white space
*/
while (*cp == ' ' || *cp == '\t')
cp++;
/*
* Save this and space to end of token
*/
starttok = cp;
while (*cp != '\0' && *cp != '\n' && *cp != ' '
&& *cp != '\t' && *cp != '#')
cp++;
/*
* If token length is zero return an error, else set end of
* token to zero and return start.
*/
if (starttok == cp)
return (NULL);
if (*cp == ' ' || *cp == '\t')
*cp++ = '\0';
else
*cp = '\0';
*str = cp;
return starttok;
}
/*
* authreadkeys - (re)read keys from a file.
*/
int
authreadkeys(
const char *file
)
{
FILE *fp;
char *line;
char *token;
keyid_t keyno;
int keytype;
char buf[512]; /* lots of room for line */
u_char keystr[20];
int len;
int j;
/*
* Open file. Complain and return if it can't be opened.
*/
fp = fopen(file, "r");
if (fp == NULL) {
msyslog(LOG_ERR, "authreadkeys: file %s: %m",
file);
return (0);
}
INIT_SSL();
/*
* Remove all existing keys
*/
auth_delkeys();
/*
* Now read lines from the file, looking for key entries
*/
while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
token = nexttok(&line);
if (token == NULL)
continue;
/*
* First is key number. See if it is okay.
*/
keyno = atoi(token);
if (keyno == 0) {
msyslog(LOG_ERR,
"authreadkeys: cannot change key %s", token);
continue;
}
if (keyno > NTP_MAXKEY) {
msyslog(LOG_ERR,
"authreadkeys: key %s > %d reserved for Autokey",
token, NTP_MAXKEY);
continue;
}
/*
* Next is keytype. See if that is all right.
*/
token = nexttok(&line);
if (token == NULL) {
msyslog(LOG_ERR,
"authreadkeys: no key type for key %d", keyno);
continue;
}
#ifdef OPENSSL
/*
* The key type is the NID used by the message digest
* algorithm. There are a number of inconsistencies in
* the OpenSSL database. We attempt to discover them
* here and prevent use of inconsistent data later.
*/
keytype = keytype_from_text(token, NULL);
if (keytype == 0) {
msyslog(LOG_ERR,
"authreadkeys: invalid type for key %d", keyno);
continue;
}
if (EVP_get_digestbynid(keytype) == NULL) {
msyslog(LOG_ERR,
"authreadkeys: no algorithm for key %d", keyno);
continue;
}
#else /* OPENSSL */
/*
* The key type is unused, but is required to be 'M' or
* 'm' for compatibility.
*/
if (!(*token == 'M' || *token == 'm')) {
msyslog(LOG_ERR,
"authreadkeys: invalid type for key %d", keyno);
continue;
}
keytype = KEY_TYPE_MD5;
#endif /* OPENSSL */
/*
* Finally, get key and insert it. If it is longer than 20
* characters, it is a binary string encoded in hex;
* otherwise, it is a text string of printable ASCII
* characters.
*/
token = nexttok(&line);
if (token == NULL) {
msyslog(LOG_ERR,
"authreadkeys: no key for key %d", keyno);
continue;
}
len = strlen(token);
if (len <= 20) {
MD5auth_setkey(keyno, keytype, (u_char *)token, len);
} else {
char hex[] = "0123456789abcdef";
u_char temp;
char *ptr;
int jlim;
jlim = min(len, 2 * sizeof(keystr));
for (j = 0; j < jlim; j++) {
ptr = strchr(hex, tolower(token[j]));
if (ptr == NULL) {
msyslog(LOG_ERR,
"authreadkeys: invalid hex digit for key %d", keyno);
continue;
}
temp = (u_char)(ptr - hex);
if (j & 1)
keystr[j / 2] |= temp;
else
keystr[j / 2] = temp << 4;
}
MD5auth_setkey(keyno, keytype, keystr, jlim / 2);
}
}
fclose(fp);
return (1);
}