]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/libntp/authreadkeys.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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 "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 }