authreadkeys.c revision 1.1.1.5 1 /*
2 * authreadkeys.c - routines to support the reading of the key file
3 */
4 #include <config.h>
5 #include <stdio.h>
6 #include <ctype.h>
7
8 #include "ntp_fp.h"
9 #include "ntp.h"
10 #include "ntp_syslog.h"
11 #include "ntp_stdlib.h"
12
13 #ifdef OPENSSL
14 #include "openssl/objects.h"
15 #include "openssl/evp.h"
16 #endif /* OPENSSL */
17
18 /* Forwards */
19 static char *nexttok (char **);
20
21 /*
22 * nexttok - basic internal tokenizing routine
23 */
24 static char *
25 nexttok(
26 char **str
27 )
28 {
29 register char *cp;
30 char *starttok;
31
32 cp = *str;
33
34 /*
35 * Space past white space
36 */
37 while (*cp == ' ' || *cp == '\t')
38 cp++;
39
40 /*
41 * Save this and space to end of token
42 */
43 starttok = cp;
44 while (*cp != '\0' && *cp != '\n' && *cp != ' '
45 && *cp != '\t' && *cp != '#')
46 cp++;
47
48 /*
49 * If token length is zero return an error, else set end of
50 * token to zero and return start.
51 */
52 if (starttok == cp)
53 return NULL;
54
55 if (*cp == ' ' || *cp == '\t')
56 *cp++ = '\0';
57 else
58 *cp = '\0';
59
60 *str = cp;
61 return starttok;
62 }
63
64
65 /*
66 * authreadkeys - (re)read keys from a file.
67 */
68 int
69 authreadkeys(
70 const char *file
71 )
72 {
73 FILE *fp;
74 char *line;
75 char *token;
76 keyid_t keyno;
77 int keytype;
78 char buf[512]; /* lots of room for line */
79 u_char keystr[32]; /* Bug 2537 */
80 size_t len;
81 size_t j;
82
83 /*
84 * Open file. Complain and return if it can't be opened.
85 */
86 fp = fopen(file, "r");
87 if (fp == NULL) {
88 msyslog(LOG_ERR, "authreadkeys: file %s: %m",
89 file);
90 return (0);
91 }
92 INIT_SSL();
93
94 /*
95 * Remove all existing keys
96 */
97 auth_delkeys();
98
99 /*
100 * Now read lines from the file, looking for key entries
101 */
102 while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
103 token = nexttok(&line);
104 if (token == NULL)
105 continue;
106
107 /*
108 * First is key number. See if it is okay.
109 */
110 keyno = atoi(token);
111 if (keyno == 0) {
112 msyslog(LOG_ERR,
113 "authreadkeys: cannot change key %s", token);
114 continue;
115 }
116
117 if (keyno > NTP_MAXKEY) {
118 msyslog(LOG_ERR,
119 "authreadkeys: key %s > %d reserved for Autokey",
120 token, NTP_MAXKEY);
121 continue;
122 }
123
124 /*
125 * Next is keytype. See if that is all right.
126 */
127 token = nexttok(&line);
128 if (token == NULL) {
129 msyslog(LOG_ERR,
130 "authreadkeys: no key type for key %d", keyno);
131 continue;
132 }
133 #ifdef OPENSSL
134 /*
135 * The key type is the NID used by the message digest
136 * algorithm. There are a number of inconsistencies in
137 * the OpenSSL database. We attempt to discover them
138 * here and prevent use of inconsistent data later.
139 */
140 keytype = keytype_from_text(token, NULL);
141 if (keytype == 0) {
142 msyslog(LOG_ERR,
143 "authreadkeys: invalid type for key %d", keyno);
144 continue;
145 }
146 if (EVP_get_digestbynid(keytype) == NULL) {
147 msyslog(LOG_ERR,
148 "authreadkeys: no algorithm for key %d", keyno);
149 continue;
150 }
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