Home | History | Annotate | Line # | Download | only in libntp
authreadkeys.c revision 1.1.1.5
      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