authreadkeys.c revision 285612
1149749Sdes/*
2149749Sdes * authreadkeys.c - routines to support the reading of the key file
3149749Sdes */
4149749Sdes#include <config.h>
5149749Sdes#include <stdio.h>
6149749Sdes#include <ctype.h>
7149749Sdes
8149749Sdes#include "ntp_fp.h"
9149749Sdes#include "ntp.h"
10149749Sdes#include "ntp_syslog.h"
11149749Sdes#include "ntp_stdlib.h"
12149749Sdes
13149749Sdes#ifdef OPENSSL
14149749Sdes#include "openssl/objects.h"
15149749Sdes#include "openssl/evp.h"
16149749Sdes#endif	/* OPENSSL */
17149749Sdes
18149749Sdes/* Forwards */
19149749Sdesstatic char *nexttok (char **);
20149749Sdes
21149749Sdes/*
22149749Sdes * nexttok - basic internal tokenizing routine
23149749Sdes */
24149749Sdesstatic char *
25149749Sdesnexttok(
26149749Sdes	char	**str
27149749Sdes	)
28192595Sdes{
29162852Sdes	register char *cp;
30149749Sdes	char *starttok;
31162852Sdes
32149749Sdes	cp = *str;
33162852Sdes
34162852Sdes	/*
35162852Sdes	 * Space past white space
36162852Sdes	 */
37162852Sdes	while (*cp == ' ' || *cp == '\t')
38162852Sdes		cp++;
39162852Sdes
40149749Sdes	/*
41149749Sdes	 * Save this and space to end of token
42215116Sdes	 */
43162852Sdes	starttok = cp;
44149749Sdes	while (*cp != '\0' && *cp != '\n' && *cp != ' '
45295367Sdes	       && *cp != '\t' && *cp != '#')
46149749Sdes		cp++;
47162852Sdes
48149749Sdes	/*
49162852Sdes	 * If token length is zero return an error, else set end of
50149749Sdes	 * token to zero and return start.
51149749Sdes	 */
52149749Sdes	if (starttok == cp)
53149749Sdes		return NULL;
54149749Sdes
55149749Sdes	if (*cp == ' ' || *cp == '\t')
56149749Sdes		*cp++ = '\0';
57149749Sdes	else
58149749Sdes		*cp = '\0';
59149749Sdes
60149749Sdes	*str = cp;
61149749Sdes	return starttok;
62149749Sdes}
63149749Sdes
64149749Sdes
65149749Sdes/*
66149749Sdes * authreadkeys - (re)read keys from a file.
67149749Sdes */
68149749Sdesint
69149749Sdesauthreadkeys(
70149749Sdes	const char *file
71149749Sdes	)
72149749Sdes{
73149749Sdes	FILE	*fp;
74157016Sdes	char	*line;
75157016Sdes	char	*token;
76157016Sdes	keyid_t	keyno;
77157016Sdes	int	keytype;
78157016Sdes	char	buf[512];		/* lots of room for line */
79157016Sdes	u_char	keystr[32];		/* Bug 2537 */
80157016Sdes	size_t	len;
81157016Sdes	size_t	j;
82149749Sdes
83181111Sdes	/*
84149749Sdes	 * Open file.  Complain and return if it can't be opened.
85149749Sdes	 */
86157016Sdes	fp = fopen(file, "r");
87149749Sdes	if (fp == NULL) {
88149749Sdes		msyslog(LOG_ERR, "authreadkeys: file %s: %m",
89149749Sdes		    file);
90149749Sdes		return (0);
91149749Sdes	}
92149749Sdes	INIT_SSL();
93149749Sdes
94149749Sdes	/*
95149749Sdes	 * Remove all existing keys
96149749Sdes	 */
97149749Sdes	auth_delkeys();
98149749Sdes
99149749Sdes	/*
100149749Sdes	 * Now read lines from the file, looking for key entries
101149749Sdes	 */
102149749Sdes	while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
103149749Sdes		token = nexttok(&line);
104149749Sdes		if (token == NULL)
105149749Sdes			continue;
106149749Sdes
107149749Sdes		/*
108149749Sdes		 * First is key number.  See if it is okay.
109149749Sdes		 */
110149749Sdes		keyno = atoi(token);
111149749Sdes		if (keyno == 0) {
112149749Sdes			msyslog(LOG_ERR,
113149749Sdes			    "authreadkeys: cannot change key %s", token);
114149749Sdes			continue;
115149749Sdes		}
116149749Sdes
117149749Sdes		if (keyno > NTP_MAXKEY) {
118149749Sdes			msyslog(LOG_ERR,
119149749Sdes			    "authreadkeys: key %s > %d reserved for Autokey",
120149749Sdes			    token, NTP_MAXKEY);
121149749Sdes			continue;
122149749Sdes		}
123149749Sdes
124149749Sdes		/*
125149749Sdes		 * Next is keytype. See if that is all right.
126149749Sdes		 */
127149749Sdes		token = nexttok(&line);
128149749Sdes		if (token == NULL) {
129149749Sdes			msyslog(LOG_ERR,
130149749Sdes			    "authreadkeys: no key type for key %d", keyno);
131181111Sdes			continue;
132149749Sdes		}
133149749Sdes#ifdef OPENSSL
134149749Sdes		/*
135149749Sdes		 * The key type is the NID used by the message digest
136149749Sdes		 * algorithm. There are a number of inconsistencies in
137149749Sdes		 * the OpenSSL database. We attempt to discover them
138149749Sdes		 * here and prevent use of inconsistent data later.
139149749Sdes		 */
140149749Sdes		keytype = keytype_from_text(token, NULL);
141149749Sdes		if (keytype == 0) {
142149749Sdes			msyslog(LOG_ERR,
143149749Sdes			    "authreadkeys: invalid type for key %d", keyno);
144149749Sdes			continue;
145149749Sdes		}
146149749Sdes		if (EVP_get_digestbynid(keytype) == NULL) {
147149749Sdes			msyslog(LOG_ERR,
148181111Sdes			    "authreadkeys: no algorithm for key %d", keyno);
149192595Sdes			continue;
150149749Sdes		}
151#else	/* !OPENSSL follows */
152
153		/*
154		 * The key type is unused, but is required to be 'M' or
155		 * 'm' for compatibility.
156		 */
157		if (!(*token == 'M' || *token == 'm')) {
158			msyslog(LOG_ERR,
159			    "authreadkeys: invalid type for key %d", keyno);
160			continue;
161		}
162		keytype = KEY_TYPE_MD5;
163#endif	/* !OPENSSL */
164
165		/*
166		 * Finally, get key and insert it. If it is longer than 20
167		 * characters, it is a binary string encoded in hex;
168		 * otherwise, it is a text string of printable ASCII
169		 * characters.
170		 */
171		token = nexttok(&line);
172		if (token == NULL) {
173			msyslog(LOG_ERR,
174			    "authreadkeys: no key for key %d", keyno);
175			continue;
176		}
177		len = strlen(token);
178		if (len <= 20) {	/* Bug 2537 */
179			MD5auth_setkey(keyno, keytype, (u_char *)token, len);
180		} else {
181			char	hex[] = "0123456789abcdef";
182			u_char	temp;
183			char	*ptr;
184			size_t	jlim;
185
186			jlim = min(len, 2 * sizeof(keystr));
187			for (j = 0; j < jlim; j++) {
188				ptr = strchr(hex, tolower((unsigned char)token[j]));
189				if (ptr == NULL)
190					break;	/* abort decoding */
191				temp = (u_char)(ptr - hex);
192				if (j & 1)
193					keystr[j / 2] |= temp;
194				else
195					keystr[j / 2] = temp << 4;
196			}
197			if (j < jlim) {
198				msyslog(LOG_ERR,
199					"authreadkeys: invalid hex digit for key %d", keyno);
200				continue;
201			}
202			MD5auth_setkey(keyno, keytype, keystr, jlim / 2);
203		}
204	}
205	fclose(fp);
206	return (1);
207}
208