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