1 /* $NetBSD: authreadkeys.c,v 1.3 2013/12/28 03:20:13 christos Exp $ */ 2 3 /* 4 * authreadkeys.c - routines to support the reading of the key file 5 */ 6 #include <config.h> 7 #include <stdio.h> 8 #include <ctype.h> 9 10 #include "ntp_fp.h" 11 #include "ntp.h" 12 #include "ntp_syslog.h" 13 #include "ntp_stdlib.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 /* 68 * authreadkeys - (re)read keys from a file. 69 */ 70 int 71 authreadkeys( 72 const char *file 73 ) 74 { 75 FILE *fp; 76 char *line; 77 char *token; 78 keyid_t keyno; 79 int keytype; 80 char buf[512]; /* lots of room for line */ 81 u_char keystr[20]; 82 size_t len; 83 size_t j; 84 85 /* 86 * Open file. Complain and return if it can't be opened. 87 */ 88 fp = fopen(file, "r"); 89 if (fp == NULL) { 90 msyslog(LOG_ERR, "authreadkeys: file %s: %m", 91 file); 92 return (0); 93 } 94 INIT_SSL(); 95 96 /* 97 * Remove all existing keys 98 */ 99 auth_delkeys(); 100 101 /* 102 * Now read lines from the file, looking for key entries 103 */ 104 while ((line = fgets(buf, sizeof buf, fp)) != NULL) { 105 token = nexttok(&line); 106 if (token == NULL) 107 continue; 108 109 /* 110 * First is key number. See if it is okay. 111 */ 112 keyno = atoi(token); 113 if (keyno == 0) { 114 msyslog(LOG_ERR, 115 "authreadkeys: cannot change key %s", token); 116 continue; 117 } 118 119 if (keyno > NTP_MAXKEY) { 120 msyslog(LOG_ERR, 121 "authreadkeys: key %s > %d reserved for Autokey", 122 token, NTP_MAXKEY); 123 continue; 124 } 125 126 /* 127 * Next is keytype. See if that is all right. 128 */ 129 token = nexttok(&line); 130 if (token == NULL) { 131 msyslog(LOG_ERR, 132 "authreadkeys: no key type for key %d", keyno); 133 continue; 134 } 135 #ifdef OPENSSL 136 /* 137 * The key type is the NID used by the message digest 138 * algorithm. There are a number of inconsistencies in 139 * the OpenSSL database. We attempt to discover them 140 * here and prevent use of inconsistent data later. 141 */ 142 keytype = keytype_from_text(token, NULL); 143 if (keytype == 0) { 144 msyslog(LOG_ERR, 145 "authreadkeys: invalid type for key %d", keyno); 146 continue; 147 } 148 if (EVP_get_digestbynid(keytype) == NULL) { 149 msyslog(LOG_ERR, 150 "authreadkeys: no algorithm for key %d", keyno); 151 continue; 152 } 153 #else /* !OPENSSL follows */ 154 155 /* 156 * The key type is unused, but is required to be 'M' or 157 * 'm' for compatibility. 158 */ 159 if (!(*token == 'M' || *token == 'm')) { 160 msyslog(LOG_ERR, 161 "authreadkeys: invalid type for key %d", keyno); 162 continue; 163 } 164 keytype = KEY_TYPE_MD5; 165 #endif /* !OPENSSL */ 166 167 /* 168 * Finally, get key and insert it. If it is longer than 20 169 * characters, it is a binary string encoded in hex; 170 * otherwise, it is a text string of printable ASCII 171 * characters. 172 */ 173 token = nexttok(&line); 174 if (token == NULL) { 175 msyslog(LOG_ERR, 176 "authreadkeys: no key for key %d", keyno); 177 continue; 178 } 179 len = strlen(token); 180 if (len <= sizeof(keystr)) { 181 MD5auth_setkey(keyno, keytype, (u_char *)token, len); 182 } else { 183 char hex[] = "0123456789abcdef"; 184 u_char temp; 185 char *ptr; 186 size_t jlim; 187 188 jlim = min(len, 2 * sizeof(keystr)); 189 for (j = 0; j < jlim; j++) { 190 ptr = strchr(hex, tolower((unsigned char)token[j])); 191 if (ptr == NULL) 192 break; /* abort decoding */ 193 temp = (u_char)(ptr - hex); 194 if (j & 1) 195 keystr[j / 2] |= temp; 196 else 197 keystr[j / 2] = temp << 4; 198 } 199 if (j < jlim) { 200 msyslog(LOG_ERR, 201 "authreadkeys: invalid hex digit for key %d", keyno); 202 continue; 203 } 204 MD5auth_setkey(keyno, keytype, keystr, jlim / 2); 205 } 206 } 207 fclose(fp); 208 return (1); 209 } 210