]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
much cleanup, fixes, and changes from Dave Mills
authorHarlan Stenn <stenn@ntp.org>
Sat, 26 Jan 2008 09:02:52 +0000 (04:02 -0500)
committerHarlan Stenn <stenn@ntp.org>
Sat, 26 Jan 2008 09:02:52 +0000 (04:02 -0500)
bk: 479af73cOUX0Xaf0PinjN5P8Ic6txA

ChangeLog
ntpd/ntp_crypto.c
ntpd/ntp_intres.c
ntpd/ntp_loopfilter.c
ntpd/ntp_monitor.c
ntpd/ntp_peer.c
ntpd/ntp_proto.c
ntpd/ntp_timer.c
ntpd/ntp_util.c

index 9170510a60b520feac24b73a728a12a554ed77e2..5d2f2eb9ecdcafed0e2f7a880e789a3d8a77963a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+* much cleanup, fixes, and changes from Dave Mills.
 * ntp_control.c: LEAPTAB is a filestamp, not an unsigned.  From Dave Mills.
 * ntp_config.c: ntp_minpoll fixes from Dave Mills.
 * ntp-keygen updates from Dave Mills.
index 021e59033f14fe3ecdac22aaf6be3840ced80cc9..ac5f891445f1c321704bf8941a3cfb25b4d8637a 100644 (file)
@@ -126,7 +126,7 @@ struct cert_info *cert_host = NULL; /* host certificate */
 struct pkey_info *pkinfo = NULL; /* key info/value cache */
 struct value hostval;          /* host value */
 struct value pubkey;           /* public key */
-struct value tai_leap;         /* leapseconds table */
+struct value tai_leap;         /* leapseconds values */
 struct pkey_info *iffkey_info = NULL; /* IFF keys */
 struct pkey_info *gqkey_info = NULL; /* GQ keys */
 struct pkey_info *mvkey_info = NULL; /* MV keys */
@@ -645,8 +645,7 @@ crypto_recv(
                         */
                        if (peer->pkey == NULL) {
                                ptr = (u_char *)xinfo->cert.ptr;
-                               cert = d2i_X509(NULL,
-                                   (const u_char **)&ptr,
+                               cert = d2i_X509(NULL, &ptr,
                                    ntohl(xinfo->cert.vallen));
                                peer->pkey = X509_get_pubkey(cert);
                                X509_free(cert);
@@ -1030,7 +1029,7 @@ crypto_recv(
                        break;
 
                /*
-                * Install leapseconds table in symmetric modes. This
+                * Install leapseconds values in symmetric modes. This
                 * table is proventicated to the NIST primary servers,
                 * either by copying the file containing the table from
                 * a NIST server to a trusted server or directly using
@@ -1049,7 +1048,7 @@ crypto_recv(
 
                        /*
                         * Pass the extension field to the transmit
-                        * side. Continue below if a leapseconds table
+                        * side. Continue below if leapseconds values
                         * accompanies the message.
                         */
                        fp = emalloc(len);
@@ -1069,7 +1068,7 @@ crypto_recv(
                        /*
                         * If this is a response, discard the message if
                         * signature not verified with respect to the
-                        * leapsecond table values.
+                        * leapseconds values.
                         */
                        if (peer->cmmd == NULL) {
                                if ((rval = crypto_verify(ep, NULL,
@@ -1091,10 +1090,9 @@ crypto_recv(
                                leap_expire = ntohl(ep->pkt[2]);
                                crypto_update();
                                msyslog(LOG_NOTICE,
-                                   "crypto: leap epoch %lu TAI offset %d expire %lu",
-                                   leap_sec, leap_tai, leap_expire);                           } else if (ntohl(ep->pkt[2]) < leap_expire) {
-                               msyslog(LOG_ERR,
-                                   "crypto: stale leap second values");
+                                   "leap epoch %lu expire %lu TAI offset %d from %s",
+                                   leap_sec, leap_expire, leap_tai,
+                                   stoa(&peer->srcadr));
                        }
                        peer->crypto |= CRYPTO_FLAG_LEAP;
                        peer->flash &= ~TEST8;
@@ -1280,9 +1278,7 @@ crypto_xmit(
         */
        case CRYPTO_CERT | CRYPTO_RESP:
                vallen = ntohl(ep->vallen);
-               if (vallen == 8) {
-                       strcpy(certname, sys_hostname);
-               } else if (vallen == 0 || vallen > MAXHOSTNAME) {
+               if (vallen == 0 || vallen > MAXHOSTNAME) {
                        rval = XEVNT_LEN;
                        break;
 
@@ -1292,15 +1288,14 @@ crypto_xmit(
                }
 
                /*
-                * Find all certificates with matching subject. If a
-                * self-signed, trusted certificate is found, use that.
-                * If not, use the last non self-signed one with
-                * matching subject. A private certificate is never
-                * divulged or signed.
+                * Find all public valid certificates with matching
+                * subject. If a self-signed, trusted certificate is
+                * found, use that certificate. If not, use the last non
+                * self-signed certificate.
                 */
                xp = yp = NULL;
                for (cp = cinfo; cp != NULL; cp = cp->link) {
-                       if (cp->flags & CERT_PRIV)
+                       if (cp->flags & (CERT_PRIV | CERT_ERROR))
                                continue;
 
                        if (strcmp(certname, cp->subject) != 0)
@@ -1477,8 +1472,8 @@ crypto_xmit(
                break;
 
        /*
-        * Send leapseconds table and signature. Use the values from the
-        * tai structure. If no table has been loaded, just send an
+        * Send leapseconds values and signature. Use the values from
+        * the tai structure. If no table has been loaded, just send an
         * empty request.
         */
        case CRYPTO_TAI:
@@ -1692,8 +1687,7 @@ crypto_encrypt(
         */
        len = ntohl(ep->vallen);
        ptr = (u_char *)ep->pkt;
-       pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, (const u_char **)&ptr,
-           len);
+       pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, len);
        if (pkey == NULL) {
                msyslog(LOG_ERR, "crypto_encrypt: %s",
                    ERR_error_string(ERR_get_error(), NULL));
@@ -1780,7 +1774,7 @@ crypto_ident(
                if (peer->ident_pkey != NULL)
                        return (CRYPTO_MV);
        }
-       msyslog(LOG_INFO,
+       msyslog(LOG_NOTICE,
            "crypto_ident: no identity parameters found for group %s",
            peer->issuer);
        return (CRYPTO_NULL);
@@ -2000,7 +1994,7 @@ crypto_update(void)
        EVP_SignUpdate(&ctx, tai_leap.ptr, len);
        if (EVP_SignFinal(&ctx, tai_leap.sig, &len, sign_pkey))
                tai_leap.siglen = htonl(len);
-       if (leap_expire > 0)
+       if (leap_sec > 0)
                crypto_flags |= CRYPTO_FLAG_TAI;
        snprintf(statstr, NTP_MAXSTRLEN, "update at %lu ts %u",
            current_time, ntohl(hostval.tstamp)); 
@@ -2118,35 +2112,38 @@ bighash(
  ***********************************************************************
  *
  * The Schnorr (IFF) identity scheme is intended for use when
- * the ntp-genkeys program does not generate the certificates used in
- * the protocol and the group key cannot be conveyed in the certificate
- * itself. For this purpose, new generations of IFF values must be
- * securely transmitted to all members of the group before use. The
- * scheme is self contained and independent of new generations of host
- * keys, sign keys and certificates.
- *
- * The IFF identity scheme is based on DSA cryptography and algorithms
- * described in Stinson p. 285. The IFF values hide in a DSA cuckoo
- * structure, but only the primes and generator are used. The p is a
- * 512-bit prime, q a 160-bit prime that divides p - 1 and is a qth root
- * of 1 mod p; that is, g^q = 1 mod p. The TA rolls primvate random
- * group key b disguised as a DSA structure member, then computes public
- * key g^(q - b). These values are shared only among group members and
- * never revealed in messages. Alice challenges Bob to confirm identity
- * using the protocol described below.
+ * certificates are generated by some other trusted certificate
+ * authority and the certificate cannot be used to convey public
+ * parameters. There are two kinds of files: encrypted server files that
+ * contain private and public values and nonencrypted client files that
+ * contain only public values. New generations of server files must be
+ * securely transmitted to all servers of the group; client files can be
+ * distributed by any means. The scheme is self contained and
+ * independent of new generations of host keys, sign keys and
+ * certificates.
+ *
+ * The IFF values hide in a DSA cuckoo structure which uses the same
+ * parameters. The values are used by an identity scheme based on DSA
+ * cryptography and described in Stimson p. 285. The p is a 512-bit
+ * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1
+ * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a
+ * private random group key b (0 < b < q) and public key v = g^b, then
+ * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients.
+ * Alice challenges Bob to confirm identity using the protocol described
+ * below.
  *
  * How it works
  *
  * The scheme goes like this. Both Alice and Bob have the public primes
  * p, q and generator g. The TA gives private key b to Bob and public
- * key v = g^(q - a) mod p to Alice.
- *
- * Alice rolls new random challenge r and sends to Bob in the IFF
- * request message. Bob rolls new random k, then computes y = k + b r
- * mod q and x = g^k mod p and sends (y, hash(x)) to Alice in the
- * response message. Besides making the response shorter, the hash makes
- * it effectivey impossible for an intruder to solve for b by observing
- * a number of these messages.
+ * key v to Alice.
+ *
+ * Alice rolls new random challenge r (o < r < q) and sends to Bob in
+ * the IFF request message. Bob rolls new random k (0 < k < q), then
+ * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x))
+ * to Alice in the response message. Besides making the response
+ * shorter, the hash makes it effectivey impossible for an intruder to
+ * solve for b by observing a number of these messages.
  * 
  * Alice receives the response and computes g^y v^r mod p. After a bit
  * of algebra, this simplifies to g^k. If the hash of this result
@@ -2180,7 +2177,7 @@ crypto_alice(
                return (XEVNT_ID);
 
        if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
-               msyslog(LOG_INFO, "crypto_alice: defective key");
+               msyslog(LOG_NOTICE, "crypto_alice: defective key");
                return (XEVNT_PUB);
        }
 
@@ -2247,7 +2244,7 @@ crypto_bob(
         * happened or we are being tormented.
         */
        if (iffkey_info == NULL) {
-               msyslog(LOG_INFO, "crypto_bob: scheme unavailable");
+               msyslog(LOG_NOTICE, "crypto_bob: scheme unavailable");
                return (XEVNT_ID);
        }
        dsa = iffkey_info->pkey->pkey.dsa;
@@ -2344,20 +2341,20 @@ crypto_iff(
         * something awful happened or we are being tormented.
         */
        if (peer->ident_pkey == NULL) {
-               msyslog(LOG_INFO, "crypto_iff: scheme unavailable");
+               msyslog(LOG_NOTICE, "crypto_iff: scheme unavailable");
                return (XEVNT_ID);
        }
        if (ntohl(ep->fstamp) != peer->ident_pkey->fstamp) {
-               msyslog(LOG_INFO, "crypto_iff: invalid filestamp %u",
+               msyslog(LOG_NOTICE, "crypto_iff: invalid filestamp %u",
                    ntohl(ep->fstamp));
                return (XEVNT_FSP);
        }
        if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
-               msyslog(LOG_INFO, "crypto_iff: defective key");
+               msyslog(LOG_NOTICE, "crypto_iff: defective key");
                return (XEVNT_PUB);
        }
        if (peer->iffval == NULL) {
-               msyslog(LOG_INFO, "crypto_iff: missing challenge");
+               msyslog(LOG_NOTICE, "crypto_iff: missing challenge");
                return (XEVNT_ID);
        }
 
@@ -2393,7 +2390,7 @@ crypto_iff(
        if (temp == 0)
                return (XEVNT_OK);
 
-       msyslog(LOG_INFO, "crypto_iff: identity not verified");
+       msyslog(LOG_NOTICE, "crypto_iff: identity not verified");
        return (XEVNT_ID);
 }
 
@@ -2407,20 +2404,25 @@ crypto_iff(
  ***********************************************************************
  *
  * The Guillou-Quisquater (GQ) identity scheme is intended for use when
- * the ntp-genkeys program generates the certificates used in the
- * protocol and the group key can be conveyed in a certificate extension
- * field. The scheme is self contained and independent of new
- * generations of host keys, sign keys and certificates.
- *
- * The GQ identity scheme is based on RSA cryptography and algorithms
- * described in Stinson p. 300 (with errors). The GQ values hide in a
- * RSA cuckoo structure, but only the modulus is used. The 512-bit
- * public modulus is n = p q, where p and q are secret large primes. The
- * TA rolls random group key b disguised as a RSA structure member.
- * Except for the public key, these values are shared only among group
- * members and never revealed in messages.
- *
- * When rolling new certificates, Bob recomputes the private and
+ * the certificate can be used to convey public parameters. The scheme
+ * uses a X509v3 certificate extension field do convey the public key of
+ * a private key known only to servers. There are two kinds of files:
+ * encrypted server files that contain private and public values and
+ * nonencrypted client files that contain only public values. New
+ * generations of server files must be securely transmitted to all
+ * servers of the group; client files can be distributed by any means.
+ * The scheme is self contained and independent of new generations of
+ * host keys and sign keys. The scheme is self contained and independent
+ * of new generations of host keys and sign keys.
+ *
+ * The GQ parameters hide in a RSA cuckoo structure which uses the same
+ * parameters. The values are used by an identity scheme based on RSA
+ * cryptography and described in Stimson p. 300 (with errors). The 512-
+ * bit public modulus is n = p q, where p and q are secret large primes.
+ * The TA rolls private random group key b as RSA exponent. These values
+ * are known to all group members.
+ *
+ * When rolling new certificates, a server recomputes the private and
  * public keys. The private key u is a random roll, while the public key
  * is the inverse obscured by the group key v = (u^-1)^b. These values
  * replace the private and public keys normally generated by the RSA
@@ -2477,7 +2479,7 @@ crypto_alice2(
                return (XEVNT_ID);
 
        if ((rsa = peer->ident_pkey->pkey->pkey.rsa) == NULL) {
-               msyslog(LOG_INFO, "crypto_alice2: defective key");
+               msyslog(LOG_NOTICE, "crypto_alice2: defective key");
                return (XEVNT_PUB);
        }
 
@@ -2544,7 +2546,7 @@ crypto_bob2(
         * happened or we are being tormented.
         */
        if (gqkey_info == NULL) {
-               msyslog(LOG_INFO, "crypto_bob2: scheme unavailable");
+               msyslog(LOG_NOTICE, "crypto_bob2: scheme unavailable");
                return (XEVNT_ID);
        }
        rsa = gqkey_info->pkey->pkey.rsa;
@@ -2644,20 +2646,20 @@ crypto_gq(
         * the remote parameter file if the keys have been refreshed.
         */
        if (peer->ident_pkey == NULL) {
-               msyslog(LOG_INFO, "crypto_gq: scheme unavailable");
+               msyslog(LOG_NOTICE, "crypto_gq: scheme unavailable");
                return (XEVNT_ID);
        }
        if (ntohl(ep->fstamp) < peer->ident_pkey->fstamp) {
-               msyslog(LOG_INFO, "crypto_gq: invalid filestamp %u",
+               msyslog(LOG_NOTICE, "crypto_gq: invalid filestamp %u",
                    ntohl(ep->fstamp));
                return (XEVNT_FSP);
        }
        if ((rsa = peer->ident_pkey->pkey->pkey.rsa) == NULL) {
-               msyslog(LOG_INFO, "crypto_gq: defective key");
+               msyslog(LOG_NOTICE, "crypto_gq: defective key");
                return (XEVNT_PUB);
        }
        if (peer->iffval == NULL) {
-               msyslog(LOG_INFO, "crypto_gq: missing challenge");
+               msyslog(LOG_NOTICE, "crypto_gq: missing challenge");
                return (XEVNT_ID);
        }
 
@@ -2679,7 +2681,7 @@ crypto_gq(
         * Compute v^r y^b mod n.
         */
        if (peer->grpkey == NULL) {
-               msyslog(LOG_INFO, "crypto_gq: missing group key");
+               msyslog(LOG_NOTICE, "crypto_gq: missing group key");
                return (XEVNT_ID);
        }
        BN_mod_exp(v, peer->grpkey, peer->iffval, rsa->n, bctx);
@@ -2699,7 +2701,7 @@ crypto_gq(
        if (temp == 0)
                return (XEVNT_OK);
 
-       msyslog(LOG_INFO, "crypto_gq: identity not verified");
+       msyslog(LOG_NOTICE, "crypto_gq: identity not verified");
        return (XEVNT_ID);
 }
 
@@ -2711,8 +2713,7 @@ crypto_gq(
  * scheme                                                              *
  *                                                                    *
  ***********************************************************************
- */
-/*
+ *
  * The Mu-Varadharajan (MV) cryptosystem was originally intended when
  * servers broadcast messages to clients, but clients never send
  * messages to servers. There is one encryption key for the server and a
@@ -2729,19 +2730,16 @@ crypto_gq(
  * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001,
  * 223-231. The paper has significant errors and serious omissions.
  *
- * Let q be the product of n distinct primes s'[j] (j = 1...n), where
- * each s'[j] has m significant bits. Let p be a prime p = 2 * q + 1, so
- * that q and each s'[j] divide p - 1 and p has M = n * m + 1
- * significant bits. The elements x mod q of Zq with the elements 2 and
- * the primes removed form a field Zq* valid for polynomial arithetic.
- * Let g be a generator of Zp; that is, gcd(g, p - 1) = 1 and g^q = 1
- * mod p. We expect M to be in the 500-bit range and n relatively small,
- * like 25, so the likelihood of a randomly generated element of x mod q
- * of Zq colliding with a factor of p - 1 is very small and can be
- * avoided. Associated with each s'[j] is an element s[j] such that s[j]
- * s'[j] = s'[j] mod q. We find s[j] as the quotient (q + s'[j]) /
- * s'[j]. These are the parameters of the scheme and they are expensive
- * to compute.
+ * Let q be the product of n distinct primes s1[j] (j = 1...n), where
+ * each s1[j] has m significant bits. Let p be a prime p = 2 * q + 1, so
+ * that q and each s1[j] divide p - 1 and p has M = n * m + 1
+ * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1)
+ * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then
+ * project into Zp* as exponents of g. Sometimes we have to compute an
+ * inverse b^-1 of random b in Zq, but for that purpose we require
+ * gcd(b, q) = 1. We expect M to be in the 500-bit range and n
+ * relatively small, like 30. These are the parameters of the scheme and
+ * they are expensive to compute.
  *
  * We set up an instance of the scheme as follows. A set of random
  * values x[j] mod q (j = 1...n), are generated as the zeros of a
@@ -2752,31 +2750,34 @@ crypto_gq(
  * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used
  * to construct the decryption keys. The devil is in the details.
  *
+ * This routine generates a private server encryption file including the
+ * private encryption key E and partial decryption keys gbar and ghat.
+ * It then generates public client decryption files including the public
+ * keys xbar[j] and xhat[j] for each client j. The partial decryption
+ * files are used to compute the inverse of E. These values are suitably
+ * blinded so secrets are not revealed.
+ *
  * The distinguishing characteristic of this scheme is the capability to
  * revoke keys. Included in the calculation of E, gbar and ghat is the
- * product s = prod(s'[j]) (j = 1...n) above. If the factor s'[j] is
+ * product s = prod(s1[j]) (j = 1...n) above. If the factor s1[j] is
  * subsequently removed from the product and E, gbar and ghat
  * recomputed, the jth client will no longer be able to compute E^-1 and
- * thus unable to decrypt the block.
+ * thus unable to decrypt the messageblock.
  *
  * How it works
  *
- * The scheme goes like this. Bob has the server values (p, A, q, gbar,
- * ghat) and Alice the client values (p, xbar, xhat).
+ * The scheme goes like this. Bob has the server values (p, E, q, gbar,
+ * ghat) and Alice has the client values (p, xbar, xhat).
  *
- * Alice rolls new random challenge r (0 < r < p) and sends to Bob in
- * the MV request message. Bob rolls new random k (0 < k < q), encrypts
- * y = A^k mod p (a permutation) and sends (hash(y), gbar^k, ghat^k) to
- * Alice.
+ * Alice rolls new random nonce r mod p and sends to Bob in the MV
+ * request message. Bob rolls random nonce k mod q, encrypts y = r E^k
+ * mod p and sends (y, gbar^k, ghat^k) to Alice.
  * 
- * Alice receives the response and computes the decryption key (the
- * inverse permutation) from previously obtained (xbar, xhat) and
- * (gbar^k, ghat^k) in the message. She computes the inverse, which is
- * unique by reasons explained in the ntp-keygen.c program sources. If
- * the hash of this result matches hash(y), Alice knows that Bob has the
- * group key b. The signed response binds this knowledge to Bob's
- * private key and the public key previously received in his
- * certificate.
+ * Alice receives the response and computes the inverse (E^k)^-1 from
+ * the partial decryption keys gbar^k, ghat^k, xbar and xhat. She then
+ * decrypts y and verifies it matches the original r. The signed
+ * response binds this knowledge to Bob's private key and the public key
+ * previously received in his certificate.
  *
  * crypto_alice3 - construct Alice's challenge in MV scheme
  *
@@ -2804,7 +2805,7 @@ crypto_alice3(
                return (XEVNT_ID);
 
        if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
-               msyslog(LOG_INFO, "crypto_alice3: defective key");
+               msyslog(LOG_NOTICE, "crypto_alice3: defective key");
                return (XEVNT_PUB);
        }
 
@@ -2870,7 +2871,7 @@ crypto_bob3(
         * happened or we are being tormented.
         */
        if (mvkey_info == NULL) {
-               msyslog(LOG_INFO, "crypto_bob3: scheme unavailable");
+               msyslog(LOG_NOTICE, "crypto_bob3: scheme unavailable");
                return (XEVNT_ID);
        }
        dsa = mvkey_info->pkey->pkey.dsa;
@@ -2887,8 +2888,8 @@ crypto_bob3(
 
        /*
         * Bob rolls random k (0 < k < q), making sure it is not a
-        * factor of q. He then computes y = A^k r and sends (hash(y),
-        * gbar^k, ghat^k) to Alice.
+        * factor of q. He then computes y = r A^k and sends (y, gbar^k,
+        * and ghat^k) to Alice.
         */
        bctx = BN_CTX_new(); k = BN_new(); u = BN_new();
        sdsa = DSA_new();
@@ -2900,15 +2901,14 @@ crypto_bob3(
                if (BN_is_one(u))
                        break;
        }
-       BN_mod_exp(u, dsa->g, k, dsa->p, bctx); /* A r */
-       BN_mod_mul(u, u, r, dsa->p, bctx);
-       bighash(u, sdsa->p);
+       BN_mod_exp(u, dsa->g, k, dsa->p, bctx); /* A^k r */
+       BN_mod_mul(sdsa->p, u, r, dsa->p, bctx);
        BN_mod_exp(sdsa->q, dsa->priv_key, k, dsa->p, bctx); /* gbar */
        BN_mod_exp(sdsa->g, dsa->pub_key, k, dsa->p, bctx); /* ghat */
        BN_CTX_free(bctx); BN_free(k); BN_free(r); BN_free(u);
 #ifdef DEBUG
        if (debug > 1)
-               DSA_print_fp(stdout, dsa, 0);
+               DSA_print_fp(stdout, sdsa, 0);
 #endif
 
        /*
@@ -2973,25 +2973,25 @@ crypto_mv(
         * something awful happened or we are being tormented.
         */
        if (peer->ident_pkey == NULL) {
-               msyslog(LOG_INFO, "crypto_mv: scheme unavailable");
+               msyslog(LOG_NOTICE, "crypto_mv: scheme unavailable");
                return (XEVNT_ID);
        }
        if (ntohl(ep->fstamp) != peer->ident_pkey->fstamp) {
-               msyslog(LOG_INFO, "crypto_mv: invalid filestamp %u",
+               msyslog(LOG_NOTICE, "crypto_mv: invalid filestamp %u",
                    ntohl(ep->fstamp));
                return (XEVNT_FSP);
        }
        if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
-               msyslog(LOG_INFO, "crypto_mv: defective key");
+               msyslog(LOG_NOTICE, "crypto_mv: defective key");
                return (XEVNT_PUB);
        }
        if (peer->iffval == NULL) {
-               msyslog(LOG_INFO, "crypto_mv: missing challenge");
+               msyslog(LOG_NOTICE, "crypto_mv: missing challenge");
                return (XEVNT_ID);
        }
 
        /*
-        * Extract the (hash(y), gbar, ghat) values from the response.
+        * Extract the y, gbar and ghat values from the response.
         */
        bctx = BN_CTX_new(); k = BN_new(); u = BN_new(); v = BN_new();
        len = ntohl(ep->vallen);
@@ -3003,19 +3003,17 @@ crypto_mv(
        }
 
        /*
-        * Compute (gbar^xhat ghat^xbar)^-1 mod p.
+        * Compute (gbar^xhat ghat^xbar) mod p.
         */
        BN_mod_exp(u, sdsa->q, dsa->pub_key, dsa->p, bctx);
        BN_mod_exp(v, sdsa->g, dsa->priv_key, dsa->p, bctx);
        BN_mod_mul(u, u, v, dsa->p, bctx);
-       BN_mod_inverse(u, u, dsa->p, bctx);
-       BN_mod_mul(v, u, peer->iffval, dsa->p, bctx);
+       BN_mod_mul(u, u, sdsa->p, dsa->p, bctx);
 
        /*
-        * The result should match the hash of r mod p.
+        * The result should match r.
         */
-       bighash(v, v);
-       temp = BN_cmp(v, sdsa->p);
+       temp = BN_cmp(u, peer->iffval);
        BN_CTX_free(bctx); BN_free(k); BN_free(u); BN_free(v);
        BN_free(peer->iffval);
        peer->iffval = NULL;
@@ -3023,7 +3021,7 @@ crypto_mv(
        if (temp == 0)
                return (XEVNT_OK);
 
-       msyslog(LOG_INFO, "crypto_mv: identity not verified");
+       msyslog(LOG_NOTICE, "crypto_mv: identity not verified");
        return (XEVNT_ID);
 }
 
@@ -3097,8 +3095,7 @@ cert_sign(
                return (XEVNT_TSP);
 
        ptr = (u_char *)ep->pkt;
-       if ((req = d2i_X509(NULL, (const u_char **)&ptr,
-                   ntohl(ep->vallen))) == NULL) {
+       if ((req = d2i_X509(NULL, &ptr, ntohl(ep->vallen))) == NULL) {
                msyslog(LOG_ERR, "cert_sign: %s",
                    ERR_error_string(ERR_get_error(), NULL));
                return (XEVNT_CRT);
@@ -3114,9 +3111,10 @@ cert_sign(
        }
 
        /*
-        * Generate X509 certificate signed by this server. For this
-        * purpose the issuer name is the server name. Also copy any
-        * extensions that might be present.
+        * Generate X509 certificate signed by this server. If this is a
+        * trusted host, the issuer name is the group name; otherwise,
+        * it is the host name. Also copy any extensions that might be
+        * present.
         */
        cert = X509_new();
        X509_set_version(cert, X509_get_version(req));
@@ -3127,7 +3125,7 @@ cert_sign(
        X509_gmtime_adj(X509_get_notAfter(cert), YEAR);
        subj = X509_get_issuer_name(cert);
        X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
-           (u_char *)sys_hostname, strlen(sys_hostname), -1, 0);
+           hostval.ptr, strlen(hostval.ptr), -1, 0);
        subj = X509_get_subject_name(req);
        X509_set_subject_name(cert, subj);
        X509_set_pubkey(cert, pkey);
@@ -3162,7 +3160,7 @@ cert_sign(
        vp->vallen = htonl(len);
        vp->ptr = emalloc(len);
        ptr = vp->ptr;
-       i2d_X509(cert, (u_char **)&ptr);
+       i2d_X509(cert, &ptr);
        vp->siglen = 0;
        vp->sig = emalloc(sign_siglen);
        EVP_SignInit(&ctx, sign_digest);
@@ -3203,8 +3201,7 @@ cert_valid(
                return (XEVNT_OK);
 
        ptr = (u_char *)cinf->cert.ptr;
-       cert = d2i_X509(NULL, (const u_char **)&ptr,
-           ntohl(cinf->cert.vallen));
+       cert = d2i_X509(NULL, &ptr, ntohl(cinf->cert.vallen));
        if (cert == NULL || !X509_verify(cert, pkey))
                return (XEVNT_VFY);
 
@@ -3382,18 +3379,15 @@ cert_parse(
        X509_EXTENSION *ext;    /* X509v3 extension */
        struct cert_info *ret;  /* certificate info/value */
        BIO     *bp;
-       X509V3_EXT_METHOD *method;
        char    pathbuf[MAXFILENAME];
-       u_char  *uptr;
-       const char *ptr;
+       u_char  *ptr;
        int     temp, cnt, i;
 
        /*
         * Decode ASN.1 objects and construct certificate structure.
         */
-       uptr = asn1cert;
-       if ((cert = d2i_X509(NULL, (const u_char **)&uptr, len)) ==
-           NULL) {
+       ptr = asn1cert;
+       if ((cert = d2i_X509(NULL, &ptr, len)) == NULL) {
                msyslog(LOG_ERR, "cert_parse: %s",
                    ERR_error_string(ERR_get_error(), NULL));
                return (NULL);
@@ -3420,7 +3414,7 @@ cert_parse(
            MAXFILENAME);
        ptr = strstr(pathbuf, "CN=");
        if (ptr == NULL) {
-               msyslog(LOG_INFO, "cert_parse: invalid subject %s",
+               msyslog(LOG_NOTICE, "cert_parse: invalid subject %s",
                    pathbuf);
                cert_free(ret);
                X509_free(cert);
@@ -3443,7 +3437,7 @@ cert_parse(
        X509_NAME_oneline(X509_get_issuer_name(cert), pathbuf,
            MAXFILENAME);
        if ((ptr = strstr(pathbuf, "CN=")) == NULL) {
-               msyslog(LOG_INFO, "cert_parse: invalid issuer %s",
+               msyslog(LOG_NOTICE, "cert_parse: invalid issuer %s",
                    pathbuf);
                cert_free(ret);
                X509_free(cert);
@@ -3462,7 +3456,6 @@ cert_parse(
        cnt = X509_get_ext_count(cert);
        for (i = 0; i < cnt; i++) {
                ext = X509_get_ext(cert, i);
-               method = X509V3_EXT_get(ext);
                temp = OBJ_obj2nid(ext->object);
                switch (temp) {
 
@@ -3510,7 +3503,7 @@ cert_parse(
                 * If certificate is self signed, verify signature.
                 */
                if (!X509_verify(cert, ret->pkey)) {
-                       msyslog(LOG_INFO,
+                       msyslog(LOG_NOTICE,
                            "cert_parse: signature not verified %s",
                            ret->subject);
                        cert_free(ret);
@@ -3522,8 +3515,8 @@ cert_parse(
                /*
                 * Check for a certificate loop.
                 */
-               if (strcmp(sys_hostname, ret->issuer) == 0) {
-                       msyslog(LOG_INFO,
+               if (strcmp(hostval.ptr, ret->issuer) == 0) {
+                       msyslog(LOG_NOTICE,
                            "cert_parse: certificate trail loop %s",
                            ret->subject);
                        cert_free(ret);
@@ -3537,7 +3530,7 @@ cert_parse(
         * be retroactive.
         */
        if (ret->first > ret->last || ret->first < fstamp) {
-               msyslog(LOG_INFO,
+               msyslog(LOG_NOTICE,
                    "cert_parse: invalid times %s first %u last %u fstamp %u",
                    ret->subject, ret->first, ret->last, fstamp);
                cert_free(ret);
@@ -3770,7 +3763,7 @@ crypto_cert(
        fclose(str);
        free(header);
        if (strcmp(name, "CERTIFICATE") != 0) {
-               msyslog(LOG_INFO, "crypto_cert: wrong PEM type %s",
+               msyslog(LOG_NOTICE, "crypto_cert: wrong PEM type %s",
                    name);
                free(name);
                free(data);
@@ -3829,7 +3822,7 @@ crypto_setup(void)
         * the case of multiple crypto commands.
         */
        if (crypto_flags & CRYPTO_FLAG_ENAB) {
-               msyslog(LOG_ERR,
+               msyslog(LOG_NOTICE,
                    "crypto_setup: spurious crypto command");
                return;
        }
@@ -3917,8 +3910,6 @@ crypto_setup(void)
        host_pkey = pinfo->pkey;
        sign_pkey = host_pkey;
        hostval.fstamp = htonl(pinfo->fstamp);
-       hostval.vallen = htonl(strlen(sys_hostname));
-       hostval.ptr = (u_char *)sys_hostname;
        
        /*
         * Construct public key extension field for agreement scheme.
@@ -3954,21 +3945,11 @@ crypto_setup(void)
                    filename);
                exit (-1);
        }
+       cert_host = cinfo;
        sign_digest = cinfo->digest;
        if (cinfo->flags & CERT_PRIV)
                crypto_flags |= CRYPTO_FLAG_PRIV;
 
-       /*
-        * The subject and host names must match.
-        */
-       if (!(cinfo->flags & CERT_PRIV) && strcmp(cinfo->subject,
-           sys_hostname) != 0) {
-               msyslog(LOG_ERR,
-                   "crypto_setup: certificate %s not for this host %s",
-                   filename, sys_hostname);
-               exit (-1);
-       }
-
        /*
         * The certificate must be self-signed.
         */
@@ -3978,30 +3959,28 @@ crypto_setup(void)
                    filename);
                exit (-1);
        }
+       hostval.vallen = htonl(strlen(cinfo->subject));
+       hostval.ptr = cinfo->subject;
 
        /*
-        * On trusted hosts the subject and group names must match.
+        * If trusted certificate, the subject name must match the group
+        * name.
         */
        if (cinfo->flags & CERT_TRUST) {
                if (sys_groupname == NULL) {
+                       sys_groupname = hostval.ptr;
+               } else if (strcmp(hostval.ptr, sys_groupname) != 0) {
                        msyslog(LOG_ERR,
-                           "crypto_setup: trusted host %s missing group name",
-                           cinfo->subject);
-                       exit (-1);
-               }
-               if (strcmp(cinfo->subject, sys_groupname) != 0) {
-                       msyslog(LOG_ERR,
-                           "crypto_setup: trusted host %s name and group name %s mismatch",
-                           cinfo->subject, sys_groupname);
+                           "crypto_setup: trusted certificate name %s does not match group name %s",
+                           hostval.ptr, sys_groupname);
                        exit (-1);
                }
        }
-       cert_host = cinfo;
        if (sys_groupname != NULL) {
 
                /*
                 * Load optional IFF parameters from file
-                * "ntpkey_iff_<groupname>".
+                * "ntpkey_iffkey_<groupname>".
                 */
                snprintf(filename, MAXFILENAME, "ntpkey_iffkey_%s",
                    sys_groupname);
@@ -4011,7 +3990,7 @@ crypto_setup(void)
 
                /*
                 * Load optional GQ parameters from file
-                * "ntpkey_gq_<groupname>".
+                * "ntpkey_gqkey_<groupname>".
                 */
                snprintf(filename, MAXFILENAME, "ntpkey_gqkey_%s",
                    sys_groupname);
@@ -4021,7 +4000,7 @@ crypto_setup(void)
 
                /*
                 * Load optional MV parameters from file
-                * "ntpkey_mv_<groupname>".
+                * "ntpkey_mvkey_<groupname>".
                 */
                snprintf(filename, MAXFILENAME, "ntpkey_mvkey_%s",
                    sys_groupname);
index 782df82b044c2eb7d2423e531f20869c59c01848..7fbe2c03d23af2f0c0e44ef381bbd669baff5ab7 100644 (file)
@@ -1044,14 +1044,15 @@ readconf(
                                intval[TOK_VERSION], name);
                        resolver_exit(1);
                }
-               if (intval[TOK_MINPOLL] < NTP_MINPOLL ||
-                   intval[TOK_MINPOLL] > NTP_MAXPOLL) {
+               if (intval[TOK_MINPOLL] < ntp_minpoll ||
+                   intval[TOK_MINPOLL] > ntp_minpoll) {
+
                        msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s",
                                intval[TOK_MINPOLL], name);
                        resolver_exit(1);
                }
 
-               if (intval[TOK_MAXPOLL] < NTP_MINPOLL ||
+               if (intval[TOK_MAXPOLL] < ntp_minpoll ||
                    intval[TOK_MAXPOLL] > NTP_MAXPOLL) {
                        msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s",
                                intval[TOK_MAXPOLL], name);
index 9090c9cc29d620f3b13b109852aa555cd26e5379..c705877037102b9b9123e2dcba93897ca7adbbc8 100644 (file)
@@ -47,6 +47,8 @@
 #define CLOCK_LIMIT    30      /* poll-adjust threshold */
 #define CLOCK_PGATE    4.      /* poll-adjust gate */
 #define PPS_MAXAGE     120     /* kernel pps signal timeout (s) */
+#define        FREQTOD(x)      ((x) / 65536e6) /* NTP to double */ 
+#define        DTOFREQ(x)      ((int32)((x) * 65536e6)) /* NTP to double */
 
 /*
  * Clock discipline state machine. This is used to control the
  * timewarp.
  *
  *     State   < step          > step          Comments
- *     ====================================================
- *     NSET    FREQ            step, FREQ      no ntp.drift
+ *     ========================================================
+ *     NSET    FREQ            step, FREQ      no frequency set
  *
- *     FSET    SYNC            step, SYNC      ntp.drift
+ *     FSET    SYNC            step, SYNC      frequency set
  *
  *     FREQ    if (mu < 900)   if (mu < 900)   set freq
  *                 ignore          ignore
  *     SPIK    SYNC            step, SYNC      set phase
  */
 #define S_NSET 0               /* clock never set */
-#define S_FSET 1               /* frequency set from the drift file */
+#define S_FSET 1               /* frequency set */
 #define S_SPIK 2               /* spike detected */
 #define S_FREQ 3               /* frequency mode */
 #define S_SYNC 4               /* clock synchronized */
 
 /*
  * Kernel PLL/PPS state machine. This is used with the kernel PLL
- * modifications described in the README.kernel file.
+ * modifications described in the documentation.
  *
  * If kernel support for the ntp_adjtime() system call is available, the
  * ntp_control flag is set. The ntp_enable and kern_enable flags can be
@@ -134,10 +136,14 @@ u_long    clock_epoch;            /* interval since last update */
 u_long pps_control;            /* last pps update */
 u_int  sys_tai;                /* TAI offset from UTC */
 static void rstclock (int, double); /* transition function */
+static double direct_freq(double); /* direct set frequency */
 
 #ifdef KERNEL_PLL
-struct timex ntv;              /* kernel API parameters */
-int    pll_status;             /* status bits for kernel pll */
+static struct timex ntv;       /* ntp_adjtime() parameters */
+int    pll_status;             /* last kernel status bits */
+#if defined(STA_NANO) && NTP_API == 4
+static u_int loop_tai;         /* last TAI offset */
+#endif /* STA_NANO */
 #endif /* KERNEL_PLL */
 
 /*
@@ -156,7 +162,7 @@ int mode_ntpdate = FALSE;   /* exit on first clock set */
  * Clock state machine variables
  */
 int    state;                  /* clock discipline state */
-u_char sys_poll = NTP_MINPOLL; /* time constant/poll (log2 s) */
+u_char sys_poll = NTP_MINPOLL; /* time constant/poll (log2 s) */
 int    tc_counter;             /* jiggle counter */
 double last_offset;            /* last offset (s) */
 int    clock_stepcnt;          /* step counter */
@@ -188,9 +194,10 @@ void
 init_loopfilter(void)
 {
        /*
-        * Initialize state variables. Initially, we expect no drift
-        * file, so set the state to S_NSET. If a drift file is present,
-        * it will be detected later and the state set to S_FSET.
+        * Initialize state variables. Initially, we expect no frequency
+        * file, so set the state to S_NSET. If a frequency file is
+        * present, it will be detected later and the state set to
+        * S_FSET.
         */
        rstclock(S_NSET, 0);
        clock_jitter = LOGTOD(sys_precision);
@@ -217,9 +224,7 @@ local_clock(
 {
        int     rval;           /* return code */
        int     osys_poll;      /* old system poll */
-       double  flladj;         /* FLL frequency adjustment (ppm) */
-       double  plladj;         /* PLL frequency adjustment (ppm) */
-       double  clock_frequency; /* clock frequency adjustment (ppm) */
+       double  clock_frequency; /* clock frequency */
        double  dtemp, etemp;   /* double temps */
 
        /*
@@ -255,16 +260,13 @@ local_clock(
        }
 
        /*
-        * If simulating ntpdate, set the clock directly, rather than
-        * using the discipline. The clock_max defines the step
-        * threshold, above which the clock will be stepped instead of
-        * slewed. The value defaults to 128 ms, but can be set to even
-        * unreasonable values. If set to zero, the clock will never be
-        * stepped. Note that a slew will persist beyond the life of
-        * this program.
-        *
-        * Note that if ntpdate is active, the terminal does not detach,
-        * so the termination comments print directly to the console.
+        * This section simulates ntpdate. If the offset exceeds the
+        * step threshold (128 ms), step the clock to that time and
+        * exit. Othewise, slew the clock to that time and exit. Note
+        * that the slew will persist and eventually complete beyond the
+        * life of this program. Note that while ntpdate is active, the
+        * terminal does not detach, so the termination message prints
+        * directly to the terminal.
         */
        if (mode_ntpdate) {
                if (fabs(fp_offset) > clock_max && clock_max > 0) {
@@ -314,16 +316,16 @@ local_clock(
        }
 
        /*
-        * Clock state machine transition function. This is where the
-        * action is and defines how the system reacts to large phase
-        * and frequency errors. There are two main regimes: when the
-        * offset exceeds the step threshold and when it does not.
-        * However, if the step threshold is set to zero, a step will
-        * never occur. See the instruction manual for the details how
-        * these actions interact with the command line options.
+        * Clock state machine transition function which defines how the
+        * system reacts to large phase and frequency excursion. There
+        * are two main regimes: when the offset exceeds the step
+        * threshold (128 ms) and when it does not. Under certain
+        * conditions updates are suspended until the stepout theshold
+        * (900 s) is exceeded. See the documentation on how these
+        * thresholds interact with commands and command line options. 
         *
         * Note the kernel is disabled if step is disabled or greater
-        * than 0.5 s. 
+        * than 0.5 s or in ntpdate mode.
         */
        osys_poll = sys_poll;
        if (sys_poll < peer->minpoll)
@@ -331,7 +333,7 @@ local_clock(
        if (sys_poll > peer->maxpoll)
                sys_poll = peer->maxpoll;
        clock_epoch += mu;
-       clock_frequency = flladj = plladj = 0;
+       clock_frequency = drift_comp;
        rval = 1;
        if (fabs(fp_offset) > clock_max && clock_max > 0) {
                switch (state) {
@@ -354,8 +356,7 @@ local_clock(
                        if (clock_epoch < clock_minstep)
                                return (0);
 
-                       clock_frequency = (fp_offset - clock_offset) /
-                           clock_epoch;
+                       clock_frequency = direct_freq(fp_offset);
 
                        /* fall through to S_SPIK */
 
@@ -384,14 +385,14 @@ local_clock(
                 * from the frequency file. Since the time is outside
                 * the step threshold, the clock is stepped immediately,
                 * rather than after the stepout interval. Guys get
-                * nervous if it takes 17 minutes to set the clock for
+                * nervous if it takes 15 minutes to set the clock for
                 * the first time.
                 *
                 * In S_FREQ and S_SPIK states the stepout threshold has
                 * expired and the phase is still above the step
                 * threshold. Note that a single spike greater than the
-                * step threshold is always suppressed, even at the
-                * longer poll intervals.
+                * step threshold is always suppressed, even with a
+                * long time constant.
                 */ 
                default:
                        step_systime(fp_offset);
@@ -445,18 +446,19 @@ local_clock(
 
                /*
                 * In S_FREQ state ignore updates until the stepout
-                * threshold. After that, correct the phase and
-                * frequency and switch to S_SYNC state.
+                * threshold. After that, compute the new frequency, but
+                * do not adjust the phase or frequency until the next
+                * update.
                 */
                case S_FREQ:
                        if (clock_epoch < clock_minstep)
                                return (0);
 
-                       clock_frequency = (fp_offset - clock_offset) /
-                           clock_epoch;
-                       rstclock(S_SYNC, fp_offset);
+                       clock_frequency = direct_freq(fp_offset);
+                       rstclock(S_SYNC, 0);
                        break;
 
+
                /*
                 * We get here by default in S_SYNC and S_SPIK states.
                 * Here we compute the frequency update due to PLL and
@@ -467,7 +469,7 @@ local_clock(
 
                        /*
                         * The FLL and PLL frequency gain constants
-                        * depend on the poll interval and Allan
+                        * depend on the time constant and Allan
                         * intercept. The PLL is always used, but
                         * becomes ineffective above the Allan
                         * intercept. The FLL is not used below one-half
@@ -476,21 +478,22 @@ local_clock(
                         */
                        if (sys_poll > allan_xpt - 1) {
                                dtemp = CLOCK_FLL - sys_poll;
-                               flladj = (fp_offset - clock_offset) /
-                                   (max(clock_epoch, allan_xpt) *
-                                   dtemp);
+                               clock_frequency += (fp_offset -
+                                   last_offset) / (max(clock_epoch,
+                                   allan_xpt) * dtemp);
                        }
 
                        /*
                         * For the PLL the integration interval
                         * (numerator) is the minimum of the update
-                        * interval and poll interval. This allows
+                        * interval and time constant. This allows
                         * oversampling, but not undersampling.
                         */ 
                        etemp = min(clock_epoch,
                            (u_long)ULOGTOD(sys_poll));
                        dtemp = 4 * CLOCK_PLL * ULOGTOD(sys_poll);
-                       plladj = fp_offset * etemp / (dtemp * dtemp);
+                       clock_frequency += fp_offset * etemp / (dtemp *
+                           dtemp);
                        rstclock(S_SYNC, fp_offset);
                        break;
                }
@@ -547,17 +550,6 @@ local_clock(
                            dtemp);
                        ntv.constant = sys_poll - 4;
 #endif /* STA_NANO */
-
-                       /*
-                        * The frequency is set directly only if
-                        * clock_frequency is nonzero coming out of FREQ
-                        * state.
-                        */
-                       if (clock_frequency != 0) {
-                               ntv.modes |= MOD_FREQUENCY;
-                               ntv.freq = (int32)((clock_frequency +
-                                   drift_comp) * 65536e6);
-                       }
                        ntv.esterror = (u_int32)(clock_jitter * 1e6);
                        ntv.maxerror = (u_int32)((sys_rootdelay / 2 +
                            sys_rootdisp) * 1e6);
@@ -578,17 +570,10 @@ local_clock(
                                ntv.status &= ~(STA_PPSFREQ |
                                    STA_PPSTIME);
                        }
-
-                       /*
-                        * If less than 23 hours remain before a leap,
-                        * set the kernel leap bits.
-                        */
-                       if (leap_sec > 0 && leap_sec < 23 * 3600) {
-                               if (sys_leap == LEAP_ADDSECOND)
-                                       ntv.status |= STA_INS;
-                               else if (sys_leap == LEAP_DELSECOND)
-                                       ntv.status |= STA_DEL;
-                       }
+                       if (sys_leap == LEAP_ADDSECOND)
+                               ntv.status |= STA_INS;
+                       else if (sys_leap == LEAP_DELSECOND)
+                               ntv.status |= STA_DEL;
                }
 
                /*
@@ -597,14 +582,13 @@ local_clock(
                 * frequency and pretend we did it here.
                 */
                if (ntp_adjtime(&ntv) == TIME_ERROR) {
-                       NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
-                           msyslog(LOG_NOTICE,
-                           "kernel time sync error %04x", ntv.status);
                        ntv.status &= ~(STA_PPSFREQ | STA_PPSTIME);
+                       msyslog(LOG_ERR,
+                           "kernel time sync error %04x", ntv.status);
                } else {
                        if ((ntv.status ^ pll_status) & ~STA_FLL)
-                               NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
-                                   msyslog(LOG_NOTICE,
+                               NLOG(NLOG_SYNCSTATUS)
+                               msyslog(LOG_INFO,
                                    "kernel time sync status change %04x",
                                    ntv.status);
                }
@@ -614,8 +598,7 @@ local_clock(
 #else /* STA_NANO */
                clock_offset = ntv.offset / 1e6;
 #endif /* STA_NANO */
-               clock_frequency = ntv.freq / 65536e6;
-               flladj = plladj = 0;
+               clock_frequency = FREQTOD(ntv.freq);
 
                /*
                 * If the kernel PPS is lit, monitor its performance.
@@ -628,28 +611,27 @@ local_clock(
                        clock_jitter = ntv.jitter / 1e6;
 #endif /* STA_NANO */
                }
-       } else {
-#endif /* KERNEL_PLL */
+
+#if defined(STA_NANO) && NTP_API == 4
                /*
-                * We get here if the kernel discipline is not enabled.
-                * Adjust the clock frequency as the sum of the directly
-                * computed frequency (if measured) and the PLL and FLL
-                * increments.
+                * If the TAI changes, update the kernel TAI.
                 */
-               clock_frequency = drift_comp + clock_frequency +
-                   flladj + plladj;
-#ifdef KERNEL_PLL
+               if (loop_tai != sys_tai) {
+                       loop_tai = sys_tai;
+                       ntv.modes = MOD_TAI;
+                       ntv.constant = sys_tai;
+                       ntp_adjtime(&ntv);
+               }
+#endif /* STA_NANO */
        }
 #endif /* KERNEL_PLL */
 
        /*
         * Clamp the frequency within the tolerance range and calculate
-        * the frequency change since the last update.
+        * the frequency difference since the last update.
         */
        if (fabs(clock_frequency) > NTP_MAXFREQ)
-               NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
-                   msyslog(LOG_NOTICE,
+               msyslog(LOG_NOTICE,
                    "frequency error %.0f PPM exceeds tolerance %.0f PPM",
                    clock_frequency * 1e6, NTP_MAXFREQ * 1e6);
        dtemp = SQUARE(clock_frequency - drift_comp);
@@ -661,15 +643,16 @@ local_clock(
                drift_comp = clock_frequency;
 
        /*
-        * Calculate the wander as the exponentially weighted frequency
-        * differences. Enable the frequency file to be written.
+        * Calculate the wander as the exponentially weighted RMS
+        * frequency differences. Record the change for the frequency
+        * file update.
         */
        etemp = SQUARE(clock_stability);
        clock_stability = SQRT(etemp + (dtemp - etemp) / CLOCK_AVG);
        drift_file_sw = TRUE;
 
        /*
-        * Here we adjust the poll interval by comparing the current
+        * Here we adjust the timeconstan by comparing the current
         * offset with the clock jitter. If the offset is less than the
         * clock jitter times a constant, then the averaging interval is
         * increased, otherwise it is decreased. A bit of hysteresis
@@ -696,7 +679,7 @@ local_clock(
        }
 
        /*
-        * If the poll interval has changed, update the poll variables.
+        * If the time constant has changed, update the poll variables.
         */
        if (osys_poll != sys_poll)
                poll_update(peer, sys_poll);
@@ -707,11 +690,11 @@ local_clock(
        record_loop_stats(clock_offset, drift_comp, clock_jitter,
            clock_stability, sys_poll);
 #ifdef DEBUG
-       if (debug > 1)
+       if (debug)
                printf(
-                   "local_clock: jitr %.6f freq %.3f stab %.6f thres %.6f\n",
-                   clock_jitter, drift_comp * 1e6, clock_stability *
-                   1e6, wander_threshold * 1e6);
+                   "local_clock: offset %.9f jitr %.6f freq %.3f stab %.6f poll %d\n",
+                   clock_offset, clock_jitter, drift_comp * 1e6,
+                   clock_stability * 1e6, sys_poll);
 #endif /* DEBUG */
        return (rval);
 #endif /* LOCKCLOCK */
@@ -758,8 +741,8 @@ adj_host_clock(
         */
        if (pps_control && current_time - pps_control > PPS_MAXAGE) {
                if (pps_control)
-                       NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
-                           msyslog(LOG_NOTICE, "pps sync disabled");
+                       NLOG(NLOG_SYNCSTATUS)
+                       msyslog(LOG_INFO, "pps sync disabled");
                pps_control = 0;
        }
 
@@ -767,8 +750,8 @@ adj_host_clock(
         * Implement the phase and frequency adjustments. The gain
         * factor (denominator) is not allowed to increase beyond the
         * Allan intercept. It doesn't make sense to average phase noise
-        * beyond this point and it helps to damp residual offset at the
-        * longer poll intervals.
+        * beyond this point and it helps to damp residual offset with a
+        * longer time constant.
         */
        adjustment = clock_offset / (CLOCK_PLL * ULOGTOD(min(sys_poll,
            allan_xpt)));
@@ -779,9 +762,7 @@ adj_host_clock(
 
 
 /*
- * Clock state machine. Enter new state and set state variables. Note we
- * use the time of the last clock filter sample, which may be earlier
- * than the current time.
+ * Clock state machine. Enter new state and set state variables.
  */
 static void
 rstclock(
@@ -790,8 +771,8 @@ rstclock(
        )
 {
 #ifdef DEBUG
-       if (debug)
-               printf("local_clock: intvl %lu offset %.6f freq %.3f state %d poll %d count %d\n",
+       if (debug > 1)
+               printf("local_clock: mu %lu offset %.6f freq %.3f state %d poll %d count %d\n",
                    clock_epoch, offset, drift_comp * 1e6, trans,
                    sys_poll, tc_counter);
 #endif
@@ -800,6 +781,57 @@ rstclock(
        clock_epoch = 0; 
 }
 
+/*
+ * calc_freq - calculate frequency directly
+ *
+ * This is very carefully done. When the offset is first computed at the
+ * first update, a residual frequency component results. Subsequently,
+ * updates are suppresed until the end of the measurement interval while
+ * the offset is amortized. At the end of the interval the frequency is
+ * calculated from the current offset, residual offset, length of the
+ * interval and residual frequency component.
+ */
+static double direct_freq(
+       double  fp_offset
+       )
+{
+#ifdef KERNEL_PLL
+       double  freq = 0;
+
+       /*
+        * If the kernel is enabled, we need the residual offset and
+        * frequency to calculate the frequency correction.
+        */
+       if (pll_control && kern_enable) {
+               memset(&ntv,  0, sizeof(ntv));
+               ntp_adjtime(&ntv);
+#ifdef STA_NANO
+               clock_offset = ntv.offset / 1e9;
+#else /* STA_NANO */
+               clock_offset = ntv.offset / 1e6;
+#endif /* STA_NANO */
+               freq = (fp_offset - clock_offset) / clock_epoch +
+                   FREQTOD(ntv.freq);
+               if (freq != 0) {
+                       ntv.modes = MOD_FREQUENCY;
+                       ntv.freq = DTOFREQ(freq);
+                       ntp_adjtime(&ntv);
+                       msyslog(LOG_NOTICE,
+                           "kernel frequency set %.3f PPM", freq *
+                           1e6);
+                       ntp_adjtime(&ntv);
+               }
+               return (freq);
+       } else {
+               return ((fp_offset - clock_offset) / clock_epoch +
+                   drift_comp);
+       }
+#else /* KERNEL_PLL */
+       return ((fp_offset - clock_offset) / clock_epoch + drift_comp);
+#endif /* KERNEL_PLL */
+
+}
+
 
 /*
  * huff-n'-puff filter
@@ -840,31 +872,23 @@ loop_config(
 #endif
        switch (item) {
 
+       /*
+        * We first assume the kernel supports the ntp_adjtime()
+        * syscall. If that syscall works, initialize the kernel time
+        * variables. Otherwise, continue leaving no harm behind.
+        */
        case LOOP_DRIFTINIT:
-
 #ifndef LOCKCLOCK
 #ifdef KERNEL_PLL
-               /*
-                * Assume the kernel supports the ntp_adjtime() syscall.
-                * If that syscall works, initialize the kernel time
-                * variables. Otherwise, continue leaving no harm
-                * behind. While at it, ask to set nanosecond mode. If
-                * the kernel agrees, rejoice; othewise, it does only
-                * microseconds.
-                */
                if (mode_ntpdate)
                        break;
 
                pll_control = 1;
                memset(&ntv, 0, sizeof(ntv));
-#ifdef STA_NANO
-               ntv.modes = MOD_BITS | MOD_NANO;
-#else /* STA_NANO */
-               ntv.modes = MOD_BITS;
-#endif /* STA_NANO */
+               ntv.modes = MOD_BITS | MOD_FREQUENCY;
+               ntv.status = STA_PLL;
                ntv.maxerror = MAXDISPERSE;
                ntv.esterror = MAXDISPERSE;
-               ntv.status = STA_UNSYNC;
 #ifdef SIGSYS
                /*
                 * Use sigsetjmp() to save state and then call
@@ -900,60 +924,58 @@ loop_config(
                        if (pll_status & STA_CLK)
                                ext_enable = 1;
 #endif /* STA_NANO */
-                       NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
-                           msyslog(LOG_INFO,
-                           "kernel time sync status %04x",
-                           pll_status);
+                       msyslog(LOG_NOTICE,
+                           "kernel time sync enabled %04x",
+                           ntv.status);
                }
 #endif /* KERNEL_PLL */
 #endif /* LOCKCLOCK */
                break;
 
+       /*
+        * Initialize the frequency. If the frequency file is missing or
+        * broken, set the initial frequency to zero. The state remains
+        * S_NSET. Otherwise, set the initial frequency to the given
+        * value and the state to S_FSET.
+        */
        case LOOP_DRIFTCOMP:
-
 #ifndef LOCKCLOCK
-               /*
-                * If the frequency value is reasonable, set the initial
-                * frequency to the given value and the state to S_FSET.
-                * Otherwise, the drift file may be missing or broken,
-                * so set the frequency to zero. This erases past
-                * history should somebody break something.
-                */
-               if (freq <= NTP_MAXFREQ && freq >= -NTP_MAXFREQ) {
-                       drift_comp = freq;
-                       rstclock(S_FSET, 0);
-               } else {
+               if (freq > NTP_MAXFREQ || freq < -NTP_MAXFREQ) {
                        drift_comp = 0;
+                       break;
                }
+               drift_comp = freq;
+               rstclock(S_FSET, 0);
 
 #ifdef KERNEL_PLL
                /*
-                * Sanity check. If the kernel is available, load the
-                * frequency and light up the loop. Make sure the offset
-                * is zero to cancel any previous nonsense. If you don't
-                * want this initialization, remove the ntp.drift file.
+                * If the kernel is enabled, load the frequency.
                 */
                if (pll_control && kern_enable) {
                        memset((char *)&ntv, 0, sizeof(ntv));
-                       ntv.modes = MOD_OFFSET | MOD_FREQUENCY;
-                       ntv.freq = (int32)(drift_comp * 65536e6);
+                       ntv.freq = DTOFREQ(drift_comp);
+                       ntv.modes = MOD_FREQUENCY;
                        ntp_adjtime(&ntv);
                }
 #endif /* KERNEL_PLL */
 #endif /* LOCKCLOCK */
                break;
 
+       /*
+        * Disable the kernel at shutdown. The microkernel just abandons
+        * ship. The nanokernel carefully cleans up so applications can
+        * see this. Note the last programmed offset and frequency are
+        * left in place.
+        */
        case LOOP_KERN_CLEAR:
 #ifndef LOCKCLOCK
 #ifdef KERNEL_PLL
-               /* Completely turn off the kernel time adjustments. */
-               if (pll_control) {
+               if (pll_control && kern_enable) {
                        memset((char *)&ntv, 0, sizeof(ntv));
-                       ntv.modes = MOD_BITS | MOD_OFFSET | MOD_FREQUENCY;
-                       ntv.status = STA_UNSYNC;
+                       ntv.modes = MOD_STATUS;
+                       ntv.status = 0;
                        ntp_adjtime(&ntv);
-                       NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
-                           msyslog(LOG_INFO,
+                       msyslog(LOG_NOTICE,
                            "kernel time sync disabled %04x",
                            ntv.status);
                   }
@@ -961,18 +983,8 @@ loop_config(
 #endif /* LOCKCLOCK */
                break;
 
-       case LOOP_LEAP:         /* set kernel TAI offset */
-#if defined(STA_NANO) && NTP_API == 4
-               if (pll_control && kern_enable) {
-                       ntv.modes = MOD_TAI;
-                       ntv.constant = sys_tai;
-                       ntp_adjtime(&ntv);
-               }
-#endif /* STA_NANO */
-               break;
-
        /*
-        * tinker command variables for Ulrich Windl. Very dangerous.
+        * Tinker command variables for Ulrich Windl. Very dangerous.
         */
        case LOOP_ALLAN:        /* Allan intercept (log2) (allan) */
                allan_xpt = (u_char)freq;
@@ -1016,8 +1028,9 @@ loop_config(
                clock_minstep = freq; 
                break;
 
+       case LOOP_LEAP:         /* not used */
        default:
-               msyslog(LOG_INFO,
+               msyslog(LOG_NOTICE,
                    "loop_config: unsupported option %d", item);
        }
 }
index 617b830e289491a09214323586438720a3654419..eca60304d1947ab0388e0e765ccc8a4e57524457 100644 (file)
@@ -84,7 +84,7 @@ static        int mon_mem_increments;         /* times called malloc() */
  * packet will be discarded if the interval betweem packets is less than
  * 1 s, as well as when the average interval is less than 16 s. 
  */
-int    res_avg_interval = 1 << NTP_MINPOLL; /* avg interpkt interval */
+int    ntp_minpoll = NTP_MINPOLL;      /* avg interpkt interval */
 int    res_min_interval = 1 << NTP_MINPKT; /* min interpkt interval */
 
 /*
@@ -268,14 +268,14 @@ ntp_monitor(
                        md->leak -= interval;
                        if (md->leak < 0)
                                md->leak = 0;
-                       leak = md->leak + res_avg_interval;
+                       leak = md->leak + (1 << ntp_minpoll);
 #ifdef DEBUG
                        if (debug > 1)
-                               printf("restrict: min %d average %d\n",
+                               printf("restrict: interval %d headway %d\n",
                                    interval, leak);
 #endif
                        if (interval >= res_min_interval - 1 && leak <
-                           NTP_SHIFT * res_avg_interval + 2) {
+                           NTP_SHIFT * (1 << ntp_minpoll) + 2) {
                                md->leak = leak;
                                md->flags &= ~RES_LIMITED;
                        }
index aedf4f1f3d93dba3351798de16db579f40a40603..900f3350d4d24c2a45aeda752c53aae2843ba46c 100644 (file)
@@ -921,14 +921,13 @@ expire_all(void)
        /*
         * This routine is called about once per day from the timer
         * routine and when the client is first synchronized. Search the
-        * peer list for all associations and flush the key list. Also,          * fetch the leap second values.
+        * peer list for all associations.
         */
        if (!crypto_flags)
                return;
 
        for (n = 0; n < NTP_HASH_SIZE; n++) {
                for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
-                       peer->crypto &= ~CRYPTO_FLAG_LEAP;
                        next_peer = peer->next;
                        if (!(peer->flags & FLAG_SKEY)) {
                                continue;
index e9bdbc69e8ac36a64ea4e59fa313b20cf886ef62..53762e2b46683ab549c2318e9791938c04a5d660 100644 (file)
@@ -92,9 +92,10 @@ u_long       sys_epoch;              /* last clock update time */
 static int sys_hopper;         /* anticlockhop counter */
 static int sys_maxhop = MAXHOP; /* anticlockhop counter threshold */
 int    leap_tai;               /* TAI at next next leap */
-u_long leap_sec;               /* next leap */
-u_long leap_expire;            /* leapfile expiration */
-static int leap_next;          /* leap consensus */
+u_long leap_sec;               /* next scheduled leap from file */
+u_long leap_peers;             /* next scheduled leap from peers */
+u_long leap_expire;            /* leap information expiration */
+static int leap_vote;          /* leap consensus */
 keyid_t        sys_private;            /* private value for session seed */
 int    sys_manycastserver;     /* respond to manycast client pkts */
 int    peer_ntpdate;           /* active peers in ntpdate mode */
@@ -124,7 +125,7 @@ u_long      sys_newversion;         /* current version */
 u_long sys_oldversion;         /* old version */
 
 u_long sys_restricted;         /* access denied */
-u_long sys_badlength;          /* bad length or format */
+u_long sys_badlength;          /* bad version, length or format */
 u_long sys_badauth;            /* bad authentication */
 u_long sys_declined;           /* packets declined */
 u_long sys_limitrejected;      /* rate exceeded */
@@ -249,7 +250,8 @@ transmit(
                 */ 
                if (peer->unreach >= NTP_UNREACH) {
                        if (peer->flags & FLAG_PREEMPT &&
-                           sys_survivors >= sys_maxclock) {
+                           (sys_survivors > sys_maxclock ||
+                           peer->pmode == MODE_BROADCAST)) {
                                peer_clear(peer, "TIME");
                                unpeer(peer);
                                return;
@@ -260,7 +262,8 @@ transmit(
                                 * If timeout in Autokey dance, restart
                                 * the protocol.
                                 */
-                               if (peer->crypto) {
+                               if (peer->crypto || (peer->flash &
+                                   TEST9)) {
                                        peer_clear(peer, "TIME");
                                        peer->unreach = 0;
                                }
@@ -397,14 +400,6 @@ receive(
                process_control(rbufp, restrict_mask);
                return;
        }
-       if (restrict_mask & RES_DONTSERVE) {
-               sys_restricted++;
-               return;                         /* no time */
-       }
-       if (rbufp->recv_length < LEN_PKT_NOMAC) {
-               sys_badlength++;
-               return;                         /* runt packet */
-       }
        
        /*
         * Version check must be after the query packets, since they
@@ -435,6 +430,18 @@ receive(
                }
        }
 
+       /*
+        * If access denied or rate exceeded and no KoD, don't waste
+        * further cycles.
+        */
+       if (restrict_mask & RES_DONTSERVE)
+               sys_restricted++;
+       if (restrict_mask & RES_LIMITED)
+               sys_limitrejected++;
+       if (restrict_mask & (RES_DONTSERVE | RES_LIMITED) &&
+           !(restrict_mask & RES_DEMOBILIZE))
+               return;
+
        /*
         * Parse the extension field if present. We figure out whether
         * an extension field is present by measuring the MAC size. If
@@ -448,12 +455,12 @@ receive(
         */
        authlen = LEN_PKT_NOMAC;
        has_mac = rbufp->recv_length - authlen;
-       while (has_mac > 0) {
+       while (has_mac != 0) {
                int temp;
 
                if (has_mac % 4 != 0 || has_mac < 0) {
                        sys_badlength++;
-                       return;                 /* bad MAC length */
+                       return;                 /* bad length */
                }
                if (has_mac == 1 * 4 || has_mac == 3 * 4 || has_mac ==
                    MAX_MAC_LEN) {
@@ -463,16 +470,28 @@ receive(
                } else if (has_mac > MAX_MAC_LEN) {
                        temp = ntohl(((u_int32 *)pkt)[authlen / 4]) &
                            0xffff;
-                       if (temp < 4 || temp > NTP_MAXEXTEN || temp % 4
-                           != 0) {
+                       if (temp < 4 || temp % 4 != 0 || temp +
+                           authlen + MAX_MAC_LEN >
+                           rbufp->recv_length) {
                                sys_badlength++;
-                               return;         /* bad MAC length */
+                               return;         /* bad length */
                        }
+
+                       /*
+                        * Extension fields are illegal if Autokey is
+                        * not configured.
+                        */
+#ifdef OPENSSL
+                       if (!crypto_flags)
+                               restrict_mask |= RES_DONTSERVE;
+#elif /* OPENSSL */
+                       restrict_mask |= RES_DONTSERVE;
+#endif /* OPENSSL */
                        authlen += temp;
                        has_mac -= temp;
                } else {
                        sys_badlength++;
-                       return;                 /* bad MAC length */
+                       return;                 /* bad length */
                }
        }
 #ifdef OPENSSL
@@ -481,7 +500,7 @@ receive(
 
        /*
         * We have tossed out as many buggy packets as possible early in
-        * the game to reduce the exposure to a clogging attack. Now we
+        * the game to reduce the exposure to a clogging attack. now we
         * have to burn some cycles to find the association and
         * authenticate the packet if required. Note that we burn only
         * MD5 cycles, again to reduce exposure. There may be no
@@ -681,17 +700,22 @@ receive(
 
                /*
                 * The vanilla case is when this is not a multicast
-                * interface. If authentication succeeds, return a
-                * server mode packet; if not and the key ID is nonzero,
-                * return a crypto-NAK.
+                * interface. If a restrict bit is lit, drop the packet.
+                * If directed, send a KoD.
                 */
-               if (restrict_mask & RES_LIMITED) {
-                       sys_limitrejected++;
-                       if (restrict_mask & RES_DEMOBILIZE)
-                               fast_xmit(rbufp, hismode, skeyid,
-                                   "RATE");
-                       return;
+               if (restrict_mask & RES_DONTSERVE) {
+                       fast_xmit(rbufp, hismode, skeyid, "DENY");
+                       return;                 /* access denied */
+
+               } else if (restrict_mask & RES_LIMITED) {
+                       fast_xmit(rbufp, hismode, skeyid, "RATE");
+                       return;                 /* rate exceeded */
                }
+
+               /*
+                * If authentication OK, send a server reply; otherwise,
+                * send a crypto-NAK.
+                */
                if (!(rbufp->dstadr->flags & INT_MCASTOPEN)) {
                        if (AUTH(restrict_mask & RES_DONTTRUST,
                           is_authentic))
@@ -728,7 +752,6 @@ receive(
                 */
                if (AUTH(restrict_mask & RES_DONTTRUST, is_authentic))
                        fast_xmit(rbufp, hismode, skeyid, NULL);
-
                return;                         /* hooray */
 
        /*
@@ -834,7 +857,7 @@ receive(
                         * neither is Autokey.
                         */
                        if (skeyid > NTP_MAXKEY) {
-                               msyslog(LOG_INFO,
+                               msyslog(LOG_NOTICE,
                                    "receive: autokey requires two-way communication");
                                sys_restricted++;
                                return;         /* no autokey */
@@ -1028,17 +1051,24 @@ receive(
 
        /*
         * Test for kiss-o'death packet. We carefully avoid a hazard
-        * when a terrorist broadcaster kisses the frog.
+        * when the client has restarted the association after a kiss by
+        * upping the throttle to the max.
         */
        if (hismode == MODE_SERVER && hisleap == LEAP_NOTINSYNC &&
            hisstratum == STRATUM_UNSPEC) {
-               if (memcmp(&pkt->refid, "RATE", 4) == 0) {
-                       peer_clear(peer, "RATE");
-                       peer->flash |= TEST4;   /* rate quench */
-                       msyslog(LOG_INFO,
+               if (memcmp(&pkt->refid, "DENY", 4) == 0) {
+                       peer_clear(peer, "DENY");
+                       peer->flash |= TEST4;
+                       msyslog(LOG_NOTICE,
+                           "receive: server %s access denied",
+                           stoa(&rbufp->recv_srcadr));
+               } else if (memcmp(&pkt->refid, "RATE", 4) == 0) {
+                       peer->throttle += NTP_SHIFT * (1 <<
+                           ntp_minpoll);
+                       poll_update(peer, peer->hpoll);
+                       msyslog(LOG_NOTICE,
                            "receive: server %s maximum rate exceeded",
                            stoa(&rbufp->recv_srcadr));
-                       return;
                }
        }
 
@@ -1113,12 +1143,13 @@ receive(
                        peer->flash |= TEST8;   /* not proventic */
 
                /*
-                * If the transmit queue is nonempty, clamp the host
-                * poll interval to the packet poll interval.
+                * About once a week restart the Autokey protocol to
+                * slurp up and refreshed certificates or leapsecond
+                * values.
                 */
-               if (peer->cmmd != 0) {
-                       peer->ppoll = pkt->ppoll;
-                       poll_update(peer, peer->hpoll);
+               if (current_time > peer->refresh) {
+                       peer_clear(peer, "CRYP");
+                       return;
                }
        }
 #endif /* OPENSSL */
@@ -1169,7 +1200,7 @@ process_packet(
        pstratum = PKT_TO_STRATUM(pkt->stratum);
 
        /*
-        * Capture the header values.
+        * Capture the header values in the client/peer association..
         */
        record_raw_stats(&peer->srcadr, peer->dstadr ?
            &peer->dstadr->sin : NULL, &p_org, &p_rec, &p_xmt,
@@ -1184,6 +1215,22 @@ process_packet(
        peer->refid = pkt->refid;               /* network byte order */
        peer->reftime = p_reftime;
 
+       /*
+        * First, if either burst mode is armed, enable the burst.
+        * Compute the headway for the next packet and delay if
+        * necessary to avoid exceeding the threshold.
+        */
+       if (peer->retry > 0) {
+               peer->retry = 0;
+               if (peer->reach)
+                       peer->burst = min(1 << (peer->hpoll -
+                           ntp_minpoll), NTP_SHIFT) - 1;
+               else
+                       peer->burst = NTP_IBURST - 1;
+               peer->nextdate = current_time;
+       }
+       poll_update(peer, peer->hpoll);
+
        /*
         * Verify the server is synchronized; that is, the leap bits and
         * stratum are valid, the root delay and root dispersion are
@@ -1212,33 +1259,14 @@ process_packet(
        }
 
        /*
-        * If the peer was previously unreachable, raise a trap. If a
-        * burst mode is active, initialize the burst. The unreachable
-        * burst is always NTP_IBURST (6) packets; the reachable burst
-        * is tailored not to exceed the minimum average headway of 16
-        * s.
+        * If the peer was previously unreachable, raise a trap. In any
+        * case, mark it reachable.
         */ 
        if (!peer->reach) {
                report_event(EVNT_REACH, peer);
                peer->timereachable = current_time;
-               if (peer->retry > 0) {
-                       peer->retry = 0;
-                       peer->burst = NTP_IBURST - 1;
-                       peer->nextdate = peer->outdate +
-                           res_min_interval;
-               }
-       } else {
-               if (peer->retry > 0) {
-                       peer->retry = 0;
-                       peer->burst = min(1 << (peer->hpoll -
-                           NTP_MINPOLL), NTP_SHIFT) - 1;
-                       if (peer->burst > 0)
-                               peer->nextdate = peer->outdate +
-                                   res_min_interval;
-               }
        }
        peer->reach |= 1;
-       poll_update(peer, peer->hpoll);
 
        /*
         * For a client/server association, calculate the clock offset,
@@ -1261,8 +1289,8 @@ process_packet(
         * only half that span. Since the typical first-order
         * differences are usually very small, they are converted to 64-
         * bit doubles and all remaining calculations done in floating-
-        * point arithmetic. This preserves the accuracy while retaining
-        * the 68-year span.
+        * double arithmetic. This preserves the accuracy while
+        * retaining the 68-year span.
         *
         * Let t1 = p_org, t2 = p_rec, t3 = p_xmt, t4 = peer->rec:
         */
@@ -1326,6 +1354,14 @@ process_packet(
                            .5) * p_del;
                else
                        td = 0;
+
+               /*
+                * Unfortunately, in many cases the errors are
+                * unacceptable, so for the present the rates are not
+                * used. In future, we might find conditions where the
+                * calculations are useful, so this should be considered
+                * a work in progress.
+                */
 #if 0 /* temporarily disabled */
                t21 -= td;
                t34 -= td;
@@ -1377,8 +1413,8 @@ clock_update(
 {
        u_char  ostratum;
        double  dtemp;
-       l_fp    now;
        u_long  epoch;
+       l_fp    now;
 #ifdef HAVE_LIBSCF_H
        char    *fmri;
 #endif /* HAVE_LIBSCF_H */
@@ -1477,26 +1513,39 @@ clock_update(
                sys_reftime = peer->rec;
 
                /*
-                * If a leapseconds file is not present and the number
-                * of survivor leap bits is greater than half the number
-                * of survivors, schedule a leap for the end of the
-                * current month.
+                * If the leapseconds values are from file or network
+                * and the leap is in the future, schedule a leap at the
+                * given epoch. Otherwise, if the number of survivor
+                * leap bits is greater than half the number of
+                * survivors, schedule a leap for the end of the current
+                * month.
                 */
                get_systime(&now);
-               if (leap_expire == 0) {
-                       u_long leapsec;
-
-                       leapsec = leap_month(now.l_ui);
-                       if (leapsec < 28 * 86400) {
-                               leapsec += now.l_ui;
-                               if (leapsec != leap_sec) {
-                                       leap_sec = leapsec;
+               if (leap_sec > 0) {
+                       if (leap_sec > now.l_ui) {
+                               sys_tai = leap_tai - 1;
+                               if (leapsec == 0)
+                                       leapsec = leap_sec - now.l_ui;
                                        msyslog(LOG_NOTICE,
-                                           "proto: leap epoch %lu",                                                leap_sec);
+                                           "crypto: leap epoch %.1f days",
+                                           leapsec / 86400.);
                                }
                        } else {
-                               leap_sec = 0;
+                               sys_tai = leap_tai;
                        }
+                       break;
+
+               if (leap_vote > sys_survivors / 2) {
+                       leap_peers = now.l_ui + leap_month(now.l_ui);
+                       if (leap_peers > now.l_ui) {
+                               if (leapsec == 0)
+                                       leapsec = leap_peers - now.l_ui;
+                                       msyslog(LOG_NOTICE,
+                                           "proto: leap epoch %.1f days",
+                                           leapsec / 86400.);
+                       }
+               } else {
+                       leapsec = 0;
                }
                break;
        /*
@@ -1521,6 +1570,7 @@ poll_update(
        )
 {
        int     hpoll;
+       u_long  next, utemp;
 
        /*
         * This routine figures out when the next poll should be sent.
@@ -1552,59 +1602,81 @@ poll_update(
        peer->hpoll = hpoll;
 
        /*
-        * Now we figure out if there is an override. If during the
-        * crypto protocol and a responce message is pending, delay one
-        * second.
-        */
-#ifdef OPENSSL
-       if (peer->cmmd != NULL && (sys_leap != LEAP_NOTINSYNC ||
-           peer->crypto)) {
-               peer->nextdate = current_time + RESP_DELAY;
-
-       /*
-        * If we get called from the receive routine while a burst is
-        * pending, just slink away. If a reference clock, delay one
-        * second; otherwise, delay two seconds.
+        * There are three variables important for poll scheduling, the
+        * current time (current_time), next scheduled time (nextdate)
+        * and the earliest time (utemp). The earliest time is 2 s
+        * seconds, but could be more due to rate management. When
+        * sending in a burst, use the earliest time. When not in a
+        * burst but with a reply pending, send at the earliest time
+        * unless the next scheduled time has not advanced. This can
+        * only happen if multiple replies are peinding in the same
+        * response interval. Otherwise, send at the later of the next
+        * scheduled time and the earliest time.
+        *
+        * Now we figure out if there is an override. If a burst is in
+        * progress and we get called from the receive process, just
+        * slink away. If called from the poll process, delay 1 s for a
+        * reference clock, otherwise 2 s.
         */
-       } else if (peer->burst > 0) {
-#else /* OPENSSL */
+       utemp = current_time + max(peer->throttle - (NTP_SHIFT - 1) *
+           (1 << ntp_minpoll), res_min_interval);
        if (peer->burst > 0) {
-#endif /* OPENSSL */
-               if (peer->nextdate != current_time)
+               if (peer->nextdate > current_time)
                        return;
 #ifdef REFCLOCK
                else if (peer->flags & FLAG_REFCLOCK)
-                       peer->nextdate += RESP_DELAY;
+                       peer->nextdate = current_time + RESP_DELAY;
 #endif /* REFCLOCK */
                else
-                       peer->nextdate += res_min_interval;
+                       peer->nextdate = utemp;
+
+       /*
+        * If a burst is not in progress and a crypto response message
+        * is pending, delay 2 s, but only if this is a new interval..
+        */
+       } else if (peer->cmmd != NULL) {
+               if (peer->nextdate > current_time) {
+                       if (peer->nextdate + res_min_interval != utemp)
+                               peer->nextdate = utemp;
+               } else {
+                       peer->nextdate = utemp;
+               }
 
        /*
-        * The ordinary case. If a retry, use minpoll; otherwise use the
-        * minimum of the host and peer intervals. In other words,
-        * oversampling is okay but understampling is evil.
+        * The ordinary case. If a retry, start wotj minpoll; otherwise
+        * wtart with the minimum of the host and peer intervals. In
+        * other words, oversampling is okay but understampling is evil.
+        * Use the maximum of this value and the headway, then increase
+        * by the minimum interval if the average headway is greater
+        * than 16 s. This is to reduce the average headway at the
+        * minimum poll interval of 16 s.
         */
        } else {
                if (peer->retry > 0)
                        hpoll = peer->minpoll;
                else
                        hpoll = min(peer->ppoll, peer->hpoll);
-               peer->nextdate = peer->outdate + RANDPOLL(hpoll);
-       }
 
-       /*
-        * If the time for the next poll has already happened, bring it
-        * up to the next second after this one. This way the only way
-        * to get nexdate == current time is from the poll routine.
-        */
-       if (peer->nextdate <= current_time)
-               peer->nextdate = current_time + 1;
+               next = (u_long)(0x10000 | (ntp_random() & 0x0fff)) << hpoll;
+
+printf("xxx %d, %d %d %lx\n", peer->ppoll, peer->hpoll, hpoll, next);\v
+               next = (u_long)((0x10000 | (ntp_random() & 0x0fff)) <<
+                   hpoll) >> 16;
+               next += peer->outdate;
+               if (next > utemp)
+                       peer->nextdate = next;
+               else
+                       peer->nextdate = utemp;
+               if (peer->throttle > (1 << ntp_minpoll))
+                       peer->nextdate += res_min_interval;
+       }
 #ifdef DEBUG
        if (debug > 1)
-               printf("poll_update: at %lu %s flags %04x poll %d burst %d retry %d next %lu\n",
-                   current_time, ntoa(&peer->srcadr), peer->flags,
-                   peer->hpoll, peer->burst, peer->retry,
-                   peer->nextdate);
+               printf("poll_update: at %lu %s poll %d burst %d retry %d head %d early %lu next %lu\n",
+                   current_time, ntoa(&peer->srcadr), peer->hpoll,
+                   peer->burst, peer->retry, peer->throttle,
+                   utemp - current_time, peer->nextdate -
+                   current_time);
 #endif
 }
 
@@ -1679,7 +1751,7 @@ peer_clear(
 
        /*
         * During initialization use the association count to spread out
-        * the polls at one-second intervals. Othersie, randomize over
+        * the polls at one-second intervals. Otherwise, randomize over
         * the minimum poll interval in order to avoid broadcast
         * implosion.
         */
@@ -1687,10 +1759,11 @@ peer_clear(
        if (initializing)
                peer->nextdate += peer_associations;
        else if (peer->hmode == MODE_PASSIVE)
-               peer->nextdate += RESP_DELAY;
+               peer->nextdate += res_min_interval;
        else
                peer->nextdate += ntp_random() % peer_associations;
 #ifdef OPENSSL
+       peer->refresh = current_time + NTP_REFRESH;
        sprintf(statstr, "clear %d ident %s", peer->associd,
            ident);
                record_crypto_stats(&peer->srcadr, statstr);
@@ -2199,8 +2272,7 @@ clock_select(void)
                        nlist = 1;
                } else {
                        if (osys_peer != NULL) {
-                               NLOG(NLOG_SYNCSTATUS)
-                                   msyslog(LOG_INFO,
+                               msyslog(LOG_NOTICE,
                                    "no servers reachable");
                                report_event(EVNT_PEERSTCHG, NULL);
                        }
@@ -2276,24 +2348,29 @@ clock_select(void)
         * the system peer, although all survivors are eligible for the
         * combining algorithm. Check for prefer and pps peers at any
         * stratum. Note that the head of the list is at the lowest
-        * stratum and that unsynchronized peers cannot survivethis far.
+        * stratum and that unsynchronized peers cannot survive this
+        * far.
+        *
+        * Also, reset the association unreach timer for the first
+        * sys_maxclock survivors. The rest, if preemptable, will be
+        * kicked off the bus after timeout.
         *
         * While at it, count the number of leap warning bits found.
         * This will be used later to vote the system leap warning bit.
         * If a leap warning bit is found on a reference clock, the vote
         * is always won.
         */
-       leap_next = 0;
+       leap_vote = 0;
        for (i = 0; i < nlist; i++) {
                sys_survivors++;
                peer = peer_list[i];
-               if (i < sys_maxclock)
+               if (sys_survivors <= sys_maxclock)
                        peer->unreach = 0;
                if (peer->leap == LEAP_ADDSECOND) {
                        if (peer->flags & FLAG_REFCLOCK)
-                               leap_next = nlist;
+                               leap_vote = nlist;
                        else 
-                               leap_next++;
+                               leap_vote++;
                }
                peer->status = CTL_PST_SEL_SYNCCAND;
                if (peer->flags & FLAG_PREFER)
@@ -2353,8 +2430,8 @@ clock_select(void)
                        sys_peer->status = CTL_PST_SEL_PPS;
                        sys_offset = sys_peer->offset;
                        if (!pps_control)
-                               NLOG(NLOG_SYSEVENT)
-                                   msyslog(LOG_INFO,
+                               NLOG(NLOG_SYNCSTATUS)
+                               msyslog(LOG_INFO,
                                    "pps sync enabled");
                        pps_control = current_time;
 #ifdef DEBUG
@@ -2416,8 +2493,8 @@ clock_select(void)
 #endif /* REFCLOCK */
                         src = ntoa(&sys_peer->srcadr);
                NLOG(NLOG_SYNCSTATUS)
-                   msyslog(LOG_INFO, "synchronized to %s, stratum %d",
-                       src, sys_peer->stratum);
+               msyslog(LOG_INFO, "synchronized to %s, stratum %d",
+                   src, sys_peer->stratum);
        }
        clock_update(sys_peer);
 }
@@ -2526,7 +2603,7 @@ peer_xmit(
                sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl],
                    &xpkt, sendlen);
                peer->sent++;
-               peer->throttle += res_avg_interval;
+               peer->throttle += 1 << ntp_minpoll;
 #ifdef DEBUG
                if (debug)
                        printf("transmit: at %ld %s->%s mode %d len %d\n",
@@ -2623,7 +2700,7 @@ peer_xmit(
                /*
                 * In symmetric modes the digest, certificate, agreement
                 * parameters, cookie and autokey values are required.
-                * The leapsecond table is optional. But, a passive peer
+                * The leapsecond field is optional. But, a passive peer
                 * will not believe the active peer until the latter has
                 * synchronized, so the agreement must be postponed
                 * until then. In any case, if a new keylist is
@@ -2682,8 +2759,8 @@ peer_xmit(
                                    peer->associd, NULL);
 
                        /*
-                        * Postamble. We trade leapseconds only when the
-                        * server and client are synchronized.
+                        * Postamble. We trade leapsecond fields only
+                        * when the server and client are synchronized.
                         */
                        else if (sys_leap != LEAP_NOTINSYNC &&
                            peer->leap != LEAP_NOTINSYNC &&
@@ -2695,7 +2772,7 @@ peer_xmit(
                /*
                 * In client mode the digest, certificate, agreement
                 * parameters and cookie are required. The leapsecond
-                * table is optional. If broadcast client mode, the
+                * field is optional. If broadcast client mode, the
                 * autokey values are required as well. In broadcast
                 * client mode, these values must be acquired during the
                 * client/server exchange to avoid having to wait until
@@ -2805,7 +2882,7 @@ peer_xmit(
        HTONL_FP(&peer->xmt, &xpkt.xmt);
        authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen);
        if (authlen == 0) {
-               msyslog(LOG_INFO, "transmit: %s key %u not found",
+               msyslog(LOG_NOTICE, "transmit: %s key %u not found",
                    stoa(&peer->srcadr), xkeyid);
                peer->flash |= TEST9;           /* no key found */
                return;
@@ -2824,7 +2901,7 @@ peer_xmit(
        sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], &xpkt,
            sendlen);
        peer->sent++;
-       peer->throttle += res_avg_interval;
+       peer->throttle += 1 << ntp_minpoll;
 
        /*
         * Calculate the encryption delay. Keep the minimum over
@@ -2913,7 +2990,7 @@ fast_xmit(
                xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
                    PKT_VERSION(rpkt->li_vn_mode), xmode);
                xpkt.stratum = STRATUM_PKT_UNSPEC;
-               memcpy(&xpkt.refid, "RATE", 4);
+               memcpy(&xpkt.refid, mask, 4);
                xpkt.org = rpkt->xmt;
                xpkt.rec = rpkt->xmt;
                xpkt.xmt = rpkt->xmt;
@@ -3168,8 +3245,7 @@ default_get_precision(void)
        /*
         * Find the nearest power of two.
         */
-       NLOG(NLOG_SYSEVENT)
-           msyslog(LOG_INFO, "precision = %.3f usec", tick * 1e6);
+           msyslog(LOG_NOTICE, "precision = %.3f usec", tick * 1e6);
        for (i = 0; tick <= 1; i++)
                tick *= 2;
        if (tick - 1. > 1. - tick / 2)
@@ -3369,7 +3445,7 @@ proto_config(
                break;
 
        default:
-               msyslog(LOG_INFO,
+               msyslog(LOG_NOTICE,
                    "proto_config: unsupported option %d", item);
        }
 }
index 5cbeb3c945b3ac542e3daf11c6d3d2bdfeafff11..a30014a9a5ed92123863a542dc1c8fcd5a255acc 100644 (file)
@@ -47,10 +47,11 @@ volatile int alarm_flag;
 /*
  * The counters and timeouts
  */
+static  u_long interface_timer;        /* interface update timer */
 static u_long adjust_timer;    /* second timer */
 static u_long stats_timer;     /* stats timer */
 static u_long huffpuff_timer;  /* huff-n'-puff timer */
-static  u_long interface_timer;        /* interface update timer */
+u_long leapsec;                /* leapseconds countdown */
 #ifdef OPENSSL
 static u_long revoke_timer;    /* keys revoke timer */
 u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout */
@@ -265,7 +266,6 @@ timer(void)
 {
        register struct peer *peer, *next_peer;
        u_int   n;
-       l_fp    now;
 
        /*
         * The basic timerevent is one second. This is used to adjust
@@ -309,8 +309,7 @@ timer(void)
                         */
                        if (peer->throttle > 0)
                                peer->throttle--;
-                       if (peer->nextdate <= current_time &&
-                           (peer->throttle == 0 || peer->burst > 0)) {
+                       if (peer->nextdate <= current_time) {
 #ifdef REFCLOCK
                                if (peer->flags & FLAG_REFCLOCK)
                                        refclock_transmit(peer);
@@ -342,37 +341,32 @@ timer(void)
        }
 
        /*
-        * Leapseconds. When the time remaining decrements to zero,
-        * increment the TAI offset. If the kernel code is not available
-        * or disabled, Do the leap crudely. There are of course races
-        * here, cheerfully ignored.
+        * Leapseconds. If a leap is pending, decrement the time
+        * remaining. If less than one day remains, set the leap bits.
+        * When no time remains, clear the leap bits and increment the
+        * TAI. If kernel suppport is not available, do the leap
+        * crudely. Note a leap cannot be pending unless the clock is
+        * set.
         */
-       if (leap_sec > 0) {
-               get_systime(&now);
-               if (now.l_ui > leap_sec) {
+       if (leapsec > 0) {
+               leapsec--;
+               if (leap_sec == 0) {
                        sys_leap = LEAP_NOWARNING;
                        sys_tai = leap_tai;
-               } else if (now.l_ui - leap_sec < 28 * 86400) {
-                       sys_leap = LEAP_ADDSECOND;
-                       if (leap_tai > 0)
-                               sys_tai = leap_tai - 1;
-               }
-#ifdef KERNEL_PLL
-               if (now.l_ui - leap_sec == 600) {
-                       if (pll_control && kern_enable)
-                               loop_config(LOOP_LEAP, 0);
-               }
-#endif /* KERNEL_PLL */
-               if (leap_sec == 0) {
 #ifdef KERNEL_PLL
                        if (!(pll_control && kern_enable))
                                step_systime(-1.0);
 #else /* KERNEL_PLL */
-                               step_systime(-1.0);
+                       step_systime(-1.0);
 #endif /* KERNEL_PLL */
                        msyslog(LOG_NOTICE,
-                           "timer: leap second %lu TAI %d",
-                               leap_sec, sys_tai);
+                           "leapsecond event %lu TAI %d",
+                           current_time, sys_tai);
+               } else {
+                       if (leapsec < DAY)
+                               sys_leap = LEAP_ADDSECOND;
+                       if (leap_tai > 0)
+                               sys_tai = leap_tai - 1;
                }
        }
 
@@ -420,7 +414,7 @@ timer(void)
        }
        
        /*
-        * Finally, write stats once per hour.
+        * Finally, write hourly stats.
         */
        if (stats_timer <= current_time) {
                stats_timer += HOUR;
index f01ee68a13e7144a65e91dfd9b2b5d3048c5ba2d..55874281fb8e7897a3a3910398bf936441b42c45 100644 (file)
@@ -106,7 +106,7 @@ static double prev_drift_comp;              /* last frequency update */
 /*
  * Static prototypes
  */
-static void leap_file(char *);
+static int leap_file(FILE *);
 
 /*
  * init_util - initialize the utilities
@@ -114,9 +114,9 @@ static void leap_file(char *);
 void
 init_util(void)
 {
-       stats_drift_file = 0;
-       stats_temp_file = 0;
-       key_file_name = 0;
+       stats_drift_file = NULL;
+       stats_temp_file = NULL;
+       key_file_name = NULL;
        filegen_register(&statsdir[0], "peerstats", &peerstats);
        filegen_register(&statsdir[0], "loopstats", &loopstats);
        filegen_register(&statsdir[0], "clockstats", &clockstats);
@@ -128,9 +128,6 @@ init_util(void)
 #ifdef DEBUG_TIMING
        filegen_register(&statsdir[0], "timingstats", &timingstats);
 #endif /* DEBUG_TIMING */
-
-leap_file("/etc/ntp.leap");    /***** temp for debug *****/
-
 }
 
 
@@ -213,13 +210,6 @@ write_stats(void)
                setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
 #endif /* VMS */
 #endif /* DOSYNCTODR */
-
-       NLOG(NLOG_SYSSTATIST)
-               msyslog(LOG_INFO,
-                   "offset %.6f sec freq %.3f ppm error %.6f poll %d",
-                   last_offset, drift_comp * 1e6, sys_jitter,
-                   sys_poll);
-
        record_sys_stats();
        clock_stepcnt = 0;
        ftemp = fabs(prev_drift_comp - drift_comp); 
@@ -249,7 +239,8 @@ write_stats(void)
                        wander_resid = wander_threshold;
                        if ((fp = fopen(stats_temp_file, "w")) == NULL)
                            {
-                               msyslog(LOG_ERR, "can't open %s: %m",
+                               msyslog(LOG_ERR,
+                                   "frequency file %s: %m",
                                    stats_temp_file);
                                return;
                        }
@@ -265,9 +256,10 @@ write_stats(void)
                            stats_drift_file);
 #else
                        /* we have no rename NFS of ftp in use */
-                       if ((fp = fopen(stats_drift_file, "w")) == NULL)
-                           {
-                               msyslog(LOG_ERR, "can't open %s: %m",
+                       if ((fp = fopen(stats_drift_file, "w")) ==
+                           NULL) {
+                               msyslog(LOG_ERR,
+                                   "frequency file %s: %m",
                                    stats_drift_file);
                                return;
                        }
@@ -345,10 +337,14 @@ stats_config(
 #endif /* SYS_WINNT */
 
        switch(item) {
-           case STATS_FREQ_FILE:
+
+       /*
+        * Open and read frequency file.
+        */
+       case STATS_FREQ_FILE:
                if (stats_drift_file != 0) {
-                       (void) free(stats_drift_file);
-                       (void) free(stats_temp_file);
+                       free(stats_drift_file);
+                       free(stats_temp_file);
                        stats_drift_file = 0;
                        stats_temp_file = 0;
                }
@@ -383,7 +379,8 @@ stats_config(
                        break;
                }
                if (fscanf(fp, "%lf", &old_drift) != 1) {
-                       msyslog(LOG_ERR, "frequency format error in %s", 
+                       msyslog(LOG_ERR,
+                           "format error frequency file %s", 
                            stats_drift_file);
                        old_drift = 1e9;
                        fclose(fp);
@@ -393,15 +390,15 @@ stats_config(
                fclose(fp);
                old_drift /= 1e6;
                prev_drift_comp = old_drift;
-               msyslog(LOG_INFO,
+               msyslog(LOG_NOTICE,
                    "frequency initialized %.3f PPM from %s",
                        old_drift * 1e6, stats_drift_file);
-
-               leap_file("/etc/ntp.leap");
-
                break;
-       
-           case STATS_STATSDIR:
+
+       /*
+        * Specify statistics directory.
+        */
+       case STATS_STATSDIR:
 
                /*
                 * HMS: the following test is insufficient:
@@ -410,7 +407,7 @@ stats_config(
                 */
                if (strlen(value) >= sizeof(statsdir)) {
                        msyslog(LOG_ERR,
-                           "value for statsdir too long (>%d, sigh)",
+                           "statsdir too long (>%d, sigh)",
                            (int)sizeof(statsdir) - 1);
                } else {
                        l_fp now;
@@ -473,20 +470,41 @@ stats_config(
                }
                break;
 
-           case STATS_PID_FILE:
+       /*
+        * Open pid file.
+        */
+       case STATS_PID_FILE:
                if ((fp = fopen(value, "w")) == NULL) {
-                       msyslog(LOG_ERR, "Can't open %s: %m", value);
+                       msyslog(LOG_ERR, "pid file %s: %m",
+                           value);
                        break;
                }
-               fprintf(fp, "%d", (int) getpid());
+               fprintf(fp, "%d", (int)getpid());
                fclose(fp);;
                break;
 
-           case STATS_LEAP_FILE:
-               leapseconds_file_name = invalue;
+       /*
+        * Read leapseconds file.
+        */
+       case STATS_LEAP_FILE:
+               if ((fp = fopen(value, "r")) == NULL) {
+                       msyslog(LOG_ERR, "leapseconds file %s: %m",
+                           value);
+                       break;
+               }
+
+               if (leap_file(fp) < 0)
+                       msyslog(LOG_ERR,
+                           "format error leapseconds file %s",
+                           value);
+               else
+                       msyslog(LOG_NOTICE,
+                           "leap epoch %lu expire %lu TAI offset %d from %s",
+                           leap_sec, leap_expire, leap_tai, value);
+               fclose(fp);
                break;
 
-           default:
+       default:
                /* oh well */
                break;
        }
@@ -586,7 +604,7 @@ record_loop_stats(
 void
 record_clock_stats(
        struct sockaddr_storage *addr,
-       const char *text
+       const char *text        /* timecode string */
        )
 {
        l_fp    now;
@@ -620,10 +638,10 @@ void
 record_raw_stats(
         struct sockaddr_storage *srcadr,
         struct sockaddr_storage *dstadr,
-       l_fp    *t1,
-       l_fp    *t2,
-       l_fp    *t3,
-       l_fp    *t4
+       l_fp    *t1,            /* originate timestamp */
+       l_fp    *t2,            /* receiver timestamp */
+       l_fp    *t3,            /* transmit timestamp */
+       l_fp    *t4             /* destination timestamp */
        )
 {
        l_fp    now;
@@ -655,11 +673,11 @@ record_raw_stats(
  * packets recieved
  * packets processed
  * current version
- * previous versions
- * declined
+ * previous version
  * access denied
  * bad length or format
  * bad authentication
+ * declined
  * rate exceeded
  */
 void
@@ -680,9 +698,8 @@ record_sys_stats(void)
                    "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
                    day, ulfptoa(&now, 3), sys_stattime / 3600,
                    sys_received, sys_processed, sys_newversion,
-                   sys_oldversion, sys_declined,
-                   sys_restricted, sys_badlength, sys_badauth,
-                   sys_limitrejected);
+                   sys_oldversion, sys_restricted, sys_badlength,
+                   sys_badauth, sys_declined, sys_limitrejected);
                fflush(sysstats.fp);
                proto_clr_stats();
        }
@@ -702,7 +719,7 @@ record_sys_stats(void)
 void
 record_crypto_stats(
        struct sockaddr_storage *addr,
-       const char *text
+       const char *text        /* text message */
        )
 {
        l_fp    now;
@@ -739,7 +756,7 @@ record_crypto_stats(
  */
 void
 record_timing_stats(
-       const char *text
+       const char *text        /* text message */
        )
 {
        static unsigned int flshcnt;
@@ -769,32 +786,16 @@ record_timing_stats(
  * Read the ERTS leapsecond file in NIST text format and extract the
  * NTP seconds of the latest leap and TAI offset after the leap.
  */
-static void
+static int
 leap_file(
-       char    *cp             /* file name */
+       FILE    *fp             /* file handle */
        )
 {
-       FILE    *str;           /* file handle */
        char    buf[NTP_MAXSTRLEN]; /* file line buffer */
-       u_long  leapsec;        /* NTP time at leap */
+       u_long  leap;           /* NTP time at leap */
        u_long  expire;         /* NTP time when file expires */
        int     offset;         /* TAI offset at leap (s) */
-       char    filename[MAXFILENAME]; /* name of leapseconds file */
-
-       NTP_REQUIRE(cp != NULL);
-
-       /*
-        * Open the leapseconds file. If the first character of the
-        * file name is not '/', prepend the keys directory string. If
-        * the file is not found, ignore; if found with errors, report
-        * to the log and ignore.
-        */
-       if (*cp == '/')
-               strcpy(filename, cp);
-       else
-               snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp);
-       if ((str = fopen(filename, "r")) == NULL)
-               return;
+       int     i;
 
        /*
         * Read and parse the leapseconds file. Empty lines and comments
@@ -802,13 +803,13 @@ leap_file(
         * expiration time in NTP seconds. Other lines begin with two
         * integers followed by junk or comments. The first integer is
         * the NTP seconds at the leap, the second is the TAI offset
-        * after the leap. Only the last correctly parsed line is
-        * significant. Parsing errors are cheerfully ignored.
+        * after the leap.
         */
        offset = 0;
-       leapsec = 0;
+       leap = 0;
        expire = 0;
-       while (fgets(buf, NTP_MAXSTRLEN - 1, str) != NULL) {
+       i = 10;
+       while (fgets(buf, NTP_MAXSTRLEN - 1, fp) != NULL) {
                if (strlen(buf) < 1)
                        continue;
 
@@ -816,20 +817,39 @@ leap_file(
                        if (strlen(buf) < 3)
                                continue;
 
-                       if (buf[1] == '@') {
-                               sscanf(&buf[2], "%lu", &expire);
+                       /*
+                        * Note the '@' flag was used only in the 2006
+                        * table; previious to that the flag was '$'.
+                        */
+                       if (buf[1] == '@' || buf[1] == '$') {
+                               if (sscanf(&buf[2], "%lu", &expire) !=
+                                   1)
+                                       return (-1);
+
                                continue;
                        }
                }
-               sscanf(buf, "%lu %d", &leapsec, &offset);
+               if (sscanf(buf, "%lu %d", &leap, &offset) == 2) {
+
+                       /*
+                        * Valid offsets must increase by one for each
+                        * leap.
+                        */
+                       if (i++ != offset)
+                               return (-1);
+               }
        }
-       fclose(str);
+
+       /*
+        * There must be at least one leap.
+        */
+       if (i == 10)
+               return (-1);
+
        leap_tai = offset;
-       leap_sec = leapsec;
+       leap_sec = leap;
        leap_expire = expire;
-       msyslog(LOG_INFO,
-           "leap_file: %s leap epoch %lu TAI offset %d expire %lu",
-           cp, leap_sec, leap_tai, leap_expire);
+       return (0);
 }
 
 
@@ -899,22 +919,19 @@ getauthkeys(
        if (len == 0)
                return;
        
-       if (key_file_name != 0) {
-               if (len > (int)strlen(key_file_name)) {
-                       (void) free(key_file_name);
-                       key_file_name = 0;
-               }
+       if (key_file_name != NULL) {
+               free(key_file_name);
+               key_file_name = NULL;
        }
-
-       if (key_file_name == 0) {
+       if (key_file_name == NULL) {
 #ifndef SYS_WINNT
-               key_file_name = (char*)emalloc((u_int) (len + 1));
+               key_file_name = emalloc(len + 1);
 #else
-               key_file_name = (char*)emalloc((u_int)  (MAXPATHLEN));
+               key_file_name = emalloc(MAXPATHLEN);
 #endif
        }
 #ifndef SYS_WINNT
-       memmove(key_file_name, keyfile, (unsigned)(len+1));
+       memmove(key_file_name, keyfile, len + 1);
 #else
        if (!ExpandEnvironmentStrings(keyfile, key_file_name,
            MAXPATHLEN)) {
@@ -932,8 +949,8 @@ getauthkeys(
 void
 rereadkeys(void)
 {
-       if (key_file_name != 0)
-           authreadkeys(key_file_name);
+       if (key_file_name != NULL)
+               authreadkeys(key_file_name);
 }