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