1043 lines
24 KiB
C
1043 lines
24 KiB
C
/*
|
|
* Program to generate MD5 and RSA keys for NTP clients and servers
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_NETINFO
|
|
#include <netinfo/ni.h>
|
|
#endif
|
|
|
|
#include "ntpd.h"
|
|
#include "ntp_stdlib.h"
|
|
#include "ntp_string.h"
|
|
#include "ntp_filegen.h"
|
|
#include "ntp_unixtime.h"
|
|
#include "ntp_config.h"
|
|
#include "ntp_cmdargs.h"
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <limits.h> /* PATH_MAX */
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef PUBKEY
|
|
# include "ntp_crypto.h"
|
|
#endif
|
|
|
|
#ifndef PATH_MAX
|
|
# ifdef _POSIX_PATH_MAX
|
|
# define PATH_MAX _POSIX_PATH_MAX
|
|
# else
|
|
# define PATH_MAX 255
|
|
# endif
|
|
#endif
|
|
|
|
/*
|
|
* Cryptodefines
|
|
*/
|
|
#define MAXKEYLEN 1024 /* maximum encoded key length */
|
|
#define MODULUSLEN 512 /* length of RSA modulus */
|
|
#define PRIMELEN 512 /* length of D_H prime, generator */
|
|
|
|
/*
|
|
* This program generates (up to) four files:
|
|
*
|
|
* ntp.keys containing the DES/MD5 private keys,
|
|
* ntpkey containing the RSA private key,
|
|
* ntpkey_HOST containing the RSA public key
|
|
* where HOST is the DNS name of the generating machine,
|
|
* ntpkey_dh containing the parameters for the Diffie-Hellman
|
|
* key-agreement algorithm.
|
|
*
|
|
* The files contain cryptographic values generated by the algorithms of
|
|
* the rsaref20 package and are in printable ASCII format. Since the
|
|
* algorythms are seeded by the system clock, each run of this program
|
|
* will produce a different outcome. There are no options or frills of
|
|
* any sort, although a number of options would seem to be appropriate.
|
|
* Waving this program in the breeze will no doubt bring a cast of
|
|
* thousands to wiggle the options this way and that for various useful
|
|
* purposes.
|
|
*
|
|
* The names of all files begin with "ntp" and end with an extension
|
|
* consisting of the seconds value of the current NTP timestamp, which
|
|
* appears in the form ".*". This provides a way to distinguish between
|
|
* key generations, since the host name and timestamp can be fetched by
|
|
* a client during operation.
|
|
*
|
|
* The ntp.keys.* file contains 16 MD5 keys. Each key consists of 16
|
|
* characters randomized over the ASCII 95-character printing subset.
|
|
* The file is read by the daemon at the location specified by the keys
|
|
* configuration file command and made visible only to root. An
|
|
* additional key consisting of a easily remembered password should be
|
|
* added by hand for use with the ntpdc program. The file must be
|
|
* distributed by secure means to other servers and clients sharing the
|
|
* same security compartment.
|
|
*
|
|
* The key identifiers for MD5 and DES keys must be less than 65536,
|
|
* although this program uses only the identifiers from 1 to 16. The key
|
|
* identifier for each association is specified as the key argument in
|
|
* the server or peer configuration file command.
|
|
*
|
|
* The ntpkey.* file contains the RSA private key. It is read by the
|
|
* daemon at the location specified by the private argument of the
|
|
* crypto configuration file command and made visible only to root.
|
|
* This file is useful only to the machine that generated it and never
|
|
* shared with any other daemon or application program.
|
|
*
|
|
* The ntpkey_host.* file contains the RSA public key, where host is the
|
|
* DNS name of the host that generated it. The file is read by the
|
|
* daemon at the location specified by the public argument to the server
|
|
* or peer configuration file command. This file can be widely
|
|
* distributed and stored without using secure means, since the data are
|
|
* public values.
|
|
*
|
|
* The ntp_dh.* file contains two Diffie-Hellman parameters, the prime
|
|
* modulus and the generator. The file is read by the daemon at the
|
|
* location specified by the dhparams argument of the crypto
|
|
* configuration file command. This file can be widely distributed and
|
|
* stored without using secure means, since the data are public values.
|
|
*
|
|
* The file formats all begin with two lines. The first line contains
|
|
* the file name and decimal timestamp, while the second contains the
|
|
* readable datestamp. Lines beginning with # are considered comments
|
|
* and ignored by the daemon. In the ntp.keys.* file, the next 16 lines
|
|
* contain the MD5 keys in order. In the ntpkey.* and ntpkey_host.*
|
|
* files, the next line contains the modulus length in bits followed by
|
|
* the key as a PEM encoded string. In the ntpkey_dh.* file, the next
|
|
* line contains the prime length in bytes followed by the prime as a
|
|
* PEM encoded string, and the next and final line contains the
|
|
* generator length in bytes followed by the generator as a PEM encoded
|
|
* string.
|
|
*
|
|
* Note: See the file ./source/rsaref.h in the rsaref20 package for
|
|
* explanation of return values, if necessary.
|
|
*/
|
|
|
|
|
|
extern char *config_file;
|
|
|
|
#ifdef HAVE_NETINFO
|
|
extern struct netinfo_config_state *config_netinfo;
|
|
extern int check_netinfo;
|
|
#endif /* HAVE_NETINFO */
|
|
|
|
#ifdef SYS_WINNT
|
|
char *alt_config_file;
|
|
LPTSTR temp;
|
|
char config_file_storage[PATH_MAX];
|
|
char alt_config_file_storage[PATH_MAX];
|
|
#endif /* SYS_WINNT */
|
|
|
|
int make_dh = 0; /* Make D-H parameter file? */
|
|
int make_md5 = 0; /* Make MD5 keyfile? */
|
|
int make_rsa = 0; /* Make RSA pair? */
|
|
int force = 0; /* Force the installation? */
|
|
int here = 0; /* Put the files here (curdir)? */
|
|
int nosymlinks = 0; /* Just create the (timestamped) files? */
|
|
int memorex = 0; /* Are we live? */
|
|
int trash = 0; /* Trash old files? */
|
|
int errflag = 0;
|
|
|
|
char *f1_keysdir = NTP_KEYSDIR;
|
|
|
|
char *f1_keys; /* Visible MD5 key file name */
|
|
char *f2_keys; /* timestamped */
|
|
char *f3_keys; /* previous filename */
|
|
|
|
char *f1_publickey;
|
|
char *f2_publickey;
|
|
char *f3_publickey;
|
|
|
|
char *f1_privatekey;
|
|
char *f2_privatekey;
|
|
char *f3_privatekey;
|
|
|
|
char *f1_dhparms;
|
|
char *f2_dhparms;
|
|
char *f3_dhparms;
|
|
|
|
|
|
/* Stubs and hacks so we can link with ntp_config.o */
|
|
u_long sys_automax; /* maximum session key lifetime */
|
|
int sys_bclient; /* we set our time to broadcasts */
|
|
int sys_manycastserver; /* 1 => respond to manycast client pkts */
|
|
u_long client_limit_period;
|
|
char * req_file; /* name of the file with configuration info */
|
|
keyid_t ctl_auth_keyid; /* keyid used for authenticating write requests */
|
|
struct interface *any_interface; /* default interface */
|
|
keyid_t info_auth_keyid; /* keyid used to authenticate requests */
|
|
u_long current_time; /* current time (s) */
|
|
const char *Version = ""; /* version declaration */
|
|
keyid_t req_keyid; /* request keyid */
|
|
u_long client_limit;
|
|
u_long client_limit_period;
|
|
l_fp sys_revoketime;
|
|
u_long sys_revoke; /* keys revoke timeout */
|
|
volatile int debug = 0; /* debugging flag */
|
|
u_char sys_minpoll; /* min poll interval (log2 s) */
|
|
|
|
void snifflink P((const char *, char **));
|
|
int filep P((const char *));
|
|
FILE *newfile P((const char *, const char *, mode_t, const char *));
|
|
void cleanlinks P((const char *, const char *, const char *));
|
|
|
|
struct peer *
|
|
peer_config(
|
|
struct sockaddr_in *srcadr,
|
|
struct interface *dstadr,
|
|
int hmode,
|
|
int version,
|
|
int minpoll,
|
|
int maxpoll,
|
|
u_int flags,
|
|
int ttl,
|
|
keyid_t key,
|
|
u_char *keystr
|
|
)
|
|
{
|
|
if (debug > 1) printf("peer_config...\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
set_sys_var(
|
|
char *data,
|
|
u_long size,
|
|
int def
|
|
)
|
|
{
|
|
if (debug > 1) printf("set_sys_var...\n");
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
ntp_intres (void)
|
|
{
|
|
if (debug > 1) printf("ntp_intres...\n");
|
|
return;
|
|
}
|
|
|
|
|
|
int
|
|
ctlsettrap(
|
|
struct sockaddr_in *raddr,
|
|
struct interface *linter,
|
|
int traptype,
|
|
int version
|
|
)
|
|
{
|
|
if (debug > 1) printf("ctlsettrap...\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifdef PUBKEY
|
|
void
|
|
crypto_config(
|
|
int item, /* configuration item */
|
|
char *cp /* file name */
|
|
)
|
|
{
|
|
switch (item) {
|
|
case CRYPTO_CONF_DH:
|
|
if (debug > 0) printf("crypto_config: DH/<%d> <%s>\n", item, cp);
|
|
f1_dhparms = strdup(cp);
|
|
break;
|
|
case CRYPTO_CONF_PRIV:
|
|
if (debug > 0) printf("crypto_config: PRIVATEKEY/<%d> <%s>\n", item, cp);
|
|
f1_privatekey = strdup(cp);
|
|
break;
|
|
case CRYPTO_CONF_PUBL:
|
|
if (debug > 0) printf("crypto_config: PUBLICKEY/<%d> <%s>\n", item, cp);
|
|
f1_publickey = strdup(cp);
|
|
break;
|
|
default:
|
|
if (debug > 1) printf("crypto_config: <%d> <%s>\n", item, cp);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
struct interface *
|
|
findinterface(
|
|
struct sockaddr_in *addr
|
|
)
|
|
{
|
|
if (debug > 1) printf("findinterface...\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
refclock_control(
|
|
struct sockaddr_in *srcadr,
|
|
struct refclockstat *in,
|
|
struct refclockstat *out
|
|
)
|
|
{
|
|
if (debug > 1) printf("refclock_control...\n");
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
loop_config(
|
|
int item,
|
|
double freq
|
|
)
|
|
{
|
|
if (debug > 1) printf("loop_config...\n");
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
filegen_config(
|
|
FILEGEN *gen,
|
|
char *basename,
|
|
u_int type,
|
|
u_int flag
|
|
)
|
|
{
|
|
if (debug > 1) printf("filegen_config...\n");
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
stats_config(
|
|
int item,
|
|
char *invalue /* only one type so far */
|
|
)
|
|
{
|
|
if (debug > 1) printf("stats_config...\n");
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
hack_restrict(
|
|
int op,
|
|
struct sockaddr_in *resaddr,
|
|
struct sockaddr_in *resmask,
|
|
int mflags,
|
|
int flags
|
|
)
|
|
{
|
|
if (debug > 1) printf("hack_restrict...\n");
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
kill_asyncio (void)
|
|
{
|
|
if (debug > 1) printf("kill_asyncio...\n");
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
proto_config(
|
|
int item,
|
|
u_long value,
|
|
double dvalue
|
|
)
|
|
{
|
|
if (debug > 1) printf("proto_config...\n");
|
|
return;
|
|
}
|
|
|
|
void
|
|
getauthkeys(
|
|
char *keyfile
|
|
)
|
|
{
|
|
if (debug > 0) printf("getauthkeys: got <%s>\n", keyfile);
|
|
f1_keys = strdup(keyfile);
|
|
return;
|
|
}
|
|
|
|
|
|
FILEGEN *
|
|
filegen_get(
|
|
char *name
|
|
)
|
|
{
|
|
if (debug > 1) printf("filegen_get...\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* End of stubs and hacks */
|
|
|
|
|
|
static void
|
|
usage(
|
|
void
|
|
)
|
|
{
|
|
printf("Usage: %s [ -c ntp.conf ] [ -g {d,m,r} ] [ -k key_file ]\n",
|
|
progname);
|
|
printf(" [ -d ] [ -f ] [ -h ] [ -l ] [ -n ] [ -t ]\n");
|
|
printf(" where:\n");
|
|
printf(" -c /etc/ntp.conf Location of ntp.conf file\n");
|
|
printf(" -d enable debug messages (can be used multiple times)\n");
|
|
printf(" -f force installation of generated keys.\n");
|
|
printf(" -g d Generate D-H parameter file\n");
|
|
printf(" -g m Generate MD5 key file\n");
|
|
printf(" -g r Generate RSA keys\n");
|
|
printf(" -g dmr (Can be combined)\n");
|
|
printf(" -h Build keys here (current directory). Implies -l\n");
|
|
printf(" -k key_file Location of key file\n");
|
|
printf(" -l Don't make the symlinks\n");
|
|
printf(" -n Don't actually do anything, just say what would be done\n");
|
|
printf(" -t Trash the (old) files at the end of symlink\n");
|
|
|
|
exit(1);
|
|
}
|
|
|
|
|
|
void
|
|
getCmdOpts (
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
int i;
|
|
|
|
while ((i = ntp_getopt(argc, argv, "c:dfg:hlnt")) != EOF)
|
|
switch (i) {
|
|
case 'c':
|
|
config_file = ntp_optarg;
|
|
#ifdef HAVE_NETINFO
|
|
check_netinfo = 0;
|
|
#endif
|
|
break;
|
|
case 'd':
|
|
++debug;
|
|
break;
|
|
case 'f':
|
|
++force;
|
|
break;
|
|
case 'g':
|
|
while (*ntp_optarg) {
|
|
switch (*ntp_optarg) {
|
|
case 'd':
|
|
++make_dh;
|
|
break;
|
|
case 'm':
|
|
++make_md5;
|
|
break;
|
|
case 'r':
|
|
++make_rsa;
|
|
break;
|
|
default:
|
|
++errflag;
|
|
break;
|
|
}
|
|
++ntp_optarg;
|
|
}
|
|
break;
|
|
case 'h':
|
|
++here;
|
|
++nosymlinks;
|
|
break;
|
|
case 'l':
|
|
++nosymlinks;
|
|
break;
|
|
case 'n':
|
|
++memorex;
|
|
break;
|
|
case 't':
|
|
++trash;
|
|
break;
|
|
case '?':
|
|
++errflag;
|
|
break;
|
|
}
|
|
|
|
if (errflag)
|
|
usage();
|
|
|
|
/* If no file type was specified, make them all. */
|
|
if (!(make_dh | make_md5 | make_rsa)) {
|
|
++make_dh;
|
|
++make_md5;
|
|
++make_rsa;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
snifflink(
|
|
const char *file,
|
|
char **linkdata
|
|
)
|
|
{
|
|
#ifdef HAVE_READLINK
|
|
char buf[PATH_MAX];
|
|
int rc;
|
|
|
|
if (!file)
|
|
return;
|
|
|
|
rc = readlink(file, buf, sizeof buf);
|
|
if (-1 == rc) {
|
|
switch (errno) {
|
|
case EINVAL: /* Fall thru */
|
|
case ENOENT:
|
|
return;
|
|
}
|
|
fprintf(stderr, "%s: readlink(%s) failed: (%d) %s\n",
|
|
progname, file, errno, strerror(errno));
|
|
exit(1);
|
|
}
|
|
buf[rc] = '\0';
|
|
*linkdata = strdup(buf);
|
|
/* XXX: make sure linkdata is not 0... */
|
|
#endif /* not HAVE_READLINK */
|
|
return;
|
|
}
|
|
|
|
|
|
int
|
|
filep(
|
|
const char *fn
|
|
)
|
|
{
|
|
struct stat sb;
|
|
|
|
if (-1 == stat(fn, &sb)) {
|
|
if (ENOENT == errno)
|
|
return 0;
|
|
fprintf(stderr, "stat(%s) failed: %s\n",
|
|
fn, strerror(errno));
|
|
exit(1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
FILE *
|
|
newfile(
|
|
const char *f1, /* Visible file */
|
|
const char *f2, /* New timestamped file name */
|
|
mode_t fmask, /* umask for new timestamped file */
|
|
const char *f3 /* Previous symlink target */
|
|
)
|
|
{
|
|
FILE *fp;
|
|
char fb[PATH_MAX];
|
|
char *cp;
|
|
|
|
if (debug > 1) printf("newfile(%s,%s,%0o,%s)\n", f1, f2,
|
|
(unsigned)fmask, f3 ? f3 : "NULL");
|
|
/*
|
|
If:
|
|
- no symlink support, or
|
|
- there is no old symlink (!f3)
|
|
- - file = dirname(f1) / f2
|
|
Otherwise:
|
|
- If ('/' == *f3)
|
|
- - file = dirname(f3) / f2
|
|
- else
|
|
- - file = dirname(f1) / dirname(f3) / f2
|
|
fopen(file)
|
|
print any error message/bail
|
|
return FILE
|
|
*/
|
|
|
|
if (here)
|
|
snprintf(fb, sizeof fb, "%s", f2);
|
|
else {
|
|
if (
|
|
#ifdef HAVE_READLINK
|
|
!f3
|
|
#else
|
|
1
|
|
#endif
|
|
) {
|
|
/* file = dirname(f1) / f2 */
|
|
snprintf(fb, sizeof fb, "%s", f1);
|
|
cp = strrchr(fb, '/');
|
|
if (cp) {
|
|
*cp = 0;
|
|
}
|
|
snprintf(fb, sizeof fb, "%s/%s", fb, f2);
|
|
if (debug > 1) printf("case 1: file is <%s>\n", fb);
|
|
} else {
|
|
/*
|
|
- If ('/' == *f3)
|
|
- - file = dirname(f3) / f2
|
|
- else
|
|
- - file = dirname(f1) / dirname(f3) / f2
|
|
*/
|
|
if ('/' != *f3) {
|
|
snprintf(fb, sizeof fb, "%s", f1);
|
|
cp = strrchr(fb, '/');
|
|
if (cp) {
|
|
++cp;
|
|
*cp = 0;
|
|
}
|
|
if (debug > 1)
|
|
printf("case 2: file is <%s>\n", fb);
|
|
} else {
|
|
*fb = 0;
|
|
}
|
|
snprintf(fb, sizeof fb, "%s%s", fb, f3);
|
|
cp = strrchr(fb, '/');
|
|
if (cp) {
|
|
*cp = 0;
|
|
}
|
|
snprintf(fb, sizeof fb, "%s/%s", fb, f2);
|
|
if (debug > 1) printf("case 3: file is <%s>\n", fb);
|
|
}
|
|
}
|
|
|
|
/*
|
|
fopen(file)
|
|
print any error message/bail
|
|
return FILE
|
|
*/
|
|
if (memorex) {
|
|
printf("Would write file <%s>\n", fb);
|
|
fp = NULL;
|
|
} else {
|
|
mode_t omask;
|
|
|
|
omask = umask(fmask);
|
|
fp = fopen(fb, "w");
|
|
(void) umask(omask);
|
|
if (fp == NULL) {
|
|
perror(fb);
|
|
exit(1);
|
|
}
|
|
}
|
|
return fp;
|
|
}
|
|
|
|
void
|
|
cleanlinks(
|
|
const char *f1, /* Visible file */
|
|
const char *f2, /* New timestamped file name */
|
|
const char *f3 /* Previous symlink target */
|
|
)
|
|
{
|
|
#ifdef HAVE_READLINK
|
|
char *cp;
|
|
char fb[PATH_MAX];
|
|
|
|
/*
|
|
Just return if nosymlinks.
|
|
unlink f1
|
|
file = dirname(f3) / f2
|
|
symlink file, f1
|
|
If trash:
|
|
- if f3 begins with a /, unlink it
|
|
- else, unlink dirname(f1) / f3
|
|
*/
|
|
#endif /* HAVE_READLINK */
|
|
|
|
if (nosymlinks)
|
|
return;
|
|
|
|
if (memorex)
|
|
printf("Would unlink(%s)\n", f1);
|
|
else if (unlink(f1)) {
|
|
if (errno != ENOENT) {
|
|
fprintf(stderr, "unlink(%s) failed: %s\n", f1,
|
|
strerror(errno));
|
|
return;
|
|
}
|
|
}
|
|
/* file = dirname(f3) / f2 */
|
|
if (f3) {
|
|
snprintf(fb, sizeof fb, "%s", f3);
|
|
cp = strrchr(fb, '/');
|
|
if (cp) {
|
|
++cp;
|
|
*cp = 0;
|
|
} else {
|
|
*fb = 0;
|
|
}
|
|
} else {
|
|
*fb = 0;
|
|
}
|
|
snprintf(fb, sizeof fb, "%s%s", fb, f2);
|
|
if (debug > 1) printf("cleanlinks 1: file is <%s>\n", fb);
|
|
|
|
if (memorex)
|
|
printf("Would symlink <%s> -> <%s>\n", f1, fb);
|
|
else if (symlink(fb, f1)) {
|
|
fprintf(stderr, "symlink(%s,%s) failed: %s\n", fb, f1,
|
|
strerror(errno));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
If trash:
|
|
- if f3 begins with a /, unlink it
|
|
- else, unlink dirname(f1) / f3
|
|
*/
|
|
if (trash && f3) {
|
|
if ('/' == *f3) {
|
|
if (memorex)
|
|
printf("Would unlink(%s)\n", f3);
|
|
else if (unlink(f3)) {
|
|
if (errno != ENOENT) {
|
|
fprintf(stderr, "unlink(%s) failed: %s\n", f3,
|
|
strerror(errno));
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
snprintf(fb, sizeof fb, "%s", f1);
|
|
cp = strrchr(fb, '/');
|
|
if (cp) {
|
|
*cp = 0;
|
|
}
|
|
snprintf(fb, sizeof fb, "%s/%s", fb, f3);
|
|
if (debug > 1)
|
|
printf("cleanlinks 2: file is <%s>\n", fb);
|
|
if (memorex)
|
|
printf("Would unlink(%s)\n", fb);
|
|
else if (unlink(fb)) {
|
|
if (errno != ENOENT) {
|
|
fprintf(stderr, "unlink(%s) failed: %s\n", fb,
|
|
strerror(errno));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
int
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
#ifdef PUBKEY
|
|
R_RSA_PRIVATE_KEY rsaref_private; /* RSA private key */
|
|
R_RSA_PUBLIC_KEY rsaref_public; /* RSA public key */
|
|
R_RSA_PROTO_KEY protokey; /* RSA prototype key */
|
|
R_DH_PARAMS dh_params; /* Diffie-Hellman parameters */
|
|
R_RANDOM_STRUCT randomstr; /* random structure */
|
|
int rval; /* return value */
|
|
u_char encoded_key[MAXKEYLEN]; /* encoded PEM string buffer */
|
|
u_int modulus; /* modulus length */
|
|
u_int len;
|
|
#endif /* PUBKEY */
|
|
struct timeval tv; /* initialization vector */
|
|
u_long ntptime; /* NTP timestamp */
|
|
char hostname[256]; /* DNS host name */
|
|
u_char md5key[17]; /* generated MD5 key */
|
|
FILE *str; /* file handle */
|
|
u_int temp;
|
|
int i, j;
|
|
mode_t std_mask; /* Standard mask */
|
|
mode_t sec_mask = 077; /* Secure mask */
|
|
char pathbuf[PATH_MAX];
|
|
|
|
gethostname(hostname, sizeof(hostname));
|
|
gettimeofday(&tv, 0);
|
|
ntptime = tv.tv_sec + JAN_1970;
|
|
|
|
/* Initialize config_file */
|
|
getconfig(argc, argv); /* ntpd/ntp_config.c */
|
|
|
|
if (!f1_keysdir) {
|
|
/* Shouldn't happen... */
|
|
f1_keysdir = "PATH_KEYSDIR";
|
|
}
|
|
if (*f1_keysdir != '/') {
|
|
fprintf(stderr,
|
|
"%s: keysdir path <%s> doesn't begin with a /\n",
|
|
progname, f1_keysdir);
|
|
exit(1);
|
|
}
|
|
|
|
if (!f2_keys) {
|
|
snprintf(pathbuf, sizeof pathbuf, "ntp.keys.%lu",
|
|
ntptime);
|
|
f2_keys = strdup(pathbuf);
|
|
}
|
|
if (!f1_keys) {
|
|
snprintf(pathbuf, sizeof pathbuf, "%s/ntp.keys",
|
|
f1_keysdir);
|
|
f1_keys = strdup(pathbuf);
|
|
}
|
|
if (*f1_keys != '/') {
|
|
fprintf(stderr,
|
|
"%s: keys path <%s> doesn't begin with a /\n",
|
|
progname, f1_keys);
|
|
exit(1);
|
|
}
|
|
snifflink(f1_keys, &f3_keys);
|
|
|
|
if (!f2_publickey) {
|
|
snprintf(pathbuf, sizeof pathbuf, "ntpkey_%s.%lu",
|
|
hostname, ntptime);
|
|
f2_publickey = strdup(pathbuf);
|
|
}
|
|
if (!f1_publickey) {
|
|
snprintf(pathbuf, sizeof pathbuf, "%s/ntpkey_%s",
|
|
f1_keysdir, hostname);
|
|
f1_publickey = strdup(pathbuf);
|
|
}
|
|
if (*f1_publickey != '/') {
|
|
fprintf(stderr,
|
|
"%s: publickey path <%s> doesn't begin with a /\n",
|
|
progname, f1_publickey);
|
|
exit(1);
|
|
}
|
|
snifflink(f1_publickey, &f3_publickey);
|
|
|
|
if (!f2_privatekey) {
|
|
snprintf(pathbuf, sizeof pathbuf, "ntpkey.%lu",
|
|
ntptime);
|
|
f2_privatekey = strdup(pathbuf);
|
|
}
|
|
if (!f1_privatekey) {
|
|
snprintf(pathbuf, sizeof pathbuf, "%s/ntpkey",
|
|
f1_keysdir);
|
|
f1_privatekey = strdup(pathbuf);
|
|
}
|
|
if (*f1_privatekey != '/') {
|
|
fprintf(stderr,
|
|
"%s: privatekey path <%s> doesn't begin with a /\n",
|
|
progname, f1_privatekey);
|
|
exit(1);
|
|
}
|
|
snifflink(f1_privatekey, &f3_privatekey);
|
|
|
|
if (!f2_dhparms) {
|
|
snprintf(pathbuf, sizeof pathbuf, "ntpkey_dh.%lu",
|
|
ntptime);
|
|
f2_dhparms = strdup(pathbuf);
|
|
}
|
|
if (!f1_dhparms) {
|
|
snprintf(pathbuf, sizeof pathbuf, "%s/ntpkey_dh",
|
|
f1_keysdir);
|
|
f1_dhparms = strdup(pathbuf);
|
|
}
|
|
if (*f1_dhparms != '/') {
|
|
fprintf(stderr,
|
|
"%s: dhparms path <%s> doesn't begin with a /\n",
|
|
progname, f1_dhparms);
|
|
exit(1);
|
|
}
|
|
snifflink(f1_dhparms, &f3_dhparms);
|
|
|
|
if (debug > 1) {
|
|
printf("After config:\n");
|
|
printf("keysdir = <%s>\n", f1_keysdir? f1_keysdir: "");
|
|
printf("keys = <%s> -> <%s>\n"
|
|
, f1_keys? f1_keys: ""
|
|
, f2_keys? f2_keys: ""
|
|
);
|
|
printf(" old = <%s>\n", f3_keys? f3_keys: "");
|
|
printf("publickey = <%s> -> <%s>\n"
|
|
, f1_publickey? f1_publickey: ""
|
|
, f2_publickey? f2_publickey: ""
|
|
);
|
|
printf(" old = <%s>\n", f3_publickey? f3_publickey: "");
|
|
printf("privatekey = <%s> -> <%s>\n"
|
|
, f1_privatekey? f1_privatekey: ""
|
|
, f2_privatekey? f2_privatekey: ""
|
|
);
|
|
printf(" old = <%s>\n", f3_privatekey? f3_privatekey: "");
|
|
printf("dhparms = <%s> -> <%s>\n"
|
|
, f1_dhparms? f1_dhparms: ""
|
|
, f2_dhparms? f2_dhparms: ""
|
|
);
|
|
printf(" old = <%s>\n", f3_dhparms? f3_dhparms: "");
|
|
}
|
|
|
|
/*
|
|
for each file we're going to install:
|
|
- make the new timestamped file
|
|
- if (!nosymlinks)
|
|
- - remove any old link
|
|
- - make the link
|
|
- - if (trash)
|
|
- - - remove the old file
|
|
*/
|
|
|
|
std_mask = umask(sec_mask); /* Get the standard mask */
|
|
(void) umask(std_mask);
|
|
|
|
if (make_md5 && (force || !filep(f1_keys))) {
|
|
/*
|
|
* Generate 16 random MD5 keys.
|
|
*/
|
|
printf("Generating MD5 key file...\n");
|
|
str = newfile(f1_keys, f2_keys, sec_mask, f3_keys);
|
|
if (!memorex) {
|
|
srandom((u_int)tv.tv_usec);
|
|
fprintf(str, "# MD5 key file %s\n# %s", f2_keys,
|
|
ctime((const time_t *) &tv.tv_sec));
|
|
for (i = 1; i <= 16; i++) {
|
|
for (j = 0; j < 16; j++) {
|
|
while (1) {
|
|
temp = random() & 0xff;
|
|
/*
|
|
** Harlan says Karnaugh maps
|
|
** are not his friend, and
|
|
** compilers can optimize
|
|
** this most easily.
|
|
*/
|
|
if (temp == '#')
|
|
continue;
|
|
if (temp > 0x20 && temp < 0x7f)
|
|
break;
|
|
}
|
|
md5key[j] = (u_char)temp;
|
|
}
|
|
md5key[16] = 0;
|
|
fprintf(str, "%2d M %16s # MD5 key\n",
|
|
i, md5key);
|
|
}
|
|
}
|
|
if (str) fclose(str);
|
|
cleanlinks(f1_keys, f2_keys, f3_keys);
|
|
}
|
|
|
|
#ifdef PUBKEY
|
|
if (make_rsa && (force || !filep(f1_publickey)
|
|
|| !filep(f1_privatekey))) {
|
|
/*
|
|
* Roll the RSA public/private key pair.
|
|
*/
|
|
printf("Generating RSA public/private key pair (%d bits)...\n",
|
|
MODULUSLEN);
|
|
if (!memorex) {
|
|
protokey.bits = MODULUSLEN;
|
|
protokey.useFermat4 = 1;
|
|
R_RandomInit(&randomstr);
|
|
R_GetRandomBytesNeeded(&len, &randomstr);
|
|
for (i = 0; i < len; i++) {
|
|
temp = random();
|
|
R_RandomUpdate(&randomstr, (u_char *)&temp, 1);
|
|
}
|
|
rval = R_GeneratePEMKeys(&rsaref_public,
|
|
&rsaref_private, &protokey,
|
|
&randomstr);
|
|
if (rval) {
|
|
printf("R_GeneratePEMKeys error %x\n", rval);
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Generate the file "ntpkey.*" containing the RSA
|
|
* private key in printable ASCII format.
|
|
*/
|
|
str = newfile(f1_privatekey, f2_privatekey, sec_mask,
|
|
f3_privatekey);
|
|
if (!memorex) {
|
|
len = sizeof(rsaref_private)
|
|
- sizeof(rsaref_private.bits);
|
|
modulus = (u_int32)rsaref_private.bits;
|
|
fprintf(str, "# RSA private key file %s\n# %s",
|
|
f2_privatekey, ctime(&tv.tv_sec));
|
|
R_EncodePEMBlock(encoded_key, &temp,
|
|
(u_char *)rsaref_private.modulus,
|
|
len);
|
|
encoded_key[temp] = '\0';
|
|
fprintf(str, "%d %s\n", modulus, encoded_key);
|
|
}
|
|
if (str) fclose(str);
|
|
cleanlinks(f1_privatekey, f2_privatekey, f3_privatekey);
|
|
|
|
/*
|
|
* Generate the file "ntpkey_host.*" containing the RSA
|
|
* public key in printable ASCII format.
|
|
*/
|
|
str = newfile(f1_publickey, f2_publickey, std_mask,
|
|
f3_publickey);
|
|
if (!memorex) {
|
|
len = sizeof(rsaref_public)
|
|
- sizeof(rsaref_public.bits);
|
|
modulus = (u_int32)rsaref_public.bits;
|
|
fprintf(str, "# RSA public key file %s\n# %s",
|
|
f2_publickey, ctime(&tv.tv_sec));
|
|
R_EncodePEMBlock(encoded_key, &temp,
|
|
(u_char *)rsaref_public.modulus, len);
|
|
encoded_key[temp] = '\0';
|
|
fprintf(str, "%d %s\n", modulus, encoded_key);
|
|
}
|
|
if (str) fclose(str);
|
|
cleanlinks(f1_publickey, f2_publickey, f3_publickey);
|
|
}
|
|
#endif /* PUBKEY */
|
|
|
|
#ifdef PUBKEY
|
|
if (make_dh && (force || !filep(f1_dhparms))) {
|
|
/*
|
|
* Roll the prime and generator for the Diffie-Hellman key
|
|
* agreement algorithm.
|
|
*/
|
|
printf("Generating Diffie-Hellman parameters (%d bits)...\n",
|
|
PRIMELEN);
|
|
str = newfile(f1_dhparms, f2_dhparms, std_mask, f3_dhparms);
|
|
|
|
if (!memorex) {
|
|
R_RandomInit(&randomstr);
|
|
R_GetRandomBytesNeeded(&len, &randomstr);
|
|
for (i = 0; i < len; i++) {
|
|
temp = random();
|
|
R_RandomUpdate(&randomstr, (u_char *)&temp, 1);
|
|
}
|
|
|
|
/*
|
|
* Generate the file "ntpkey_dh.*" containing the
|
|
* Diffie-Hellman prime and generator in printable
|
|
* ASCII format.
|
|
*/
|
|
len = DH_PRIME_LEN(PRIMELEN);
|
|
dh_params.prime = (u_char *)malloc(len);
|
|
dh_params.generator = (u_char *)malloc(len);
|
|
rval = R_GenerateDHParams(&dh_params, PRIMELEN,
|
|
PRIMELEN / 2, &randomstr);
|
|
if (rval) {
|
|
printf("R_GenerateDHParams error %x\n", rval);
|
|
return (-1);
|
|
}
|
|
|
|
fprintf(str,
|
|
"# Diffie-Hellman parameter file %s\n# %s",
|
|
f2_dhparms, ctime(&tv.tv_sec));
|
|
R_EncodePEMBlock(encoded_key, &temp,
|
|
(u_char *)dh_params.prime,
|
|
dh_params.primeLen);
|
|
encoded_key[temp] = '\0';
|
|
fprintf(str, "%d %s\n", dh_params.primeLen,
|
|
encoded_key);
|
|
R_EncodePEMBlock(encoded_key, &temp,
|
|
(u_char *)dh_params.generator,
|
|
dh_params.generatorLen);
|
|
encoded_key[temp] = '\0';
|
|
fprintf(str, "%d %s\n", dh_params.generatorLen,
|
|
encoded_key);
|
|
}
|
|
if (str) fclose(str);
|
|
cleanlinks(f1_dhparms, f2_dhparms, f3_dhparms);
|
|
}
|
|
#endif /* PUBKEY */
|
|
|
|
return (0);
|
|
}
|