]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/libntp/authreadkeys.c
Update ntpd to 4.2.8p13 to fix authenticated denial of service.
[FreeBSD/FreeBSD.git] / contrib / ntp / libntp / authreadkeys.c
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 "ntpd.h"     /* Only for DPRINTF */
9 //#include "ntp_fp.h"
10 #include "ntp.h"
11 #include "ntp_syslog.h"
12 #include "ntp_stdlib.h"
13 #include "ntp_keyacc.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 /* TALOS-CAN-0055: possibly DoS attack by setting the key file to the
68  * log file. This is hard to prevent (it would need to check two files
69  * to be the same on the inode level, which will not work so easily with
70  * Windows or VMS) but we can avoid the self-amplification loop: We only
71  * log the first 5 errors, silently ignore the next 10 errors, and give
72  * up when when we have found more than 15 errors.
73  *
74  * This avoids the endless file iteration we will end up with otherwise,
75  * and also avoids overflowing the log file.
76  *
77  * Nevertheless, once this happens, the keys are gone since this would
78  * require a save/swap strategy that is not easy to apply due to the
79  * data on global/static level.
80  */
81
82 static const u_int nerr_loglimit = 5u;
83 static const u_int nerr_maxlimit = 15;
84
85 static void log_maybe(u_int*, const char*, ...) NTP_PRINTF(2, 3);
86
87 typedef struct keydata KeyDataT;
88 struct keydata {
89         KeyDataT *next;         /* queue/stack link             */
90         KeyAccT  *keyacclist;   /* key access list              */
91         keyid_t   keyid;        /* stored key ID                */
92         u_short   keytype;      /* stored key type              */
93         u_short   seclen;       /* length of secret             */
94         u_char    secbuf[1];    /* begin of secret (formal only)*/
95 };
96
97 static void
98 log_maybe(
99         u_int      *pnerr,
100         const char *fmt  ,
101         ...)
102 {
103         va_list ap;
104         if ((NULL == pnerr) || (++(*pnerr) <= nerr_loglimit)) {
105                 va_start(ap, fmt);
106                 mvsyslog(LOG_ERR, fmt, ap);
107                 va_end(ap);
108         }
109 }
110
111 static void
112 free_keydata(
113         KeyDataT *node
114         )
115 {
116         KeyAccT *kap;
117         
118         if (node) {
119                 while (node->keyacclist) {
120                         kap = node->keyacclist;
121                         node->keyacclist = kap->next;
122                         free(kap);
123                 }
124
125                 /* purge secrets from memory before free()ing it */
126                 memset(node, 0, sizeof(*node) + node->seclen);
127                 free(node);
128         }
129 }
130
131 /*
132  * authreadkeys - (re)read keys from a file.
133  */
134 int
135 authreadkeys(
136         const char *file
137         )
138 {
139         FILE    *fp;
140         char    *line;
141         char    *token;
142         keyid_t keyno;
143         int     keytype;
144         char    buf[512];               /* lots of room for line */
145         u_char  keystr[32];             /* Bug 2537 */
146         size_t  len;
147         size_t  j;
148         u_int   nerr;
149         KeyDataT *list = NULL;
150         KeyDataT *next = NULL;
151
152         /*
153          * Open file.  Complain and return if it can't be opened.
154          */
155         fp = fopen(file, "r");
156         if (fp == NULL) {
157                 msyslog(LOG_ERR, "authreadkeys: file '%s': %m",
158                     file);
159                 goto onerror;
160         }
161         INIT_SSL();
162
163         /*
164          * Now read lines from the file, looking for key entries. Put
165          * the data into temporary store for later propagation to avoid
166          * two-pass processing.
167          */
168         nerr = 0;
169         while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
170                 if (nerr > nerr_maxlimit)
171                         break;
172                 token = nexttok(&line);
173                 if (token == NULL)
174                         continue;
175                 
176                 /*
177                  * First is key number.  See if it is okay.
178                  */
179                 keyno = atoi(token);
180                 if (keyno < 1) {
181                         log_maybe(&nerr,
182                                   "authreadkeys: cannot change key %s",
183                                   token);
184                         continue;
185                 }
186
187                 if (keyno > NTP_MAXKEY) {
188                         log_maybe(&nerr,
189                                   "authreadkeys: key %s > %d reserved for Autokey",
190                                   token, NTP_MAXKEY);
191                         continue;
192                 }
193
194                 /*
195                  * Next is keytype. See if that is all right.
196                  */
197                 token = nexttok(&line);
198                 if (token == NULL) {
199                         log_maybe(&nerr,
200                                   "authreadkeys: no key type for key %d",
201                                   keyno);
202                         continue;
203                 }
204
205                 /* We want to silently ignore keys where we do not
206                  * support the requested digest type. OTOH, we want to
207                  * make sure the file is well-formed.  That means we
208                  * have to process the line completely and have to
209                  * finally throw away the result... This is a bit more
210                  * work, but it also results in better error detection.
211                  */ 
212 #ifdef OPENSSL
213                 /*
214                  * The key type is the NID used by the message digest 
215                  * algorithm. There are a number of inconsistencies in
216                  * the OpenSSL database. We attempt to discover them
217                  * here and prevent use of inconsistent data later.
218                  */
219                 keytype = keytype_from_text(token, NULL);
220                 if (keytype == 0) {
221                         log_maybe(NULL,
222                                   "authreadkeys: invalid type for key %d",
223                                   keyno);
224 #  ifdef ENABLE_CMAC
225                 } else if (NID_cmac != keytype &&
226                                 EVP_get_digestbynid(keytype) == NULL) {
227                         log_maybe(NULL,
228                                   "authreadkeys: no algorithm for key %d",
229                                   keyno);
230                         keytype = 0;
231 #  endif /* ENABLE_CMAC */
232                 }
233 #else   /* !OPENSSL follows */
234                 /*
235                  * The key type is unused, but is required to be 'M' or
236                  * 'm' for compatibility.
237                  */
238                 if (!(*token == 'M' || *token == 'm')) {
239                         log_maybe(NULL,
240                                   "authreadkeys: invalid type for key %d",
241                                   keyno);
242                         keytype = 0;
243                 } else {
244                         keytype = KEY_TYPE_MD5;
245                 }
246 #endif  /* !OPENSSL */
247
248                 /*
249                  * Finally, get key and insert it. If it is longer than 20
250                  * characters, it is a binary string encoded in hex;
251                  * otherwise, it is a text string of printable ASCII
252                  * characters.
253                  */
254                 token = nexttok(&line);
255                 if (token == NULL) {
256                         log_maybe(&nerr,
257                                   "authreadkeys: no key for key %d", keyno);
258                         continue;
259                 }
260                 next = NULL;
261                 len = strlen(token);
262                 if (len <= 20) {        /* Bug 2537 */
263                         next = emalloc(sizeof(KeyDataT) + len);
264                         next->keyacclist = NULL;
265                         next->keyid   = keyno;
266                         next->keytype = keytype;
267                         next->seclen  = len;
268                         memcpy(next->secbuf, token, len);
269                 } else {
270                         static const char hex[] = "0123456789abcdef";
271                         u_char  temp;
272                         char    *ptr;
273                         size_t  jlim;
274
275                         jlim = min(len, 2 * sizeof(keystr));
276                         for (j = 0; j < jlim; j++) {
277                                 ptr = strchr(hex, tolower((unsigned char)token[j]));
278                                 if (ptr == NULL)
279                                         break;  /* abort decoding */
280                                 temp = (u_char)(ptr - hex);
281                                 if (j & 1)
282                                         keystr[j / 2] |= temp;
283                                 else
284                                         keystr[j / 2] = temp << 4;
285                         }
286                         if (j < jlim) {
287                                 log_maybe(&nerr,
288                                           "authreadkeys: invalid hex digit for key %d",
289                                           keyno);
290                                 continue;
291                         }
292                         len = jlim/2; /* hmmmm.... what about odd length?!? */
293                         next = emalloc(sizeof(KeyDataT) + len);
294                         next->keyacclist = NULL;
295                         next->keyid   = keyno;
296                         next->keytype = keytype;
297                         next->seclen  = len;
298                         memcpy(next->secbuf, keystr, len);
299                 }
300
301                 token = nexttok(&line);
302                 if (token != NULL) {    /* A comma-separated IP access list */
303                         char *tp = token;
304
305                         while (tp) {
306                                 char *i;
307                                 char *snp;      /* subnet text pointer */
308                                 unsigned int snbits;
309                                 sockaddr_u addr;
310
311                                 i = strchr(tp, (int)',');
312                                 if (i) {
313                                         *i = '\0';
314                                 }
315                                 snp = strchr(tp, (int)'/');
316                                 if (snp) {
317                                         char *sp;
318
319                                         *snp++ = '\0';
320                                         snbits = 0;
321                                         sp = snp;
322
323                                         while (*sp != '\0') {
324                                                 if (!isdigit((unsigned char)*sp))
325                                                     break;
326                                                 if (snbits > 1000)
327                                                     break;      /* overflow */
328                                                 snbits = 10 * snbits + (*sp++ - '0');       /* ascii dependent */
329                                         }
330                                         if (*sp != '\0') {
331                                                 log_maybe(&nerr,
332                                                           "authreadkeys: Invalid character in subnet specification for <%s/%s> in key %d",
333                                                           sp, snp, keyno);
334                                                 goto nextip;
335                                         }
336                                 } else {
337                                         snbits = UINT_MAX;
338                                 }
339
340                                 if (is_ip_address(tp, AF_UNSPEC, &addr)) {
341                                         /* Make sure that snbits is valid for addr */
342                                     if ((snbits < UINT_MAX) &&
343                                         ( (IS_IPV4(&addr) && snbits > 32) ||
344                                           (IS_IPV6(&addr) && snbits > 128))) {
345                                                 log_maybe(NULL,
346                                                           "authreadkeys: excessive subnet mask <%s/%s> for key %d",
347                                                           tp, snp, keyno);
348                                     }
349                                     next->keyacclist = keyacc_new_push(
350                                         next->keyacclist, &addr, snbits);
351                                 } else {
352                                         log_maybe(&nerr,
353                                                   "authreadkeys: invalid IP address <%s> for key %d",
354                                                   tp, keyno);
355                                 }
356
357                         nextip:
358                                 if (i) {
359                                         tp = i + 1;
360                                 } else {
361                                         tp = 0;
362                                 }
363                         }
364                 }
365
366                 /* check if this has to be weeded out... */
367                 if (0 == keytype) {
368                         free_keydata(next);
369                         next = NULL;
370                         continue;
371                 }
372                 
373                 INSIST(NULL != next);
374                 next->next = list;
375                 list = next;
376         }
377         fclose(fp);
378         if (nerr > 0) {
379                 const char * why = "";
380                 if (nerr > nerr_maxlimit)
381                         why = " (emergency break)";
382                 msyslog(LOG_ERR,
383                         "authreadkeys: rejecting file '%s' after %u error(s)%s",
384                         file, nerr, why);
385                 goto onerror;
386         }
387
388         /* first remove old file-based keys */
389         auth_delkeys();
390         /* insert the new key material */
391         while (NULL != (next = list)) {
392                 list = next->next;
393                 MD5auth_setkey(next->keyid, next->keytype,
394                                next->secbuf, next->seclen, next->keyacclist);
395                 next->keyacclist = NULL; /* consumed by MD5auth_setkey */
396                 free_keydata(next);
397         }
398         return (1);
399
400   onerror:
401         /* Mop up temporary storage before bailing out. */
402         while (NULL != (next = list)) {
403                 list = next->next;
404                 free_keydata(next);
405         }
406         return (0);
407 }