Initial import from FreeBSD RELENG_4:
[games.git] / contrib / ntp / util / ntp-genkeys.c
1 /*
2  * Program to generate MD5 and RSA keys for NTP clients and servers
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #ifdef HAVE_NETINFO
10 #include <netinfo/ni.h>
11 #endif
12
13 #include "ntpd.h"
14 #include "ntp_stdlib.h"
15 #include "ntp_string.h"
16 #include "ntp_filegen.h"
17 #include "ntp_unixtime.h"
18 #include "ntp_config.h"
19 #include "ntp_cmdargs.h"
20
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <limits.h>             /* PATH_MAX */
24 #include <sys/stat.h>
25
26 #ifdef PUBKEY
27 # include "ntp_crypto.h"
28 #endif
29
30 #ifndef PATH_MAX
31 # ifdef _POSIX_PATH_MAX
32 #  define PATH_MAX _POSIX_PATH_MAX
33 # else
34 #  define PATH_MAX 255
35 # endif
36 #endif
37
38 /*
39  * Cryptodefines
40  */
41 #define MAXKEYLEN       1024    /* maximum encoded key length */
42 #define MODULUSLEN      512     /* length of RSA modulus */
43 #define PRIMELEN        512     /* length of D_H prime, generator */
44
45 /*
46  * This program generates (up to) four files:
47  *
48  *      ntp.keys    containing the DES/MD5 private keys,
49  *      ntpkey      containing the RSA private key,
50  *      ntpkey_HOST containing the RSA public key
51  *                   where HOST is the DNS name of the generating machine,
52  *      ntpkey_dh   containing the parameters for the Diffie-Hellman
53  *                  key-agreement algorithm.
54  *
55  * The files contain cryptographic values generated by the algorithms of
56  * the rsaref20 package and are in printable ASCII format.  Since the
57  * algorythms are seeded by the system clock, each run of this program
58  * will produce a different outcome.  There are no options or frills of
59  * any sort, although a number of options would seem to be appropriate.
60  * Waving this program in the breeze will no doubt bring a cast of
61  * thousands to wiggle the options this way and that for various useful
62  * purposes.
63  *
64  * The names of all files begin with "ntp" and end with an extension
65  * consisting of the seconds value of the current NTP timestamp, which
66  * appears in the form ".*".  This provides a way to distinguish between
67  * key generations, since the host name and timestamp can be fetched by
68  * a client during operation.
69  *
70  * The ntp.keys.* file contains 16 MD5 keys.  Each key consists of 16
71  * characters randomized over the ASCII 95-character printing subset.
72  * The file is read by the daemon at the location specified by the keys
73  * configuration file command and made visible only to root.  An
74  * additional key consisting of a easily remembered password should be
75  * added by hand for use with the ntpdc program.  The file must be
76  * distributed by secure means to other servers and clients sharing the
77  * same security compartment.
78  *
79  * The key identifiers for MD5 and DES keys must be less than 65536,
80  * although this program uses only the identifiers from 1 to 16.  The key
81  * identifier for each association is specified as the key argument in
82  * the server or peer configuration file command.
83  *
84  * The ntpkey.* file contains the RSA private key.  It is read by the
85  * daemon at the location specified by the private argument of the
86  * crypto configuration file command and made visible only to root.
87  * This file is useful only to the machine that generated it and never
88  * shared with any other daemon or application program.
89  *
90  * The ntpkey_host.* file contains the RSA public key, where host is the
91  * DNS name of the host that generated it.  The file is read by the
92  * daemon at the location specified by the public argument to the server
93  * or peer configuration file command.  This file can be widely
94  * distributed and stored without using secure means, since the data are
95  * public values.
96  *
97  * The ntp_dh.* file contains two Diffie-Hellman parameters, the prime
98  * modulus and the generator.  The file is read by the daemon at the
99  * location specified by the dhparams argument of the crypto
100  * configuration file command.  This file can be widely distributed and
101  * stored without using secure means, since the data are public values.
102  *
103  * The file formats all begin with two lines.  The first line contains
104  * the file name and decimal timestamp, while the second contains the
105  * readable datestamp.  Lines beginning with # are considered comments
106  * and ignored by the daemon.  In the ntp.keys.* file, the next 16 lines
107  * contain the MD5 keys in order.  In the ntpkey.* and ntpkey_host.*
108  * files, the next line contains the modulus length in bits followed by
109  * the key as a PEM encoded string.  In the ntpkey_dh.* file, the next
110  * line contains the prime length in bytes followed by the prime as a
111  * PEM encoded string, and the next and final line contains the
112  * generator length in bytes followed by the generator as a PEM encoded
113  * string.
114  *
115  * Note: See the file ./source/rsaref.h in the rsaref20 package for
116  * explanation of return values, if necessary.
117  */
118
119
120 extern char *config_file;
121
122 #ifdef HAVE_NETINFO
123 extern struct netinfo_config_state *config_netinfo;
124 extern int check_netinfo;
125 #endif /* HAVE_NETINFO */
126
127 #ifdef SYS_WINNT
128 char *alt_config_file;
129 LPTSTR temp;
130 char config_file_storage[PATH_MAX];
131 char alt_config_file_storage[PATH_MAX];
132 #endif /* SYS_WINNT */
133
134 int make_dh = 0;                /* Make D-H parameter file? */
135 int make_md5 = 0;               /* Make MD5 keyfile? */
136 int make_rsa = 0;               /* Make RSA pair? */
137 int force = 0;                  /* Force the installation? */
138 int here = 0;                   /* Put the files here (curdir)? */
139 int nosymlinks = 0;             /* Just create the (timestamped) files? */
140 int memorex = 0;                /* Are we live? */
141 int trash = 0;                  /* Trash old files? */
142 int errflag = 0;
143
144 char *f1_keysdir = NTP_KEYSDIR;
145
146 char *f1_keys;                  /* Visible MD5 key file name */
147 char *f2_keys;                  /* timestamped */
148 char *f3_keys;                  /* previous filename */
149
150 char *f1_publickey;
151 char *f2_publickey;
152 char *f3_publickey;
153
154 char *f1_privatekey;
155 char *f2_privatekey;
156 char *f3_privatekey;
157
158 char *f1_dhparms;
159 char *f2_dhparms;
160 char *f3_dhparms;
161
162
163 /* Stubs and hacks so we can link with ntp_config.o */
164 u_long  sys_automax;            /* maximum session key lifetime */
165 int     sys_bclient;            /* we set our time to broadcasts */
166 int     sys_manycastserver;     /* 1 => respond to manycast client pkts */
167 u_long  client_limit_period;
168 char *  req_file;               /* name of the file with configuration info */
169 keyid_t ctl_auth_keyid;         /* keyid used for authenticating write requests */
170 struct interface *any_interface;        /* default interface */
171 keyid_t info_auth_keyid;        /* keyid used to authenticate requests */
172 u_long  current_time;           /* current time (s) */
173 const char *Version = "";       /* version declaration */
174 keyid_t req_keyid;              /* request keyid */
175 u_long  client_limit;
176 u_long  client_limit_period;
177 l_fp    sys_revoketime;
178 u_long  sys_revoke;             /* keys revoke timeout */
179 volatile int debug = 0;         /* debugging flag */
180 u_char  sys_minpoll;            /* min poll interval (log2 s) */
181
182 void snifflink P((const char *, char **));
183 int filep P((const char *));
184 FILE *newfile P((const char *, const char *, mode_t, const char *));
185 void cleanlinks P((const char *, const char *, const char *));
186
187 struct peer *
188 peer_config(
189         struct sockaddr_in *srcadr,
190         struct interface *dstadr,
191         int hmode,
192         int version,
193         int minpoll,
194         int maxpoll,
195         u_int flags,
196         int ttl,
197         keyid_t key,
198         u_char *keystr
199         )
200 {
201         if (debug > 1) printf("peer_config...\n");
202         return 0;
203 }
204
205
206 void
207 set_sys_var(
208         char *data,
209         u_long size,
210         int def
211         )
212 {
213         if (debug > 1) printf("set_sys_var...\n");
214         return;
215 }
216
217
218 void
219 ntp_intres (void)
220 {
221         if (debug > 1) printf("ntp_intres...\n");
222         return;
223 }
224
225
226 int
227 ctlsettrap(
228         struct sockaddr_in *raddr,
229         struct interface *linter,
230         int traptype,
231         int version
232         )
233 {
234         if (debug > 1) printf("ctlsettrap...\n");
235         return 0;
236 }
237
238
239 #ifdef PUBKEY
240 void
241 crypto_config(
242         int item,               /* configuration item */
243         char *cp                /* file name */
244         )
245 {
246         switch (item) {
247             case CRYPTO_CONF_DH:
248                 if (debug > 0) printf("crypto_config: DH/<%d> <%s>\n", item, cp);
249                 f1_dhparms = strdup(cp);
250                 break;
251             case CRYPTO_CONF_PRIV:
252                 if (debug > 0) printf("crypto_config: PRIVATEKEY/<%d> <%s>\n", item, cp);
253                 f1_privatekey = strdup(cp);
254                 break;
255             case CRYPTO_CONF_PUBL:
256                 if (debug > 0) printf("crypto_config: PUBLICKEY/<%d> <%s>\n", item, cp);
257                 f1_publickey = strdup(cp);
258                 break;
259             default:
260                 if (debug > 1) printf("crypto_config: <%d> <%s>\n", item, cp);
261                 break;
262         }
263         return;
264 }
265 #endif
266
267
268 struct interface *
269 findinterface(
270         struct sockaddr_in *addr
271         )
272 {
273         if (debug > 1) printf("findinterface...\n");
274         return 0;
275 }
276
277
278 void
279 refclock_control(
280         struct sockaddr_in *srcadr,
281         struct refclockstat *in,
282         struct refclockstat *out
283         )
284 {
285         if (debug > 1) printf("refclock_control...\n");
286         return;
287 }
288
289
290 void
291 loop_config(
292         int item,
293         double freq
294         )
295 {
296         if (debug > 1) printf("loop_config...\n");
297         return;
298 }
299
300
301 void
302 filegen_config(
303         FILEGEN *gen,
304         char    *basename,
305         u_int   type,
306         u_int   flag
307         )
308 {
309         if (debug > 1) printf("filegen_config...\n");
310         return;
311 }
312
313
314 void
315 stats_config(
316         int item,
317         char *invalue   /* only one type so far */
318         )
319 {
320         if (debug > 1) printf("stats_config...\n");
321         return;
322 }
323
324
325 void
326 hack_restrict(
327         int op,
328         struct sockaddr_in *resaddr,
329         struct sockaddr_in *resmask,
330         int mflags,
331         int flags
332         )
333 {
334         if (debug > 1) printf("hack_restrict...\n");
335         return;
336 }
337
338
339 void
340 kill_asyncio (void)
341 {
342         if (debug > 1) printf("kill_asyncio...\n");
343         return;
344 }
345
346
347 void
348 proto_config(
349         int item,
350         u_long value,
351         double dvalue
352         )
353 {
354         if (debug > 1) printf("proto_config...\n");
355         return;
356 }
357
358 void
359 getauthkeys(
360         char *keyfile
361         )
362 {
363         if (debug > 0) printf("getauthkeys: got <%s>\n", keyfile);
364         f1_keys = strdup(keyfile);
365         return;
366 }
367
368
369 FILEGEN *
370 filegen_get(
371         char *name
372         )
373 {
374         if (debug > 1) printf("filegen_get...\n");
375         return 0;
376 }
377
378
379 /* End of stubs and hacks */
380
381
382 static void
383 usage(
384         void
385         )
386 {
387         printf("Usage: %s [ -c ntp.conf ] [ -g {d,m,r} ] [ -k key_file ]\n",
388                progname);
389         printf("       [ -d ] [ -f ] [ -h ] [ -l ] [ -n ] [ -t ]\n");
390         printf(" where:\n");
391         printf("  -c /etc/ntp.conf   Location of ntp.conf file\n");
392         printf("  -d     enable debug messages (can be used multiple times)\n");
393         printf("  -f     force installation of generated keys.\n");
394         printf("  -g d   Generate D-H parameter file\n");
395         printf("  -g m   Generate MD5 key file\n");
396         printf("  -g r   Generate RSA keys\n");
397         printf("  -g dmr (Can be combined)\n");
398         printf("  -h     Build keys here (current directory). Implies -l\n");
399         printf("  -k key_file        Location of key file\n");
400         printf("  -l     Don't make the symlinks\n");
401         printf("  -n     Don't actually do anything, just say what would be done\n");
402         printf("  -t     Trash the (old) files at the end of symlink\n");
403
404         exit(1);
405 }
406
407
408 void
409 getCmdOpts (
410         int argc,
411         char *argv[]
412         )
413 {
414         int i;
415
416         while ((i = ntp_getopt(argc, argv, "c:dfg:hlnt")) != EOF)
417                 switch (i) {
418                     case 'c':
419                         config_file = ntp_optarg;
420 #ifdef HAVE_NETINFO
421                         check_netinfo = 0;
422 #endif
423                         break;
424                     case 'd':
425                         ++debug;
426                         break;
427                     case 'f':
428                         ++force;
429                         break;
430                     case 'g':
431                         while (*ntp_optarg) {
432                                 switch (*ntp_optarg) {
433                                     case 'd':
434                                         ++make_dh;
435                                         break;
436                                     case 'm':
437                                         ++make_md5;
438                                         break;
439                                     case 'r':
440                                         ++make_rsa;
441                                         break;
442                                     default:
443                                         ++errflag;
444                                         break;
445                                 }
446                                 ++ntp_optarg;
447                         }
448                         break;
449                     case 'h':
450                         ++here;
451                         ++nosymlinks;
452                         break;
453                     case 'l':
454                         ++nosymlinks;
455                         break;
456                     case 'n':
457                         ++memorex;
458                         break;
459                     case 't':
460                         ++trash;
461                         break;
462                     case '?':
463                         ++errflag;
464                         break;
465                 }
466
467         if (errflag)
468                 usage();
469
470         /* If no file type was specified, make them all. */
471         if (!(make_dh | make_md5 | make_rsa)) {
472                 ++make_dh;
473                 ++make_md5;
474                 ++make_rsa;
475         }
476 }
477
478
479 void
480 snifflink(
481         const char *file,
482         char **linkdata
483         )
484 {
485 #ifdef HAVE_READLINK
486         char buf[PATH_MAX];
487         int rc;
488
489         if (!file)
490                 return;
491
492         rc = readlink(file, buf, sizeof buf);
493         if (-1 == rc) {
494                 switch (errno) {
495                     case EINVAL:        /* Fall thru */
496                     case ENOENT:
497                         return;
498                 }
499                 fprintf(stderr, "%s: readlink(%s) failed: (%d) %s\n",
500                         progname, file, errno, strerror(errno));
501                 exit(1);
502         }
503         buf[rc] = '\0';
504         *linkdata = strdup(buf);
505         /* XXX: make sure linkdata is not 0... */
506 #endif /* not HAVE_READLINK */
507         return;
508 }
509
510
511 int
512 filep(
513         const char *fn
514         )
515 {
516         struct stat sb;
517
518         if (-1 == stat(fn, &sb)) {
519                 if (ENOENT == errno)
520                         return 0;
521                 fprintf(stderr, "stat(%s) failed: %s\n",
522                         fn, strerror(errno));
523                 exit(1);
524         }
525         return 1;
526 }
527
528
529 FILE *
530 newfile(
531         const char *f1,         /* Visible file */
532         const char *f2,         /* New timestamped file name */
533         mode_t fmask,           /* umask for new timestamped file */
534         const char *f3          /* Previous symlink target */
535         )
536 {
537         FILE *fp;
538         char fb[PATH_MAX];
539         char *cp;
540
541         if (debug > 1) printf("newfile(%s,%s,%0o,%s)\n", f1, f2,
542                               (unsigned)fmask, f3 ? f3 : "NULL");
543         /*
544            If:
545            - no symlink support, or
546            - there is no old symlink (!f3)
547            - - file = dirname(f1) / f2
548            Otherwise:
549            - If ('/' == *f3)
550            - - file = dirname(f3) / f2
551            - else
552            - - file = dirname(f1) / dirname(f3) / f2
553            fopen(file)
554            print any error message/bail
555            return FILE
556         */
557
558         if (here)
559                 snprintf(fb, sizeof fb, "%s", f2);
560         else {
561                 if (
562 #ifdef HAVE_READLINK
563                     !f3
564 #else
565                     1
566 #endif
567                    ) {
568                         /* file = dirname(f1) / f2 */
569                         snprintf(fb, sizeof fb, "%s", f1);
570                         cp = strrchr(fb, '/');
571                         if (cp) {
572                                 *cp = 0;
573                         }
574                         snprintf(fb, sizeof fb, "%s/%s", fb, f2);
575                         if (debug > 1) printf("case 1: file is <%s>\n", fb);
576                 } else {
577                         /*
578                           - If ('/' == *f3)
579                           - - file = dirname(f3) / f2
580                           - else
581                           - - file = dirname(f1) / dirname(f3) / f2
582                         */
583                         if ('/' != *f3) {
584                                 snprintf(fb, sizeof fb, "%s", f1);
585                                 cp = strrchr(fb, '/');
586                                 if (cp) {
587                                         ++cp;
588                                         *cp = 0;
589                                 }
590                                 if (debug > 1)
591                                         printf("case 2: file is <%s>\n", fb);
592                         } else {
593                                 *fb = 0;
594                         }
595                         snprintf(fb, sizeof fb, "%s%s", fb, f3);
596                         cp = strrchr(fb, '/');
597                         if (cp) {
598                                 *cp = 0;
599                         }
600                         snprintf(fb, sizeof fb, "%s/%s", fb, f2);
601                         if (debug > 1) printf("case 3: file is <%s>\n", fb);
602                 }
603         }
604
605         /*
606           fopen(file)
607           print any error message/bail
608           return FILE
609         */
610         if (memorex) {
611                 printf("Would write file <%s>\n", fb);
612                 fp = NULL;
613         } else {
614                 mode_t omask;
615
616                 omask = umask(fmask);
617                 fp = fopen(fb, "w");
618                 (void) umask(omask);
619                 if (fp == NULL) {
620                         perror(fb);
621                         exit(1);
622                 }
623         }
624         return fp;
625 }
626
627 void
628 cleanlinks(
629         const char *f1,         /* Visible file */
630         const char *f2,         /* New timestamped file name */
631         const char *f3          /* Previous symlink target */
632         )
633 {
634 #ifdef HAVE_READLINK
635         char *cp;
636         char fb[PATH_MAX];
637
638         /*
639           Just return if nosymlinks.
640           unlink f1
641           file = dirname(f3) / f2
642           symlink file, f1
643           If trash:
644           - if f3 begins with a /, unlink it
645           - else, unlink dirname(f1) / f3
646         */
647 #endif /* HAVE_READLINK */
648
649         if (nosymlinks)
650                 return;
651
652         if (memorex)
653                 printf("Would unlink(%s)\n", f1);
654         else if (unlink(f1)) {
655                 if (errno != ENOENT) {
656                         fprintf(stderr, "unlink(%s) failed: %s\n", f1,
657                                 strerror(errno));
658                         return;
659                 }
660         }
661         /* file = dirname(f3) / f2 */
662         if (f3) {
663                 snprintf(fb, sizeof fb, "%s", f3);
664                 cp = strrchr(fb, '/');
665                 if (cp) {
666                         ++cp;
667                         *cp = 0;
668                 } else {
669                         *fb = 0;
670                 }
671         } else {
672                 *fb = 0;
673         }
674         snprintf(fb, sizeof fb, "%s%s", fb, f2);
675         if (debug > 1) printf("cleanlinks 1: file is <%s>\n", fb);
676
677         if (memorex)
678                 printf("Would symlink <%s> -> <%s>\n", f1, fb);
679         else if (symlink(fb, f1)) {
680                 fprintf(stderr, "symlink(%s,%s) failed: %s\n", fb, f1,
681                         strerror(errno));
682                 return;
683         }
684
685         /*
686           If trash:
687           - if f3 begins with a /, unlink it
688           - else, unlink dirname(f1) / f3
689         */
690         if (trash && f3) {
691                 if ('/' == *f3) {
692                         if (memorex)
693                                 printf("Would unlink(%s)\n", f3);
694                         else if (unlink(f3)) {
695                                 if (errno != ENOENT) {
696                                         fprintf(stderr, "unlink(%s) failed: %s\n", f3,
697                                                 strerror(errno));
698                                         return;
699                                 }
700                         }
701                 } else {
702                         snprintf(fb, sizeof fb, "%s", f1);
703                         cp = strrchr(fb, '/');
704                         if (cp) {
705                                 *cp = 0;
706                         }
707                         snprintf(fb, sizeof fb, "%s/%s", fb, f3);
708                         if (debug > 1)
709                                 printf("cleanlinks 2: file is <%s>\n", fb);
710                         if (memorex)
711                                 printf("Would unlink(%s)\n", fb);
712                         else if (unlink(fb)) {
713                                 if (errno != ENOENT) {
714                                         fprintf(stderr, "unlink(%s) failed: %s\n", fb,
715                                                 strerror(errno));
716                                         return;
717                                 }
718                         }
719                 }
720         }
721
722         return;
723 }
724
725
726 int
727 main(
728         int argc,
729         char *argv[]
730         )
731 {
732 #ifdef PUBKEY
733         R_RSA_PRIVATE_KEY rsaref_private; /* RSA private key */
734         R_RSA_PUBLIC_KEY rsaref_public; /* RSA public key */
735         R_RSA_PROTO_KEY protokey;       /* RSA prototype key */
736         R_DH_PARAMS dh_params;          /* Diffie-Hellman parameters */
737         R_RANDOM_STRUCT randomstr;      /* random structure */
738         int rval;                       /* return value */
739         u_char encoded_key[MAXKEYLEN];  /* encoded PEM string buffer */
740         u_int modulus;                  /* modulus length */
741         u_int len;
742 #endif /* PUBKEY */
743         struct timeval tv;              /* initialization vector */
744         u_long ntptime;                 /* NTP timestamp */
745         char hostname[256];             /* DNS host name */
746         u_char md5key[17];              /* generated MD5 key */ 
747         FILE *str;                      /* file handle */
748         u_int temp;
749         int i, j;
750         mode_t std_mask;        /* Standard mask */
751         mode_t sec_mask = 077;  /* Secure mask */
752         char pathbuf[PATH_MAX];
753
754         gethostname(hostname, sizeof(hostname));
755         gettimeofday(&tv, 0);
756         ntptime = tv.tv_sec + JAN_1970;
757
758         /* Initialize config_file */
759         getconfig(argc, argv);  /* ntpd/ntp_config.c */
760
761         if (!f1_keysdir) {
762                 /* Shouldn't happen... */
763                 f1_keysdir = "PATH_KEYSDIR";
764         }
765         if (*f1_keysdir != '/') {
766                 fprintf(stderr,
767                         "%s: keysdir path <%s> doesn't begin with a /\n",
768                         progname, f1_keysdir);
769                 exit(1);
770         }
771
772         if (!f2_keys) {
773                 snprintf(pathbuf, sizeof pathbuf, "ntp.keys.%lu",
774                          ntptime);
775                 f2_keys = strdup(pathbuf);
776         }
777         if (!f1_keys) {
778                 snprintf(pathbuf, sizeof pathbuf, "%s/ntp.keys",
779                          f1_keysdir);
780                 f1_keys = strdup(pathbuf);
781         }
782         if (*f1_keys != '/') {
783                 fprintf(stderr,
784                         "%s: keys path <%s> doesn't begin with a /\n",
785                         progname, f1_keys);
786                 exit(1);
787         }
788         snifflink(f1_keys, &f3_keys);
789
790         if (!f2_publickey) {
791                 snprintf(pathbuf, sizeof pathbuf, "ntpkey_%s.%lu",
792                          hostname, ntptime);
793                 f2_publickey = strdup(pathbuf);
794         }
795         if (!f1_publickey) {
796                 snprintf(pathbuf, sizeof pathbuf, "%s/ntpkey_%s",
797                          f1_keysdir, hostname);
798                 f1_publickey = strdup(pathbuf);
799         }
800         if (*f1_publickey != '/') {
801                 fprintf(stderr,
802                         "%s: publickey path <%s> doesn't begin with a /\n",
803                         progname, f1_publickey);
804                 exit(1);
805         }
806         snifflink(f1_publickey, &f3_publickey);
807
808         if (!f2_privatekey) {
809                 snprintf(pathbuf, sizeof pathbuf, "ntpkey.%lu",
810                          ntptime);
811                 f2_privatekey = strdup(pathbuf);
812         }
813         if (!f1_privatekey) {
814                 snprintf(pathbuf, sizeof pathbuf, "%s/ntpkey",
815                          f1_keysdir);
816                 f1_privatekey = strdup(pathbuf);
817         }
818         if (*f1_privatekey != '/') {
819                 fprintf(stderr,
820                         "%s: privatekey path <%s> doesn't begin with a /\n",
821                         progname, f1_privatekey);
822                 exit(1);
823         }
824         snifflink(f1_privatekey, &f3_privatekey);
825
826         if (!f2_dhparms) {
827                 snprintf(pathbuf, sizeof pathbuf, "ntpkey_dh.%lu",
828                          ntptime);
829                 f2_dhparms = strdup(pathbuf);
830         }
831         if (!f1_dhparms) {
832                 snprintf(pathbuf, sizeof pathbuf, "%s/ntpkey_dh",
833                          f1_keysdir);
834                 f1_dhparms = strdup(pathbuf);
835         }
836         if (*f1_dhparms != '/') {
837                 fprintf(stderr,
838                         "%s: dhparms path <%s> doesn't begin with a /\n",
839                         progname, f1_dhparms);
840                 exit(1);
841         }
842         snifflink(f1_dhparms, &f3_dhparms);
843
844         if (debug > 1) {
845                 printf("After config:\n");
846                 printf("keysdir    = <%s>\n", f1_keysdir? f1_keysdir: "");
847                 printf("keys       = <%s> -> <%s>\n"
848                        , f1_keys? f1_keys: ""
849                        , f2_keys? f2_keys: ""
850                       );
851                 printf("       old = <%s>\n", f3_keys? f3_keys: "");
852                 printf("publickey  = <%s> -> <%s>\n"
853                        , f1_publickey? f1_publickey: ""
854                        , f2_publickey? f2_publickey: ""
855                       );
856                 printf("       old = <%s>\n", f3_publickey? f3_publickey: "");
857                 printf("privatekey = <%s> -> <%s>\n"
858                        , f1_privatekey? f1_privatekey: ""
859                        , f2_privatekey? f2_privatekey: ""
860                       );
861                 printf("       old = <%s>\n", f3_privatekey? f3_privatekey: "");
862                 printf("dhparms    = <%s> -> <%s>\n"
863                        , f1_dhparms? f1_dhparms: ""
864                        , f2_dhparms? f2_dhparms: ""
865                       );
866                 printf("       old = <%s>\n", f3_dhparms? f3_dhparms: "");
867         }
868
869         /*
870           for each file we're going to install:
871           - make the new timestamped file
872           - if (!nosymlinks)
873           - - remove any old link
874           - - make the link
875           - - if (trash)
876           - - - remove the old file
877         */
878
879         std_mask = umask(sec_mask); /* Get the standard mask */
880         (void) umask(std_mask);
881
882         if (make_md5 && (force || !filep(f1_keys))) {
883                 /*
884                  * Generate 16 random MD5 keys.
885                  */
886                 printf("Generating MD5 key file...\n");
887                 str = newfile(f1_keys, f2_keys, sec_mask, f3_keys);
888                 if (!memorex) {
889                         srandom((u_int)tv.tv_usec);
890                         fprintf(str, "# MD5 key file %s\n# %s", f2_keys,
891                                 ctime((const time_t *) &tv.tv_sec));
892                         for (i = 1; i <= 16; i++) {
893                                 for (j = 0; j < 16; j++) {
894                                         while (1) {
895                                                 temp = random() & 0xff;
896                                                 /*
897                                                 ** Harlan says Karnaugh maps
898                                                 ** are not his friend, and
899                                                 ** compilers can optimize
900                                                 ** this most easily.
901                                                 */
902                                                 if (temp == '#')
903                                                         continue;
904                                                 if (temp > 0x20 && temp < 0x7f)
905                                                         break;
906                                         }
907                                         md5key[j] = (u_char)temp;
908                                 }
909                                 md5key[16] = 0;
910                                 fprintf(str, "%2d M %16s        # MD5 key\n",
911                                         i, md5key);
912                         }
913                 }
914                 if (str) fclose(str);
915                 cleanlinks(f1_keys, f2_keys, f3_keys);
916         }
917
918 #ifdef PUBKEY
919         if (make_rsa && (force || !filep(f1_publickey)
920                          || !filep(f1_privatekey))) {
921                 /*
922                  * Roll the RSA public/private key pair.
923                  */
924                 printf("Generating RSA public/private key pair (%d bits)...\n",
925                        MODULUSLEN);
926                 if (!memorex) {
927                         protokey.bits = MODULUSLEN;
928                         protokey.useFermat4 = 1;
929                         R_RandomInit(&randomstr);
930                         R_GetRandomBytesNeeded(&len, &randomstr);
931                         for (i = 0; i < len; i++) {
932                                 temp = random();
933                                 R_RandomUpdate(&randomstr, (u_char *)&temp, 1);
934                         }
935                         rval = R_GeneratePEMKeys(&rsaref_public,
936                                                  &rsaref_private, &protokey,
937                                                  &randomstr);
938                         if (rval) {
939                                 printf("R_GeneratePEMKeys error %x\n", rval);
940                                 return (-1);
941                         }
942                 }
943
944                 /*
945                  * Generate the file "ntpkey.*" containing the RSA
946                  * private key in printable ASCII format.
947                  */
948                 str = newfile(f1_privatekey, f2_privatekey, sec_mask,
949                               f3_privatekey);
950                 if (!memorex) {
951                         len = sizeof(rsaref_private)
952                             - sizeof(rsaref_private.bits);
953                         modulus = (u_int32)rsaref_private.bits;
954                         fprintf(str, "# RSA private key file %s\n# %s",
955                                 f2_privatekey,  ctime(&tv.tv_sec));
956                         R_EncodePEMBlock(encoded_key, &temp,
957                                          (u_char *)rsaref_private.modulus,
958                                          len);
959                         encoded_key[temp] = '\0';
960                         fprintf(str, "%d %s\n", modulus, encoded_key);
961                 }
962                 if (str) fclose(str);
963                 cleanlinks(f1_privatekey, f2_privatekey, f3_privatekey);
964
965                 /*
966                  * Generate the file "ntpkey_host.*" containing the RSA
967                  * public key in printable ASCII format.
968                  */
969                 str = newfile(f1_publickey, f2_publickey, std_mask,
970                               f3_publickey);
971                 if (!memorex) {
972                         len = sizeof(rsaref_public)
973                             - sizeof(rsaref_public.bits);
974                         modulus = (u_int32)rsaref_public.bits;
975                         fprintf(str, "# RSA public key file %s\n# %s",
976                                 f2_publickey, ctime(&tv.tv_sec));
977                         R_EncodePEMBlock(encoded_key, &temp,
978                                          (u_char *)rsaref_public.modulus, len);
979                         encoded_key[temp] = '\0';
980                         fprintf(str, "%d %s\n", modulus, encoded_key);
981                 }
982                 if (str) fclose(str);
983                 cleanlinks(f1_publickey, f2_publickey, f3_publickey);
984         }
985 #endif /* PUBKEY */
986
987 #ifdef PUBKEY
988         if (make_dh && (force || !filep(f1_dhparms))) {
989                 /*
990                  * Roll the prime and generator for the Diffie-Hellman key
991                  * agreement algorithm.
992                  */
993                 printf("Generating Diffie-Hellman parameters (%d bits)...\n",
994                        PRIMELEN);
995                 str = newfile(f1_dhparms, f2_dhparms, std_mask, f3_dhparms);
996
997                 if (!memorex) {
998                         R_RandomInit(&randomstr);
999                         R_GetRandomBytesNeeded(&len, &randomstr);
1000                         for (i = 0; i < len; i++) {
1001                                 temp = random();
1002                                 R_RandomUpdate(&randomstr, (u_char *)&temp, 1);
1003                         }
1004
1005                         /*
1006                          * Generate the file "ntpkey_dh.*" containing the
1007                          * Diffie-Hellman prime and generator in printable
1008                          * ASCII format.
1009                          */
1010                         len = DH_PRIME_LEN(PRIMELEN);
1011                         dh_params.prime = (u_char *)malloc(len);
1012                         dh_params.generator = (u_char *)malloc(len);
1013                         rval = R_GenerateDHParams(&dh_params, PRIMELEN,
1014                                                   PRIMELEN / 2, &randomstr);
1015                         if (rval) {
1016                                 printf("R_GenerateDHParams error %x\n", rval);
1017                                 return (-1);
1018                         }
1019
1020                         fprintf(str,
1021                                 "# Diffie-Hellman parameter file %s\n# %s",
1022                                 f2_dhparms, ctime(&tv.tv_sec));
1023                         R_EncodePEMBlock(encoded_key, &temp,
1024                                          (u_char *)dh_params.prime,
1025                                          dh_params.primeLen);
1026                         encoded_key[temp] = '\0';
1027                         fprintf(str, "%d %s\n", dh_params.primeLen,
1028                                 encoded_key);
1029                         R_EncodePEMBlock(encoded_key, &temp,
1030                                          (u_char *)dh_params.generator,
1031                                          dh_params.generatorLen);
1032                         encoded_key[temp] = '\0';
1033                         fprintf(str, "%d %s\n", dh_params.generatorLen,
1034                                 encoded_key);
1035                 }
1036                 if (str) fclose(str);
1037                 cleanlinks(f1_dhparms, f2_dhparms, f3_dhparms);
1038         }
1039 #endif /* PUBKEY */
1040
1041         return (0);
1042 }