Home | History | Annotate | Line # | Download | only in libntp
authreadkeys.c revision 1.4
      1 /*	$NetBSD: authreadkeys.c,v 1.4 2014/12/19 20:43:17 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[32];		/* Bug 2537 */
     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 <= 20) {	/* Bug 2537 */
    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