authreadkeys.c revision 1.4 1 /* $NetBSD: authreadkeys.c,v 1.4 2014/12/19 20:43:17 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[32]; /* Bug 2537 */
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 <= 20) { /* Bug 2537 */
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