#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_NETINFO
#include <netinfo/ni.h>
#endif
#include "ntp_machine.h"
#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"
#ifndef GETTIMEOFDAY
# define GETTIMEOFDAY gettimeofday
#endif
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
#ifdef PUBKEY
# include "ntp_crypto.h"
#endif
#include "l_stdlib.h"
#ifndef PATH_MAX
# ifdef _POSIX_PATH_MAX
# define PATH_MAX _POSIX_PATH_MAX
# else
# define PATH_MAX 255
# endif
#endif
#define MAXKEYLEN 1024
#define MODULUSLEN 512
#define PRIMELEN 512
extern char *config_file;
#ifdef HAVE_NETINFO
extern struct netinfo_config_state *config_netinfo;
extern int check_netinfo;
#endif
#ifdef SYS_WINNT
char *alt_config_file;
LPTSTR temp;
char config_file_storage[PATH_MAX];
char alt_config_file_storage[PATH_MAX];
#endif
int make_dh = 0;
int make_md5 = 0;
int make_rsa = 0;
int force = 0;
int here = 0;
int nosymlinks = 0;
int memorex = 0;
int trash = 0;
int errflag = 0;
char *f1_keysdir = NTP_KEYSDIR;
char *f1_keys;
char *f2_keys;
char *f3_keys;
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;
u_long sys_automax;
int sys_bclient;
int sys_manycastserver;
char * req_file;
keyid_t ctl_auth_keyid;
struct interface *any_interface;
keyid_t info_auth_keyid;
u_long current_time;
const char *Version = "";
keyid_t req_keyid;
u_long client_limit;
u_long client_limit_period;
l_fp sys_revoketime;
u_long sys_revoke;
volatile int debug = 0;
u_char sys_minpoll;
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,
char *cp
)
{
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
)
{
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;
}
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 (!(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:
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);
#endif
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,
const char *f2,
mode_t fmask,
const char *f3
)
{
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 (here)
snprintf(fb, sizeof fb, "%s", f2);
else {
if (
#ifdef HAVE_READLINK
!f3
#else
1
#endif
) {
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) {
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);
}
}
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,
const char *f2,
const char *f3
)
{
#ifdef HAVE_READLINK
char *cp;
char fb[PATH_MAX];
#endif
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;
}
}
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 && 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;
R_RSA_PUBLIC_KEY rsaref_public;
R_RSA_PROTO_KEY protokey;
R_DH_PARAMS dh_params;
R_RANDOM_STRUCT randomstr;
int rval;
u_char encoded_key[MAXKEYLEN];
u_int modulus;
u_int len;
#endif
struct timeval tv;
u_long ntptime;
char hostname[256];
u_char md5key[17];
FILE *str;
u_int temp;
int i, j;
mode_t std_mask;
mode_t sec_mask = 077;
char pathbuf[PATH_MAX];
gethostname(hostname, sizeof(hostname));
GETTIMEOFDAY(&tv, 0);
ntptime = tv.tv_sec + JAN_1970;
getconfig(argc, argv);
if (!f1_keysdir) {
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: "");
}
std_mask = umask(sec_mask);
(void) umask(std_mask);
if (make_md5 && (force || !filep(f1_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;
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))) {
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);
}
}
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);
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
#ifdef PUBKEY
if (make_dh && (force || !filep(f1_dhparms))) {
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);
}
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
return (0);
}