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