Home | History | Annotate | Line # | Download | only in libntp
authreadkeys.c revision 1.6
      1  1.6  christos /*	$NetBSD: authreadkeys.c,v 1.6 2015/07/10 14:20:32 christos Exp $	*/
      2  1.1    kardel 
      3  1.1    kardel /*
      4  1.1    kardel  * authreadkeys.c - routines to support the reading of the key file
      5  1.1    kardel  */
      6  1.1    kardel #include <config.h>
      7  1.1    kardel #include <stdio.h>
      8  1.1    kardel #include <ctype.h>
      9  1.1    kardel 
     10  1.1    kardel #include "ntp_fp.h"
     11  1.1    kardel #include "ntp.h"
     12  1.1    kardel #include "ntp_syslog.h"
     13  1.1    kardel #include "ntp_stdlib.h"
     14  1.1    kardel 
     15  1.1    kardel #ifdef OPENSSL
     16  1.1    kardel #include "openssl/objects.h"
     17  1.3  christos #include "openssl/evp.h"
     18  1.3  christos #endif	/* OPENSSL */
     19  1.1    kardel 
     20  1.1    kardel /* Forwards */
     21  1.1    kardel static char *nexttok (char **);
     22  1.1    kardel 
     23  1.1    kardel /*
     24  1.1    kardel  * nexttok - basic internal tokenizing routine
     25  1.1    kardel  */
     26  1.1    kardel static char *
     27  1.1    kardel nexttok(
     28  1.1    kardel 	char	**str
     29  1.1    kardel 	)
     30  1.1    kardel {
     31  1.1    kardel 	register char *cp;
     32  1.1    kardel 	char *starttok;
     33  1.1    kardel 
     34  1.1    kardel 	cp = *str;
     35  1.1    kardel 
     36  1.1    kardel 	/*
     37  1.1    kardel 	 * Space past white space
     38  1.1    kardel 	 */
     39  1.1    kardel 	while (*cp == ' ' || *cp == '\t')
     40  1.3  christos 		cp++;
     41  1.1    kardel 
     42  1.1    kardel 	/*
     43  1.1    kardel 	 * Save this and space to end of token
     44  1.1    kardel 	 */
     45  1.1    kardel 	starttok = cp;
     46  1.1    kardel 	while (*cp != '\0' && *cp != '\n' && *cp != ' '
     47  1.1    kardel 	       && *cp != '\t' && *cp != '#')
     48  1.3  christos 		cp++;
     49  1.1    kardel 
     50  1.1    kardel 	/*
     51  1.1    kardel 	 * If token length is zero return an error, else set end of
     52  1.1    kardel 	 * token to zero and return start.
     53  1.1    kardel 	 */
     54  1.1    kardel 	if (starttok == cp)
     55  1.3  christos 		return NULL;
     56  1.1    kardel 
     57  1.1    kardel 	if (*cp == ' ' || *cp == '\t')
     58  1.3  christos 		*cp++ = '\0';
     59  1.1    kardel 	else
     60  1.3  christos 		*cp = '\0';
     61  1.1    kardel 
     62  1.1    kardel 	*str = cp;
     63  1.1    kardel 	return starttok;
     64  1.1    kardel }
     65  1.1    kardel 
     66  1.1    kardel 
     67  1.1    kardel /*
     68  1.1    kardel  * authreadkeys - (re)read keys from a file.
     69  1.1    kardel  */
     70  1.1    kardel int
     71  1.1    kardel authreadkeys(
     72  1.1    kardel 	const char *file
     73  1.1    kardel 	)
     74  1.1    kardel {
     75  1.1    kardel 	FILE	*fp;
     76  1.1    kardel 	char	*line;
     77  1.1    kardel 	char	*token;
     78  1.1    kardel 	keyid_t	keyno;
     79  1.1    kardel 	int	keytype;
     80  1.1    kardel 	char	buf[512];		/* lots of room for line */
     81  1.4  christos 	u_char	keystr[32];		/* Bug 2537 */
     82  1.2  christos 	size_t	len;
     83  1.2  christos 	size_t	j;
     84  1.1    kardel 
     85  1.1    kardel 	/*
     86  1.1    kardel 	 * Open file.  Complain and return if it can't be opened.
     87  1.1    kardel 	 */
     88  1.1    kardel 	fp = fopen(file, "r");
     89  1.1    kardel 	if (fp == NULL) {
     90  1.1    kardel 		msyslog(LOG_ERR, "authreadkeys: file %s: %m",
     91  1.1    kardel 		    file);
     92  1.1    kardel 		return (0);
     93  1.1    kardel 	}
     94  1.1    kardel 	INIT_SSL();
     95  1.1    kardel 
     96  1.1    kardel 	/*
     97  1.1    kardel 	 * Remove all existing keys
     98  1.1    kardel 	 */
     99  1.1    kardel 	auth_delkeys();
    100  1.1    kardel 
    101  1.1    kardel 	/*
    102  1.1    kardel 	 * Now read lines from the file, looking for key entries
    103  1.1    kardel 	 */
    104  1.1    kardel 	while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
    105  1.1    kardel 		token = nexttok(&line);
    106  1.1    kardel 		if (token == NULL)
    107  1.1    kardel 			continue;
    108  1.1    kardel 
    109  1.1    kardel 		/*
    110  1.1    kardel 		 * First is key number.  See if it is okay.
    111  1.1    kardel 		 */
    112  1.1    kardel 		keyno = atoi(token);
    113  1.1    kardel 		if (keyno == 0) {
    114  1.1    kardel 			msyslog(LOG_ERR,
    115  1.1    kardel 			    "authreadkeys: cannot change key %s", token);
    116  1.1    kardel 			continue;
    117  1.1    kardel 		}
    118  1.1    kardel 
    119  1.1    kardel 		if (keyno > NTP_MAXKEY) {
    120  1.1    kardel 			msyslog(LOG_ERR,
    121  1.1    kardel 			    "authreadkeys: key %s > %d reserved for Autokey",
    122  1.1    kardel 			    token, NTP_MAXKEY);
    123  1.1    kardel 			continue;
    124  1.1    kardel 		}
    125  1.1    kardel 
    126  1.1    kardel 		/*
    127  1.1    kardel 		 * Next is keytype. See if that is all right.
    128  1.1    kardel 		 */
    129  1.1    kardel 		token = nexttok(&line);
    130  1.1    kardel 		if (token == NULL) {
    131  1.1    kardel 			msyslog(LOG_ERR,
    132  1.1    kardel 			    "authreadkeys: no key type for key %d", keyno);
    133  1.1    kardel 			continue;
    134  1.1    kardel 		}
    135  1.1    kardel #ifdef OPENSSL
    136  1.1    kardel 		/*
    137  1.1    kardel 		 * The key type is the NID used by the message digest
    138  1.1    kardel 		 * algorithm. There are a number of inconsistencies in
    139  1.1    kardel 		 * the OpenSSL database. We attempt to discover them
    140  1.1    kardel 		 * here and prevent use of inconsistent data later.
    141  1.1    kardel 		 */
    142  1.1    kardel 		keytype = keytype_from_text(token, NULL);
    143  1.1    kardel 		if (keytype == 0) {
    144  1.1    kardel 			msyslog(LOG_ERR,
    145  1.1    kardel 			    "authreadkeys: invalid type for key %d", keyno);
    146  1.1    kardel 			continue;
    147  1.1    kardel 		}
    148  1.1    kardel 		if (EVP_get_digestbynid(keytype) == NULL) {
    149  1.1    kardel 			msyslog(LOG_ERR,
    150  1.1    kardel 			    "authreadkeys: no algorithm for key %d", keyno);
    151  1.1    kardel 			continue;
    152  1.1    kardel 		}
    153  1.3  christos #else	/* !OPENSSL follows */
    154  1.1    kardel 
    155  1.1    kardel 		/*
    156  1.1    kardel 		 * The key type is unused, but is required to be 'M' or
    157  1.1    kardel 		 * 'm' for compatibility.
    158  1.1    kardel 		 */
    159  1.1    kardel 		if (!(*token == 'M' || *token == 'm')) {
    160  1.1    kardel 			msyslog(LOG_ERR,
    161  1.1    kardel 			    "authreadkeys: invalid type for key %d", keyno);
    162  1.1    kardel 			continue;
    163  1.1    kardel 		}
    164  1.1    kardel 		keytype = KEY_TYPE_MD5;
    165  1.3  christos #endif	/* !OPENSSL */
    166  1.1    kardel 
    167  1.1    kardel 		/*
    168  1.1    kardel 		 * Finally, get key and insert it. If it is longer than 20
    169  1.1    kardel 		 * characters, it is a binary string encoded in hex;
    170  1.1    kardel 		 * otherwise, it is a text string of printable ASCII
    171  1.1    kardel 		 * characters.
    172  1.1    kardel 		 */
    173  1.1    kardel 		token = nexttok(&line);
    174  1.1    kardel 		if (token == NULL) {
    175  1.1    kardel 			msyslog(LOG_ERR,
    176  1.1    kardel 			    "authreadkeys: no key for key %d", keyno);
    177  1.1    kardel 			continue;
    178  1.1    kardel 		}
    179  1.1    kardel 		len = strlen(token);
    180  1.4  christos 		if (len <= 20) {	/* Bug 2537 */
    181  1.1    kardel 			MD5auth_setkey(keyno, keytype, (u_char *)token, len);
    182  1.1    kardel 		} else {
    183  1.1    kardel 			char	hex[] = "0123456789abcdef";
    184  1.1    kardel 			u_char	temp;
    185  1.1    kardel 			char	*ptr;
    186  1.2  christos 			size_t	jlim;
    187  1.1    kardel 
    188  1.1    kardel 			jlim = min(len, 2 * sizeof(keystr));
    189  1.1    kardel 			for (j = 0; j < jlim; j++) {
    190  1.2  christos 				ptr = strchr(hex, tolower((unsigned char)token[j]));
    191  1.3  christos 				if (ptr == NULL)
    192  1.3  christos 					break;	/* abort decoding */
    193  1.1    kardel 				temp = (u_char)(ptr - hex);
    194  1.1    kardel 				if (j & 1)
    195  1.1    kardel 					keystr[j / 2] |= temp;
    196  1.1    kardel 				else
    197  1.1    kardel 					keystr[j / 2] = temp << 4;
    198  1.1    kardel 			}
    199  1.3  christos 			if (j < jlim) {
    200  1.3  christos 				msyslog(LOG_ERR,
    201  1.3  christos 					"authreadkeys: invalid hex digit for key %d", keyno);
    202  1.3  christos 				continue;
    203  1.3  christos 			}
    204  1.1    kardel 			MD5auth_setkey(keyno, keytype, keystr, jlim / 2);
    205  1.1    kardel 		}
    206  1.1    kardel 	}
    207  1.1    kardel 	fclose(fp);
    208  1.1    kardel 	return (1);
    209  1.1    kardel }
    210