authreadkeys.c revision 285612
1149749Sdes/* 2149749Sdes * authreadkeys.c - routines to support the reading of the key file 3149749Sdes */ 4149749Sdes#include <config.h> 5149749Sdes#include <stdio.h> 6149749Sdes#include <ctype.h> 7149749Sdes 8149749Sdes#include "ntp_fp.h" 9149749Sdes#include "ntp.h" 10149749Sdes#include "ntp_syslog.h" 11149749Sdes#include "ntp_stdlib.h" 12149749Sdes 13149749Sdes#ifdef OPENSSL 14149749Sdes#include "openssl/objects.h" 15149749Sdes#include "openssl/evp.h" 16149749Sdes#endif /* OPENSSL */ 17149749Sdes 18149749Sdes/* Forwards */ 19149749Sdesstatic char *nexttok (char **); 20149749Sdes 21149749Sdes/* 22149749Sdes * nexttok - basic internal tokenizing routine 23149749Sdes */ 24149749Sdesstatic char * 25149749Sdesnexttok( 26149749Sdes char **str 27149749Sdes ) 28192595Sdes{ 29162852Sdes register char *cp; 30149749Sdes char *starttok; 31162852Sdes 32149749Sdes cp = *str; 33162852Sdes 34162852Sdes /* 35162852Sdes * Space past white space 36162852Sdes */ 37162852Sdes while (*cp == ' ' || *cp == '\t') 38162852Sdes cp++; 39162852Sdes 40149749Sdes /* 41149749Sdes * Save this and space to end of token 42215116Sdes */ 43162852Sdes starttok = cp; 44149749Sdes while (*cp != '\0' && *cp != '\n' && *cp != ' ' 45295367Sdes && *cp != '\t' && *cp != '#') 46149749Sdes cp++; 47162852Sdes 48149749Sdes /* 49162852Sdes * If token length is zero return an error, else set end of 50149749Sdes * token to zero and return start. 51149749Sdes */ 52149749Sdes if (starttok == cp) 53149749Sdes return NULL; 54149749Sdes 55149749Sdes if (*cp == ' ' || *cp == '\t') 56149749Sdes *cp++ = '\0'; 57149749Sdes else 58149749Sdes *cp = '\0'; 59149749Sdes 60149749Sdes *str = cp; 61149749Sdes return starttok; 62149749Sdes} 63149749Sdes 64149749Sdes 65149749Sdes/* 66149749Sdes * authreadkeys - (re)read keys from a file. 67149749Sdes */ 68149749Sdesint 69149749Sdesauthreadkeys( 70149749Sdes const char *file 71149749Sdes ) 72149749Sdes{ 73149749Sdes FILE *fp; 74157016Sdes char *line; 75157016Sdes char *token; 76157016Sdes keyid_t keyno; 77157016Sdes int keytype; 78157016Sdes char buf[512]; /* lots of room for line */ 79157016Sdes u_char keystr[32]; /* Bug 2537 */ 80157016Sdes size_t len; 81157016Sdes size_t j; 82149749Sdes 83181111Sdes /* 84149749Sdes * Open file. Complain and return if it can't be opened. 85149749Sdes */ 86157016Sdes fp = fopen(file, "r"); 87149749Sdes if (fp == NULL) { 88149749Sdes msyslog(LOG_ERR, "authreadkeys: file %s: %m", 89149749Sdes file); 90149749Sdes return (0); 91149749Sdes } 92149749Sdes INIT_SSL(); 93149749Sdes 94149749Sdes /* 95149749Sdes * Remove all existing keys 96149749Sdes */ 97149749Sdes auth_delkeys(); 98149749Sdes 99149749Sdes /* 100149749Sdes * Now read lines from the file, looking for key entries 101149749Sdes */ 102149749Sdes while ((line = fgets(buf, sizeof buf, fp)) != NULL) { 103149749Sdes token = nexttok(&line); 104149749Sdes if (token == NULL) 105149749Sdes continue; 106149749Sdes 107149749Sdes /* 108149749Sdes * First is key number. See if it is okay. 109149749Sdes */ 110149749Sdes keyno = atoi(token); 111149749Sdes if (keyno == 0) { 112149749Sdes msyslog(LOG_ERR, 113149749Sdes "authreadkeys: cannot change key %s", token); 114149749Sdes continue; 115149749Sdes } 116149749Sdes 117149749Sdes if (keyno > NTP_MAXKEY) { 118149749Sdes msyslog(LOG_ERR, 119149749Sdes "authreadkeys: key %s > %d reserved for Autokey", 120149749Sdes token, NTP_MAXKEY); 121149749Sdes continue; 122149749Sdes } 123149749Sdes 124149749Sdes /* 125149749Sdes * Next is keytype. See if that is all right. 126149749Sdes */ 127149749Sdes token = nexttok(&line); 128149749Sdes if (token == NULL) { 129149749Sdes msyslog(LOG_ERR, 130149749Sdes "authreadkeys: no key type for key %d", keyno); 131181111Sdes continue; 132149749Sdes } 133149749Sdes#ifdef OPENSSL 134149749Sdes /* 135149749Sdes * The key type is the NID used by the message digest 136149749Sdes * algorithm. There are a number of inconsistencies in 137149749Sdes * the OpenSSL database. We attempt to discover them 138149749Sdes * here and prevent use of inconsistent data later. 139149749Sdes */ 140149749Sdes keytype = keytype_from_text(token, NULL); 141149749Sdes if (keytype == 0) { 142149749Sdes msyslog(LOG_ERR, 143149749Sdes "authreadkeys: invalid type for key %d", keyno); 144149749Sdes continue; 145149749Sdes } 146149749Sdes if (EVP_get_digestbynid(keytype) == NULL) { 147149749Sdes msyslog(LOG_ERR, 148181111Sdes "authreadkeys: no algorithm for key %d", keyno); 149192595Sdes continue; 150149749Sdes } 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