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