xref: /netbsd-src/external/bsd/ntp/dist/libntp/authreadkeys.c (revision 80d9064ac03cbb6a4174695f0d5b237c8766d3d0)
1 /*	$NetBSD: authreadkeys.c,v 1.3 2013/12/28 03:20:13 christos Exp $	*/
2 
3 /*
4  * authreadkeys.c - routines to support the reading of the key file
5  */
6 #include <config.h>
7 #include <stdio.h>
8 #include <ctype.h>
9 
10 #include "ntp_fp.h"
11 #include "ntp.h"
12 #include "ntp_syslog.h"
13 #include "ntp_stdlib.h"
14 
15 #ifdef OPENSSL
16 #include "openssl/objects.h"
17 #include "openssl/evp.h"
18 #endif	/* OPENSSL */
19 
20 /* Forwards */
21 static char *nexttok (char **);
22 
23 /*
24  * nexttok - basic internal tokenizing routine
25  */
26 static char *
27 nexttok(
28 	char	**str
29 	)
30 {
31 	register char *cp;
32 	char *starttok;
33 
34 	cp = *str;
35 
36 	/*
37 	 * Space past white space
38 	 */
39 	while (*cp == ' ' || *cp == '\t')
40 		cp++;
41 
42 	/*
43 	 * Save this and space to end of token
44 	 */
45 	starttok = cp;
46 	while (*cp != '\0' && *cp != '\n' && *cp != ' '
47 	       && *cp != '\t' && *cp != '#')
48 		cp++;
49 
50 	/*
51 	 * If token length is zero return an error, else set end of
52 	 * token to zero and return start.
53 	 */
54 	if (starttok == cp)
55 		return NULL;
56 
57 	if (*cp == ' ' || *cp == '\t')
58 		*cp++ = '\0';
59 	else
60 		*cp = '\0';
61 
62 	*str = cp;
63 	return starttok;
64 }
65 
66 
67 /*
68  * authreadkeys - (re)read keys from a file.
69  */
70 int
71 authreadkeys(
72 	const char *file
73 	)
74 {
75 	FILE	*fp;
76 	char	*line;
77 	char	*token;
78 	keyid_t	keyno;
79 	int	keytype;
80 	char	buf[512];		/* lots of room for line */
81 	u_char	keystr[20];
82 	size_t	len;
83 	size_t	j;
84 
85 	/*
86 	 * Open file.  Complain and return if it can't be opened.
87 	 */
88 	fp = fopen(file, "r");
89 	if (fp == NULL) {
90 		msyslog(LOG_ERR, "authreadkeys: file %s: %m",
91 		    file);
92 		return (0);
93 	}
94 	INIT_SSL();
95 
96 	/*
97 	 * Remove all existing keys
98 	 */
99 	auth_delkeys();
100 
101 	/*
102 	 * Now read lines from the file, looking for key entries
103 	 */
104 	while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
105 		token = nexttok(&line);
106 		if (token == NULL)
107 			continue;
108 
109 		/*
110 		 * First is key number.  See if it is okay.
111 		 */
112 		keyno = atoi(token);
113 		if (keyno == 0) {
114 			msyslog(LOG_ERR,
115 			    "authreadkeys: cannot change key %s", token);
116 			continue;
117 		}
118 
119 		if (keyno > NTP_MAXKEY) {
120 			msyslog(LOG_ERR,
121 			    "authreadkeys: key %s > %d reserved for Autokey",
122 			    token, NTP_MAXKEY);
123 			continue;
124 		}
125 
126 		/*
127 		 * Next is keytype. See if that is all right.
128 		 */
129 		token = nexttok(&line);
130 		if (token == NULL) {
131 			msyslog(LOG_ERR,
132 			    "authreadkeys: no key type for key %d", keyno);
133 			continue;
134 		}
135 #ifdef OPENSSL
136 		/*
137 		 * The key type is the NID used by the message digest
138 		 * algorithm. There are a number of inconsistencies in
139 		 * the OpenSSL database. We attempt to discover them
140 		 * here and prevent use of inconsistent data later.
141 		 */
142 		keytype = keytype_from_text(token, NULL);
143 		if (keytype == 0) {
144 			msyslog(LOG_ERR,
145 			    "authreadkeys: invalid type for key %d", keyno);
146 			continue;
147 		}
148 		if (EVP_get_digestbynid(keytype) == NULL) {
149 			msyslog(LOG_ERR,
150 			    "authreadkeys: no algorithm for key %d", keyno);
151 			continue;
152 		}
153 #else	/* !OPENSSL follows */
154 
155 		/*
156 		 * The key type is unused, but is required to be 'M' or
157 		 * 'm' for compatibility.
158 		 */
159 		if (!(*token == 'M' || *token == 'm')) {
160 			msyslog(LOG_ERR,
161 			    "authreadkeys: invalid type for key %d", keyno);
162 			continue;
163 		}
164 		keytype = KEY_TYPE_MD5;
165 #endif	/* !OPENSSL */
166 
167 		/*
168 		 * Finally, get key and insert it. If it is longer than 20
169 		 * characters, it is a binary string encoded in hex;
170 		 * otherwise, it is a text string of printable ASCII
171 		 * characters.
172 		 */
173 		token = nexttok(&line);
174 		if (token == NULL) {
175 			msyslog(LOG_ERR,
176 			    "authreadkeys: no key for key %d", keyno);
177 			continue;
178 		}
179 		len = strlen(token);
180 		if (len <= sizeof(keystr)) {
181 			MD5auth_setkey(keyno, keytype, (u_char *)token, len);
182 		} else {
183 			char	hex[] = "0123456789abcdef";
184 			u_char	temp;
185 			char	*ptr;
186 			size_t	jlim;
187 
188 			jlim = min(len, 2 * sizeof(keystr));
189 			for (j = 0; j < jlim; j++) {
190 				ptr = strchr(hex, tolower((unsigned char)token[j]));
191 				if (ptr == NULL)
192 					break;	/* abort decoding */
193 				temp = (u_char)(ptr - hex);
194 				if (j & 1)
195 					keystr[j / 2] |= temp;
196 				else
197 					keystr[j / 2] = temp << 4;
198 			}
199 			if (j < jlim) {
200 				msyslog(LOG_ERR,
201 					"authreadkeys: invalid hex digit for key %d", keyno);
202 				continue;
203 			}
204 			MD5auth_setkey(keyno, keytype, keystr, jlim / 2);
205 		}
206 	}
207 	fclose(fp);
208 	return (1);
209 }
210