]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
NEWS update; orphan/revoke/expire stuff from Dave Mills
authorHarlan Stenn <stenn@ntp.org>
Sun, 2 Oct 2005 08:12:05 +0000 (04:12 -0400)
committerHarlan Stenn <stenn@ntp.org>
Sun, 2 Oct 2005 08:12:05 +0000 (04:12 -0400)
bk: 433f96551oxzlJlSq_1jZwOwLXFqjw

NEWS
include/ntp.h
include/ntp_config.h
include/ntp_control.h
ntpd/ntp_config.c
ntpd/ntp_control.c
ntpd/ntp_crypto.c
ntpd/ntp_loopfilter.c
ntpd/ntp_peer.c
ntpd/ntp_proto.c

diff --git a/NEWS b/NEWS
index ef93fca0f8cc923e6e2040c5791c894b49e61e35..02bfe5aa6e73fae09a67ab7949fb069f8d51a1ac 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,5 @@
+* SNTP
+* Bugfixes
 ---
 (4.2.0)
 * More stuff than I have time to document
index ea1414a9f79f42b9c163867c80d5bf2047ccc0f6..ed9dcb62b56d8c08678ec2162ffaf5511363ba89 100644 (file)
@@ -114,7 +114,6 @@ typedef char s_char;
 /*
  * Clock filter algorithm tuning parameters
  */
-#define MINDISPERSE    .01     /* min dispersion */
 #define MAXDISPERSE    16.     /* max dispersion */
 #define        NTP_SHIFT       8       /* clock filter stages */
 #define NTP_FWEIGHT    .5      /* clock filter weight */
@@ -125,7 +124,7 @@ typedef char s_char;
 #define        NTP_MINCLOCK    3       /* min survivors */
 #define        NTP_MAXCLOCK    10      /* max candidates */
 #define        NTP_MAXASSOC    50      /* max associations */
-#define MINDISPERSE    .0    /* min dispersion increment */
+#define MINDISPERSE    .005    /* min dispersion increment */
 #define MAXDISTANCE    1.      /* max root distance (select threshold) */
 #define CLOCK_SGATE    3.      /* popcorn spike gate */
 #define HUFFPUFF       900     /* huff-n'-puff sample interval (s) */
@@ -740,6 +739,8 @@ struct pkt {
 #define PROTO_ADJ              23
 #define        PROTO_MAXHOP            24
 #define        PROTO_BEACON            25
+#define        PROTO_ORPHAN            26
+
 /*
  * Configuration items for the loop filter
  */
index 2d771093292391171399ae22fd06330b6a672ff7..c840502a7e221b022f8aa617262c6abfaa0f17ae 100644 (file)
 #define CONF_TOS_MAXDIST       8
 #define        CONF_TOS_MAXHOP         9
 #define        CONF_TOS_BEACON         10
+#define        CONF_TOS_ORPHAN         11
 
 #ifdef OPENSSL
 /*
index 8877dc061c026b4c7014c47c44f8bb8cbbbb5819..c299794534b3b8c33dbdda93929c21f26a33c418 100644 (file)
@@ -175,7 +175,8 @@ struct ntp_control {
 #define CS_TAI         27
 #define        CS_DIGEST       28
 #define CS_IDENT       29
-#define        CS_MAXCODE      CS_DIGEST
+#define        CS_REVOKE       30
+#define        CS_MAXCODE      CS_REVOKE
 #else
 #define        CS_MAXCODE      CS_VARLIST
 #endif /* OPENSSL */
index d72a600448543eb68059d354b646ed06e446d62d..eee45d70fe0ef4fa3f4974493ce531eaa360028f 100644 (file)
@@ -248,6 +248,7 @@ static struct keyword tos_keywords[] = {
        { "maxdist",            CONF_TOS_MAXDIST },
        { "maxhop",             CONF_TOS_MAXHOP },
        { "beacon",             CONF_TOS_BEACON },
+       { "orphan",             CONF_TOS_ORPHAN },
        { "",                   CONFIG_UNKNOWN }
 };
 
@@ -1121,6 +1122,10 @@ getconfig(
                                proto_config(PROTO_MAXHOP, 0, ftemp, NULL);
                                break;
 
+                           case CONF_TOS_ORPHAN:
+                               proto_config(PROTO_ORPHAN, 0, ftemp, NULL);
+                               break;
+
                            case CONF_TOS_BEACON:
                                proto_config(PROTO_BEACON, 0, ftemp, NULL);
                                break;
index e3d62093ffbbe3c55565ff0e5ff2d4897f16a690..0e6fb706b52effcbd3f75e70e46508a1a3735b95 100644 (file)
@@ -9,6 +9,7 @@
 #include "ntp_io.h"
 #include "ntp_refclock.h"
 #include "ntp_control.h"
+#include "ntp_unixtime.h"
 #include "ntp_stdlib.h"
 
 #include <stdio.h>
@@ -59,6 +60,7 @@ static        void    ctl_putid       P((const char *, char *));
 static void    ctl_putarray    P((const char *, double *, int));
 static void    ctl_putsys      P((int));
 static void    ctl_putpeer     P((int, struct peer *));
+static void    ctl_putfs       P((const char *, tstamp_t));
 #ifdef REFCLOCK
 static void    ctl_putclock    P((int, struct refclockstat *, int));
 #endif /* REFCLOCK */
@@ -118,13 +120,14 @@ static struct ctl_var sys_var[] = {
        { CS_HOST,      RO, "hostname" },       /* 22 */
        { CS_PUBLIC,    RO, "hostkey" },        /* 23 */
        { CS_CERTIF,    RO, "cert" },           /* 24 */
-       { CS_REVTIME,   RO, "refresh" },        /* 25 */
+       { CS_REVTIME,   RO, "expire" },         /* 25 */
        { CS_LEAPTAB,   RO, "leapsec" },        /* 26 */
        { CS_TAI,       RO, "tai" },            /* 27 */
        { CS_DIGEST,    RO, "signature" },      /* 28 */
        { CS_IDENT,     RO, "ident" },          /* 29 */
+       { CS_REVOKE,    RO, "expire" },         /* 30 */
 #endif /* OPENSSL */
-       { 0,            EOV, "" }               /* 21/30 */
+       { 0,            EOV, "" }               /* 21/31 */
 };
 
 static struct ctl_var *ext_sys_var = (struct ctl_var *)0;
@@ -158,7 +161,6 @@ static      u_char def_sys_var[] = {
        CS_DIGEST,
        CS_FLAGS,
        CS_PUBLIC,
-       CS_REVTIME,
        CS_IDENT,
        CS_LEAPTAB,
        CS_TAI,
@@ -999,6 +1001,39 @@ ctl_putuint(
        ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
 }
 
+/*
+ * ctl_putfs - write a decoded filestamp into the response
+ */
+static void
+ctl_putfs(
+       const char *tag,
+       tstamp_t uval
+       )
+{
+       register char *cp;
+       register const char *cq;
+       char buffer[200];
+       struct tm *tm = NULL;
+       time_t fstamp;
+
+       cp = buffer;
+       cq = tag;
+       while (*cq != '\0')
+               *cp++ = *cq++;
+
+       *cp++ = '=';
+       fstamp = uval - JAN_1970;
+       tm = gmtime(&fstamp);
+       if (tm == NULL)
+               return;
+
+       sprintf(cp, "%04d%02d%02d%04d", tm->tm_year + 1900, tm->tm_mon,
+           tm->tm_mday + 1, tm->tm_hour * 60 + tm->tm_min);
+       while (*cp != '\0')
+               cp++;
+       ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
+}
+
 
 /*
  * ctl_puthex - write a tagged unsigned integer, in hex, into the response
@@ -1373,23 +1408,23 @@ ctl_putsys(
 
        case CS_CERTIF:
                for (cp = cinfo; cp != NULL; cp = cp->link) {
-                       sprintf(cbuf, "%s %s 0x%x %u", cp->subject,
-                           cp->issuer, cp->flags,
-                           ntohl(cp->cert.fstamp));
+                       sprintf(cbuf, "%s %s 0x%x", cp->subject,
+                           cp->issuer, cp->flags);
                        ctl_putstr(sys_var[CS_CERTIF].text, cbuf,
                            strlen(cbuf));
+                       ctl_putfs(sys_var[CS_REVOKE].text, cp->last);
                }
                break;
 
        case CS_PUBLIC:
                if (hostval.fstamp != 0)
-                       ctl_putuint(sys_var[CS_PUBLIC].text,
+                       ctl_putfs(sys_var[CS_PUBLIC].text,
                            ntohl(hostval.fstamp));
                break;
 
        case CS_REVTIME:
                if (hostval.tstamp != 0)
-                       ctl_putuint(sys_var[CS_REVTIME].text,
+                       ctl_putfs(sys_var[CS_REVTIME].text,
                            ntohl(hostval.tstamp));
                break;
 
@@ -1407,7 +1442,7 @@ ctl_putsys(
 
        case CS_LEAPTAB:
                if (tai_leap.fstamp != 0)
-                       ctl_putuint(sys_var[CS_LEAPTAB].text,
+                       ctl_putfs(sys_var[CS_LEAPTAB].text,
                            ntohl(tai_leap.fstamp));
                break;
 
@@ -1671,22 +1706,17 @@ ctl_putpeer(
 
        case CP_HOST:
                if (peer->subject != NULL)
-                       ctl_putstr(peer_var[CP_HOST].text, peer->subject,
-                           strlen(peer->subject));
+                       ctl_putstr(peer_var[CP_HOST].text,
+                           peer->subject, strlen(peer->subject));
                break;
 
-       case CP_VALID:
-               if (peer->pkey == NULL)
-                       break;
-
-               sprintf(str, "%u:%u", peer->first, peer->last);
-               ctl_putstr(peer_var[CP_VALID].text, str, strlen(str));
+       case CP_VALID:          /* not used */
                break;
 
        case CP_IDENT:
                if (peer->issuer != NULL)
-                       ctl_putstr(peer_var[CP_IDENT].text, peer->issuer,
-                           strlen(peer->issuer));
+                       ctl_putstr(peer_var[CP_IDENT].text,
+                           peer->issuer, strlen(peer->issuer));
                break;
 
        case CP_INITSEQ:
@@ -1694,7 +1724,7 @@ ctl_putpeer(
                        break;
                ctl_putint(peer_var[CP_INITSEQ].text, ap->seq);
                ctl_puthex(peer_var[CP_INITKEY].text, ap->key);
-               ctl_putuint(peer_var[CP_INITTSP].text,
+               ctl_putfs(peer_var[CP_INITTSP].text,
                    ntohl(peer->recval.tstamp));
                break;
 #endif /* OPENSSL */
index 1fc957368127a35f87aed31adadaa3c75aaf6d77..211e3201dbba85b6a54d17ee7c1b6de8dd3eae47 100644 (file)
@@ -258,7 +258,7 @@ make_keylist(
        keyid_t keyid = 0;      /* next key ID */
        keyid_t cookie;         /* private value */
        u_long  lifetime;
-       u_int   len;
+       u_int   len, mpoll;
        int     i;
 
        /*
@@ -290,8 +290,8 @@ make_keylist(
         * included in the hash is zero if broadcast mode, the peer
         * cookie if client mode or the host cookie if symmetric modes.
         */
-       lifetime = min(sys_automax, NTP_MAXSESSION * (1 <<
-           peer->hpoll));
+       mpoll = 1 << min(peer->ppoll, peer->hpoll);
+       lifetime = min(sys_automax, NTP_MAXSESSION * mpoll);
        if (peer->hmode == MODE_BROADCAST)
                cookie = 0;
        else
@@ -301,9 +301,9 @@ make_keylist(
                peer->keynumber = i;
                keyid = session_key(&dstadr->sin, &peer->srcadr, keyid,
                    cookie, lifetime);
-               lifetime -= 1 << peer->hpoll;
+               lifetime -= mpoll;
                if (auth_havekey(keyid) || keyid <= NTP_MAXKEY ||
-                   lifetime <= (1 << peer->hpoll))
+                   lifetime <= mpoll)
                        break;
        }
 
@@ -377,6 +377,7 @@ crypto_recv(
        X509    *cert;          /* X509 certificate */
        char    statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
        keyid_t cookie;         /* crumbles */
+       int     hismode;        /* packet mode */
        int     rval = XEVNT_OK;
        u_char  *ptr;
        u_int32 temp32;
@@ -392,6 +393,7 @@ crypto_recv(
         * association ID is saved only if nonzero.
         */
        authlen = LEN_PKT_NOMAC;
+       hismode = (int)PKT_MODE((&rbufp->recv_pkt)->li_vn_mode);
        while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) {
                pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4;
                ep = (struct exten *)pkt;
@@ -442,15 +444,19 @@ crypto_recv(
                 * defines the signature scheme. Note the request and
                 * response are identical, but neither is validated by
                 * signature. The request is processed here only in
-                * symmetric modes. The server name field would be
+                * symmetric modes. The server name field might be
                 * useful to implement access controls in future.
                 */
                case CRYPTO_ASSOC:
 
                        /*
-                        * Pass the extension field to the transmit
-                        * side.
+                        * Discard the message if it has already been
+                        * stored. Otherwise, pass the extension field
+                        * to the transmit side.
                         */
+                       if (peer->crypto)
+                               break;
+
                        fp = emalloc(len);
                        memcpy(fp, ep, len);
                        temp32 = CRYPTO_RESP;
@@ -462,12 +468,13 @@ crypto_recv(
 
                        /*
                         * Discard the message if it has already been
-                        * stored or the server is not synchronized.
+                        * stored or the message has been amputated.
                         */
-                       if (peer->crypto || !fstamp)
+                       if (peer->crypto)
                                break;
 
-                       if (len < VALUE_LEN + vallen) {
+                       if (vallen == 0 || vallen > MAXHOSTNAME ||
+                           len < VALUE_LEN + vallen) {
                                rval = XEVNT_LEN;
                                break;
                        }
@@ -479,53 +486,62 @@ crypto_recv(
                         * identity are presumed valid, so we skip the
                         * certificate and identity exchanges and move
                         * immediately to the cookie exchange which
-                        * confirms the server signature. If the client
-                        * has IFF or GC or both, the server must have
-                        * the same one or both. Otherwise, the default
-                        * TC scheme is used.
+                        * confirms the server signature.
                         */
+                       temp32 = crypto_flags & fstamp &
+                           CRYPTO_FLAG_MASK;
                        if (crypto_flags & CRYPTO_FLAG_PRIV) {
-                               if (!(fstamp & CRYPTO_FLAG_PRIV))
+                               if (!(fstamp & CRYPTO_FLAG_PRIV)) {
                                        rval = XEVNT_KEY;
-                               else
+                                       break;
+
+                               } else {
                                        fstamp |= CRYPTO_FLAG_VALID |
-                                           CRYPTO_FLAG_VRFY;
-                       } else if (crypto_flags & CRYPTO_FLAG_MASK &&
-                           !(crypto_flags & fstamp & CRYPTO_FLAG_MASK))
-                           {
+                                           CRYPTO_FLAG_VRFY |
+                                           CRYPTO_FLAG_SIGN;
+                               }
+                       /*
+                        * In symmetric modes it is an error if either
+                        * peer requests identity and the other peer
+                        * does not support it.
+                        */
+                       } else if ((hismode == MODE_ACTIVE || hismode ==
+                           MODE_PASSIVE) && ((crypto_flags | fstamp) &
+                           CRYPTO_FLAG_MASK) && !temp32) {
                                rval = XEVNT_KEY;
-                       } else {
-                               fstamp &= ~CRYPTO_FLAG_MASK;
+                               break;
+                       /*
+                        * It is an error if the client requests
+                        * identity and the server does not support it.
+                        */
+                       } else if (hismode == MODE_CLIENT && (fstamp &
+                           CRYPTO_FLAG_MASK) && !temp32) {
+                               rval = XEVNT_KEY;
+                               break;
                        }
 
                        /*
-                        * Discard the message if identity error.
+                        * Otherwise, the identity scheme(s) are those
+                        * that both client and server support.
                         */
-                       if (rval != XEVNT_OK)
-                               break;
+                       fstamp = temp32 | (fstamp & ~CRYPTO_FLAG_MASK);
 
                        /*
-                        * Discard the message if the host name length
-                        * is unreasonable or the signature digest NID
-                        * is not supported.
+                        * Discard the message if the signature digest
+                        * NID is not supported.
                         */
                        temp32 = (fstamp >> 16) & 0xffff;
                        dp =
                            (const EVP_MD *)EVP_get_digestbynid(temp32);
-                       if (vallen == 0 || vallen > MAXHOSTNAME)
-                               rval = XEVNT_LEN;
-                       else if (dp == NULL)
+                       if (dp == NULL) {
                                rval = XEVNT_MD;
-                       if (rval != XEVNT_OK)
                                break;
+                       }
 
                        /*
                         * Save status word, host name and message
-                        * digest/signature type. If PC identity, be
-                        * sure not to sign the certificate.
+                        * digest/signature type.
                         */
-                       if (crypto_flags & CRYPTO_FLAG_PRIV)
-                               fstamp |= CRYPTO_FLAG_SIGN;
                        peer->crypto = fstamp;
                        peer->digest = dp;
                        peer->subject = emalloc(vallen + 1);
@@ -554,12 +570,8 @@ crypto_recv(
                case CRYPTO_CERT | CRYPTO_RESP:
 
                        /*
-                        * Discard the message if invalid or identity
-                        * already confirmed.
+                        * Discard the message if invalid.
                         */
-                       if (peer->crypto & CRYPTO_FLAG_VRFY)
-                               break;
-
                        if ((rval = crypto_verify(ep, NULL, peer)) !=
                            XEVNT_OK)
                                break;
@@ -629,12 +641,13 @@ crypto_recv(
                case CRYPTO_IFF | CRYPTO_RESP:
 
                        /*
-                        * Discard the message if invalid or identity
-                        * already confirmed.
+                        * Discard the message if invalid or certificate
+                        * trail not trusted.
                         */
-                       if (peer->crypto & CRYPTO_FLAG_VRFY)
+                       if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+                               rval = XEVNT_ERR;
                                break;
-
+                       }
                        if ((rval = crypto_verify(ep, NULL, peer)) !=
                            XEVNT_OK)
                                break;
@@ -676,12 +689,13 @@ crypto_recv(
                case CRYPTO_GQ | CRYPTO_RESP:
 
                        /*
-                        * Discard the message if invalid or identity
-                        * already confirmed.
+                        * Discard the message if invalid or certificate
+                        * trail not trusted.
                         */
-                       if (peer->crypto & CRYPTO_FLAG_VRFY)
+                       if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+                               rval = XEVNT_ERR;
                                break;
-
+                       }
                        if ((rval = crypto_verify(ep, NULL, peer)) !=
                            XEVNT_OK)
                                break;
@@ -716,12 +730,13 @@ crypto_recv(
                case CRYPTO_MV | CRYPTO_RESP:
 
                        /*
-                        * Discard the message if invalid or identity
-                        * already confirmed.
+                        * Discard the message if invalid or certificate
+                        * trail not trusted.
                         */
-                       if (peer->crypto & CRYPTO_FLAG_VRFY)
+                       if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+                               rval = XEVNT_ERR;
                                break;
-
+                       }
                        if ((rval = crypto_verify(ep, NULL, peer)) !=
                            XEVNT_OK)
                                break;
@@ -760,12 +775,13 @@ crypto_recv(
                case CRYPTO_SIGN | CRYPTO_RESP:
 
                        /*
-                        * Discard the message if invalid or identity
-                        * not confirmed.
+                        * Discard the message if invalid or not
+                        * proventic.
                         */
-                       if (!(peer->crypto & CRYPTO_FLAG_VRFY))
+                       if (!(peer->crypto & CRYPTO_FLAG_PROV)) {
+                               rval = XEVNT_ERR;
                                break;
-
+                       }
                        if ((rval = crypto_verify(ep, NULL, peer)) !=
                            XEVNT_OK)
                                break;
@@ -800,12 +816,8 @@ crypto_recv(
                case CRYPTO_COOK:
 
                        /*
-                        * Discard the message if invalid or identity
-                        * not confirmed.
+                        * Discard the message if invalid.
                         */
-                       if (!(peer->crypto & CRYPTO_FLAG_VRFY))
-                               break;
-
                        if ((rval = crypto_verify(ep, NULL, peer)) !=
                            XEVNT_OK)
                                break;
@@ -858,9 +870,10 @@ crypto_recv(
                         * not confirmed or signature not verified with
                         * respect to the cookie values.
                         */
-                       if (!(peer->crypto & CRYPTO_FLAG_VRFY))
+                       if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
+                               rval = XEVNT_ERR;
                                break;
-
+                       }
                        if ((rval = crypto_verify(ep, &peer->cookval,
                            peer)) != XEVNT_OK)
                                break;
@@ -927,9 +940,10 @@ crypto_recv(
                         * not confirmed or signature not verified with
                         * respect to the receive autokey values.
                         */
-                       if (!(peer->crypto & CRYPTO_FLAG_VRFY))
+                       if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
+                               rval = XEVNT_ERR;
                                break;
-
+                       }
                        if ((rval = crypto_verify(ep, &peer->recval,
                            peer)) != XEVNT_OK)
                                break;
@@ -973,12 +987,8 @@ crypto_recv(
                case CRYPTO_TAI:
 
                        /*
-                        * Discard the message if invalid or identity
-                        * not confirmed.
+                        * Discard the message if invalid.
                         */
-                       if (!(peer->crypto & CRYPTO_FLAG_VRFY))
-                               break;
-
                        if ((rval = crypto_verify(ep, NULL, peer)) !=
                            XEVNT_OK)
                                break;
@@ -1002,16 +1012,19 @@ crypto_recv(
                case CRYPTO_TAI | CRYPTO_RESP:
 
                        /*
-                        * Discard the message if invalid or identity
-                        * not confirmed or signature not verified with
+                        * Discard the message if invalid or not
+                        * proventic or signature not verified with
                         * respect to the leapsecond table values.
                         */
-                       if (!(peer->crypto & CRYPTO_FLAG_VRFY))
-                               break;
-
-                       if ((rval = crypto_verify(ep, &peer->tai_leap,
-                           peer)) != XEVNT_OK)
+                       if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
+                               rval = XEVNT_ERR;
                                break;
+                       }
+                       if (peer->cmmd == NULL) {
+                               if ((rval = crypto_verify(ep,
+                                   &peer->tai_leap, peer)) != XEVNT_OK)
+                                       break;
+                       }
 
                        /*
                         * Initialize peer variables, leapseconds
@@ -1244,18 +1257,20 @@ crypto_xmit(
                        opcode |= CRYPTO_ERROR;
                        break;
                }
-               if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK)
+               if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK) {
                        len += crypto_send(fp, &vtemp);
-               value_free(&vtemp);
+                       value_free(&vtemp);
+               }
                break;
 
        /*
         * Send response in Schnorr (IFF) identity scheme.
         */
        case CRYPTO_IFF | CRYPTO_RESP:
-               if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK)
+               if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK) {
                        len += crypto_send(fp, &vtemp);
-               value_free(&vtemp);
+                       value_free(&vtemp);
+               }
                break;
 
        /*
@@ -1266,18 +1281,20 @@ crypto_xmit(
                        opcode |= CRYPTO_ERROR;
                        break;
                }
-               if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK)
+               if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK) {
                        len += crypto_send(fp, &vtemp);
-               value_free(&vtemp);
+                       value_free(&vtemp);
+               }
                break;
 
        /*
         * Send response in Guillou-Quisquater (GQ) identity scheme.
         */
        case CRYPTO_GQ | CRYPTO_RESP:
-               if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK)
+               if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK) {
                        len += crypto_send(fp, &vtemp);
-               value_free(&vtemp);
+                       value_free(&vtemp);
+               }
                break;
 
        /*
@@ -1288,18 +1305,20 @@ crypto_xmit(
                        opcode |= CRYPTO_ERROR;
                        break;
                }
-               if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK)
+               if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK) {
                        len += crypto_send(fp, &vtemp);
-               value_free(&vtemp);
+                       value_free(&vtemp);
+               }
                break;
 
        /*
         * Send response in MV identity scheme.
         */
        case CRYPTO_MV | CRYPTO_RESP:
-               if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK)
+               if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK) {
                        len += crypto_send(fp, &vtemp);
-               value_free(&vtemp);
+                       value_free(&vtemp);
+               }
                break;
 
        /*
@@ -1393,6 +1412,7 @@ crypto_xmit(
                opcode |= CRYPTO_ERROR;
                sprintf(statstr, "error %x opcode %x", rval, opcode);
                record_crypto_stats(srcadr_sin, statstr);
+               report_event(rval, NULL);
 #ifdef DEBUG
                if (debug)
                        printf("crypto_xmit: %s\n", statstr);
@@ -2137,7 +2157,7 @@ crypto_bob(
         * If the IFF parameters are not valid, something awful
         * happened or we are being tormented.
         */
-       if (!(crypto_flags & CRYPTO_FLAG_IFF)) {
+       if (iffpar_pkey == NULL) {
                msyslog(LOG_INFO, "crypto_bob: scheme unavailable");
                return (XEVNT_ID);
        }
@@ -2431,7 +2451,7 @@ crypto_bob2(
         * If the GQ parameters are not valid, something awful
         * happened or we are being tormented.
         */
-       if (!(crypto_flags & CRYPTO_FLAG_GQ)) {
+       if (gqpar_pkey == NULL) {
                msyslog(LOG_INFO, "crypto_bob2: scheme unavailable");
                return (XEVNT_ID);
        }
@@ -2748,7 +2768,7 @@ crypto_bob3(
         * If the MV parameters are not valid, something awful
         * happened or we are being tormented.
         */
-       if (!(crypto_flags & CRYPTO_FLAG_MV)) {
+       if (mvpar_pkey == NULL) {
                msyslog(LOG_INFO, "crypto_bob3: scheme unavailable");
                return (XEVNT_ID);
        }
index 16cde320217032489d948a68002118403345e9b9..5dcbadccdb0d9e3fa394326d4c00292a04236792 100644 (file)
@@ -497,7 +497,7 @@ local_clock(
 #ifdef STA_NANO
                if (pll_control && kern_enable && sys_tai == 0) {
                        memset(&ntv, 0, sizeof(ntv));
-                       ntv.modes = MOD_BITS | MOD_TAI;
+                       ntv.modes = MOD_TAI;
                        ntv.constant = i + TAI_1972 - 1;
                        ntp_adjtime(&ntv);
                }
index fd0279615ffc34cd001108179593b779d9649c5e..e24a645e805e91fdafb682ad3d776f81e714fc45 100644 (file)
@@ -341,7 +341,6 @@ unpeer(
                printf("demobilize %u %d %d\n", peer_to_remove->associd,
                    peer_associations, peer_preempt);
 #endif
-       peer_clear(peer_to_remove, "KILL");
        hash = NTP_HASH_ADDR(&peer_to_remove->srcadr);
        peer_hash_count[hash]--;
        peer_demobilizations++;
index 2677237d6c417215af61c1f3cd82307d9281fa7a..4789021d1160bc9d2499f63aeaafd965e42e4654 100644 (file)
@@ -1,4 +1,4 @@
-/*
+y/*
  * ntp_proto.c - NTP version 4 protocol machinery
  *
  * ATTENTION: Get approval from Dave Mills on all changes to this file!
@@ -84,6 +84,8 @@ int   sys_minsane = 1;        /* minimum candidates */
 int    sys_minclock = NTP_MINCLOCK; /* minimum survivors */
 int    sys_maxclock = NTP_MAXCLOCK; /* maximum candidates */
 int    sys_cohort = 0;         /* cohort switch */
+int    sys_orphan = STRATUM_UNSPEC + 1; /* orphan stratum */
+double sys_orphandelay = 0;    /* orphan root delay */
 int    sys_beacon = BEACON;    /* manycast beacon interval */
 int    sys_ttlmax;             /* max ttl mapping vector index */
 u_char sys_ttl[MAX_TTL];       /* ttl mapping vector */
@@ -130,13 +132,22 @@ transmit(
         */
        /*
         * In broadcast mode the poll interval is never changed from
-        * minpoll.
+        * minpoll. Orphan mode is active when enabled and when no other
+        * source is available. In this mode broadcasts are made at the
+        * orphan stratum and with root delay randomized over a 1-s
+        * range. The root delay is used by the election algorithm to
+        * select a single source from among the orphan dwellers.
         */
        hpoll = peer->hpoll;
        if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) {
                peer->outdate = current_time;
-               if (sys_peer != NULL)
+               if (sys_peer != NULL) {
+                       peer_xmit(peer);
+               } else if (sys_orphan < STRATUM_UNSPEC) {
+                       sys_leap = LEAP_NOWARNING;
+                       sys_stratum = sys_orphan;
                        peer_xmit(peer);
+               }
                poll_update(peer, hpoll);
                return;
        }
@@ -176,13 +187,17 @@ transmit(
                u_char oreach;
 
                /*
-                * Update the reachability status.
+                * Update the reachability status. If not heard for
+                * three consecutive polls, stuff infinity in the clock
+                * filter. 
                 */
                oreach = peer->reach;
                peer->outdate = current_time;
                if (peer == sys_peer)
                        sys_hopper++;
                peer->reach <<= 1;
+               if (!(peer->reach & 0x07))
+                       clock_filter(peer, 0., 0., MAXDISPERSE);
                if (!peer->reach) {
 
                        /*
@@ -203,20 +218,35 @@ transmit(
                            peer->unreach == 0) {
                                peer->burst = NTP_BURST;
                        }
+                       if (!(peer->flags & FLAG_PREEMPT))      
+                               peer->unreach++;
+                       else
+                               peer->unreach += 3;
                } else {
 
                        /*
-                        * Here the peer is reachable. If it has not
-                        * been heard for three consecutive polls, stuff
-                        * infinity in the clock filter. Next, set the
-                        * poll interval to the system poll interval.
-                        * Send a burst only if enabled and the peer is
-                        * fit.
+                        * Here the peer is reachable. Set the poll
+                        * interval to the system poll interval. Send a
+                        * burst only if enabled and the peer is fit.
+                        *
+                        * Respond to the peer evaluation produced by
+                        * the selection algorithm. If less than the
+                        * outlyer level, up the unreach by three. If
+                        * there are excess associations, up the unreach
+                        * by two if not a candidate and by one if so.
                         */
-                       if (!(peer->reach & 0x07))
-                               clock_filter(peer, 0., 0., MAXDISPERSE);
-                       if (!(peer->flags & FLAG_PREEMPT))      
+                       if (!(peer->flags & FLAG_PREEMPT)) {
                                peer->unreach = 0;
+                       } else if (peer->status < CTL_PST_SEL_SELCAND) {
+                               peer->unreach += 3;
+                       } else if (peer_preempt > sys_maxclock) {
+                               if (peer->status < CTL_PST_SEL_SYNCCAND)
+                                       peer->unreach += 2;
+                               else
+                                       peer->unreach++;
+                       } else {
+                               peer->unreach = 0;
+                       }
                        hpoll = sys_poll;
                        if (peer->flags & FLAG_BURST &&
                            peer_unfit(peer))
@@ -224,29 +254,15 @@ transmit(
                }
 
                /*
-                * Respond to the peer evaluation produced by the
-                * selection algorithm. If less than the outlieer level,
-                * up the distance by three. If there are excess
-                * associations less than the candidate level, up the
-                * distance by two. If there are excess associations
-                * otherwise, up the distance. If the distance exceeds
-                * the threshold, off the rascal.
+                * Watch for timeout. If ephemeral or preemptable, toss
+                * the rascal; otherwise, bump the poll interval.
                 */ 
-               if (peer->status < CTL_PST_SEL_SELCAND)
-                       peer->unreach += 3;
-               else if (peer_preempt > sys_maxclock) {
-                       if (peer->status < CTL_PST_SEL_SYNCCAND)
-                               peer->unreach += 2;
-                       else
-                               peer->unreach += 1;
-               } else {
-                       peer->unreach = 0;
-               }
                if (peer->unreach >= NTP_UNREACH) {
-                       if (peer->flags & FLAG_PREEMPT) {
+                       if (peer->flags & FLAG_PREEMPT ||
+                           !(peer->flags & FLAG_CONFIG)) {
+                               peer_clear(peer, "TIME");
                                unpeer(peer);
                                return;
-
                        } else {
                                hpoll++;
                        }
@@ -698,7 +714,7 @@ receive(
                 * manycaster or it has already synchronized to us.
                 */
                if (sys_peer == NULL || hisstratum < sys_stratum ||
-                   (sys_cohort && hisstratum) == sys_stratum ||
+                   (sys_cohort && hisstratum == sys_stratum) ||
                    rbufp->dstadr->addr_refid == pkt->refid)
                        return;                 /* no help */
 
@@ -788,16 +804,9 @@ receive(
                        if ((peer = newpeer(&rbufp->recv_srcadr,
                            rbufp->dstadr, MODE_CLIENT, hisversion,
                            NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_MCAST |
-                           FLAG_IBURST | FLAG_PREEMPT, MDF_BCLNT, 0,
-                           skeyid)) == NULL)
+                           FLAG_IBURST, MDF_BCLNT, 0, skeyid)) ==
+                           NULL)
                                return;         /* system error */
-#ifdef OPENSSL
-                       if (skeyid <= NTP_MAXKEY)
-                               return;         /* symmetric keys */
-
-                       if (crypto_recv(peer, rbufp) != XEVNT_OK)
-                               unpeer(peer);   /* crypto failure */
-#endif /* OPENSSL */
                        return;                 /* hooray */
 
 
@@ -810,16 +819,16 @@ receive(
                         * If a two-way exchange is not possible,
                         * neither is Autokey.
                         */
-                       if (skeyid <= NTP_MAXKEY) {
+                       if (skeyid > NTP_MAXKEY) {
                                msyslog(LOG_INFO,
-                                   "receive: broadcast requires two-way communication");
+                                   "receive: autokey requires two-way communication");
                                return;         /* no autokey */
                        }
 #endif /* OPENSSL */
                        if ((peer = newpeer(&rbufp->recv_srcadr,
                            rbufp->dstadr, MODE_BCLIENT, hisversion,
-                           NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_PREEMPT,
-                           MDF_BCLNT, 0, skeyid)) == NULL)
+                           NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_BCLNT, 0,
+                           skeyid)) == NULL)
                                return;         /* system error */
                }
                break;
@@ -860,10 +869,9 @@ receive(
 
                if ((peer = newpeer(&rbufp->recv_srcadr,
                    rbufp->dstadr, MODE_PASSIVE, hisversion,
-                   NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_PREEMPT, MDF_UCAST,
-                   0, skeyid)) == NULL)
+                   NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_UCAST, 0,
+                   skeyid)) == NULL)
                        return;                 /* system error */
-
                break;
 
        /*
@@ -893,7 +901,7 @@ receive(
         * Next comes a rigorous schedule of timestamp checking. If the
         * transmit timestamp is zero, the server is horribly broken.
         */
-       if (L_ISZERO(&p_xmt))
+       if (L_ISZERO(&p_xmt)) {
                return;                         /* read rfc1305 */
 
        /*
@@ -901,16 +909,16 @@ receive(
         * packet is a replay. This prevents the bad guys from replaying
         * the most recent packet, authenticated or not.
         */
-       if (L_ISEQU(&peer->org, &p_xmt)) {
+       } else if (L_ISEQU(&peer->org, &p_xmt)) {
                peer->flash |= TEST1;
                peer->oldpkt++;
                return;                         /* duplicate packet */
-       }
+       
 
        /*
         * If this is a broadcast mode packet, skip further checking.
         */
-       if (hismode != MODE_BROADCAST) {
+       } else if (hismode != MODE_BROADCAST) {
                if (L_ISZERO(&p_org))
                        peer->flash |= TEST3;   /* protocol unsynch */
                else if (!L_ISEQU(&p_org, &peer->xmt))
@@ -919,18 +927,27 @@ receive(
 
        /*
         * Update the origin and destination timestamps. If
-        * unsynchronized or bogus abandon ship.
+        * unsynchronized or bogus abandon ship. If the crypto machine
+        * breaks, light the crypto bit and plaint the log.
         */
        peer->org = p_xmt;
        peer->rec = rbufp->recv_time;
-       if (peer->flash)
+       if (peer->flash) {
+#ifdef OPENSSL
+               if (crypto_flags && (peer->flags & FLAG_SKEY)) {
+                       rval = crypto_recv(peer, rbufp);
+                       if (rval != XEVNT_OK)
+                               peer->flash |= TEST9; /* crypto error */
+               }
+#endif /* OPENSSL */
                return;                         /* unsynch */
+       }
 
        /*
         * The timestamps are valid and the receive packet matches the
         * last one sent. If the packet is a crypto-NAK, the server
-        * might have just changed keys. We demobilize the association
-        * and wait for better times.
+        * might have just changed keys. We reset the association
+        * and restart the protocol.
         */
        if (is_authentic == AUTH_CRYPTO) {
                peer_clear(peer, "AUTH");
@@ -940,11 +957,14 @@ receive(
         * If the association is authenticated, the key ID is nonzero
         * and received packets must be authenticated. This is designed
         * to avoid a bait-and-switch attack, which was possible in past
-        * versions.
+        * versions. If symmetric modes, return a crypto-NAK. The peer
+        * should restart the protocol.
         */
        } else if (!AUTH(peer->keyid || (restrict_mask & RES_DONTTRUST),
            is_authentic)) {
                peer->flash |= TEST5;
+               if (hismode == MODE_ACTIVE || hismode == MODE_PASSIVE)
+                       fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask);
                return;                         /* bad auth */
        }
 
@@ -980,20 +1000,20 @@ receive(
         *    match, sit the dance and wait for timeout.
         *
         * In case of crypto error, fire the orchestra and stop dancing.
-        * This is considered a permanant error, so go directly to jail.
+        * This is considered a permanant error, so light the crypto bit
+        * to suppress further requests.
         */
        if (crypto_flags && (peer->flags & FLAG_SKEY)) {
                peer->flash |= TEST8;
                rval = crypto_recv(peer, rbufp);
                if (rval != XEVNT_OK) {
-                       peer_clear(peer, "CRYP");
                        peer->flash |= TEST9;   /* crypto error */
                        return;
 
                } else if (hismode == MODE_SERVER) {
                        if (skeyid == peer->keyid)
                                peer->flash &= ~TEST8;
-               } else if (!peer->flash & TEST8) {
+               } else if (!(peer->flash & TEST8)) {
                        peer->pkeyid = skeyid;
                } else if ((ap = (struct autokey *)peer->recval.ptr) !=
                    NULL) {
@@ -1044,22 +1064,6 @@ receive(
                    peer->flash, stoa(&peer->srcadr));
                return;
        }
-
-#ifdef OPENSSL
-       /*
-        * If TEST8 is lit, the autokey sequence has broken, which
-        * probably means the server has refreshed its private value.
-        * Not to worry, reset and wait for the next time.
-        */
-       if (peer->flash & TEST8 && peer->crypto & CRYPTO_FLAG_AUTO) {
-#ifdef DEBUG
-               if (debug)
-                       printf(
-                           "receive: flash auto %04x\n", peer->flash);
-#endif
-               peer_clear(peer, "AUTO");
-       }
-#endif /* OPENSSL */
 }
 
 
@@ -1112,7 +1116,7 @@ process_packet(
        record_raw_stats(&peer->srcadr, &peer->dstadr->sin, &p_org,
            &p_rec, &p_xmt, &peer->rec);
        peer->leap = pleap;
-       peer->stratum = pstratum;
+       peer->stratum = min(pstratum, STRATUM_UNSPEC);
        peer->pmode = pmode;
        peer->ppoll = pkt->ppoll;
        peer->precision = pkt->precision;
@@ -1130,10 +1134,8 @@ process_packet(
        if (pleap == LEAP_NOTINSYNC ||          /* test 6 */
            pstratum < sys_floor || pstratum >= sys_ceiling)
                peer->flash |= TEST6;           /* peer not synch */
-       ci = p_xmt;
-       L_SUB(&ci, &p_reftime);
        if (p_del < 0 || p_disp < 0 || p_del /  /* test 7 */
-           2 + p_disp >= MAXDISPERSE || L_ISNEG(&ci))
+           2 + p_disp >= MAXDISPERSE || !L_ISHIS(&p_xmt, &p_reftime))
                peer->flash |= TEST7;           /* bad header */
 
        /*
@@ -1284,19 +1286,28 @@ clock_update(void)
        /*
         * Clock was slewed. Update the system stratum, leap bits, root
         * delay, root dispersion, reference ID and reference time. If
-        * the leap changes, we gotta reroll the keys.
+        * the leap changes, we gotta reroll the keys. Except for
+        * reference clocks, the minimum dispersion increment is not
+        * less than sys_mindisp.
         */
        case 1:
                sys_leap = leap_next;
-               sys_stratum = (u_char)(sys_peer->stratum + 1);
+               sys_stratum = sys_peer->stratum + 1;
                if (sys_stratum == 1 || sys_stratum == STRATUM_UNSPEC)
                        sys_refid = sys_peer->refid;
                else
                        sys_refid = addr2refid(&sys_peer->srcadr);
                sys_reftime = sys_peer->rec;
-               sys_rootdelay = sys_peer->rootdelay + sys_peer->delay;
+
+               /*
+                * In orphan mode the stratum defaults to the orphan
+                * stratum. The root delay is set to a random value
+                * generated at startup. The root dispersion is set from
+                * the peer dispersion; the the peer root dispersion
+                * ignored.
+                */
                dtemp = sys_peer->disp + clock_phi * (current_time -
-                   sys_peer->epoch) + sys_jitter +
+                   sys_peer->update) + sys_jitter +
                    fabs(sys_peer->offset);
 #ifdef REFCLOCK
                if (!(sys_peer->flags & FLAG_REFCLOCK) && dtemp <
@@ -1306,7 +1317,16 @@ clock_update(void)
                if (dtemp < sys_mindisp)
                        dtemp = sys_mindisp;
 #endif /* REFCLOCK */
-               sys_rootdispersion = sys_peer->rootdispersion + dtemp;
+               if (sys_stratum >= sys_orphan) {
+                       sys_stratum = sys_orphan;
+                       sys_rootdelay = sys_peer->delay;
+                       sys_rootdispersion = dtemp;
+               } else {
+                       sys_rootdelay = sys_peer->delay +
+                           sys_peer->rootdelay;
+                       sys_rootdispersion = dtemp +
+                           sys_peer->rootdispersion;
+               }
                if (oleap == LEAP_NOTINSYNC) {
                        report_event(EVNT_SYNCCHG, NULL);
 #ifdef OPENSSL
@@ -1486,6 +1506,7 @@ peer_clear(
        memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO);
        peer->estbdelay = sys_bdelay;
        peer->ppoll = peer->maxpoll;
+       peer->hpoll = peer->minpoll;
        peer->disp = MAXDISPERSE;
        peer->jitter = LOGTOD(sys_precision);
        for (i = 0; i < NTP_SHIFT; i++) {
@@ -1512,10 +1533,12 @@ peer_clear(
         */
        peer->nextdate = peer->update = peer->outdate = current_time;
        if (initializing)
-               peer->nextdate = current_time + peer_associations;
+               peer->nextdate += peer_associations;
+       else if (peer->hmode == MODE_PASSIVE)
+               peer->nextdate += RESP_DELAY;
        else
-               peer->nextdate = current_time + (ntp_random() & ((1 <<
-                   NTP_MINPOLL) - 1));
+               peer->nextdate += (ntp_random() & ((1 << NTP_MINDPOLL) -
+                   1));
 #ifdef DEBUG
        if (debug)
                printf("peer_clear: at %ld next %ld assoc ID %d refid %s\n",
@@ -1949,13 +1972,16 @@ clock_select(void)
         * NTP_MAXASSOC of them. Scan the list to find falsetickers, who
         * leave the island immediately. The TRUE peer is alwasy a
         * truechimer. We must leave at least one peer to collect the
-        * million bucks.
+        * million bucks. If in orphan mode, rascals found with lower
+        * stratum are guaranteed a seat on the bus.
         */
        j = 0;
        for (i = 0; i < nlist; i++) {
                peer = peer_list[i];
                if (nlist > 1 && (peer->offset <= low || peer->offset >=
-                   high) && !(peer->flags & FLAG_TRUE))
+                   high) && !(peer->flags & FLAG_TRUE) &&
+                   !(sys_stratum >= sys_orphan && peer->stratum <
+                   sys_orphan))
                        continue;
 
                peer->status = CTL_PST_SEL_DISTSYSPEER;
@@ -2006,7 +2032,6 @@ clock_select(void)
                        nlist = 1;
                } else {
                        if (osys_peer != NULL) {
-                               sys_poll = NTP_MINPOLL;
                                NLOG(NLOG_SYNCSTATUS)
                                    msyslog(LOG_INFO,
                                    "no servers reachable");
@@ -2089,6 +2114,10 @@ clock_select(void)
         * stratum. Note that the head of the list is at the lowest
         * stratum and that unsynchronized peers cannot survive this
         * far.
+        *
+        * In orphan mode the prefer peer is determined as the minimum
+        * root delay of the available peers. In normal mode the prefer
+        * peer is designated in the configuration file.
         */
        leap_next = 0;
        for (i = 0; i < nlist; i++) {
@@ -2155,7 +2184,11 @@ clock_select(void)
                } else {
                        sys_peer = sys_prefer;
                        sys_peer->status = CTL_PST_SEL_SYSPEER;
-                       sys_offset = sys_peer->offset;
+                       if (peer->stratum >= sys_orphan &&
+                           sys_orphandelay < sys_peer->rootdelay)
+                               sys_offset = 0;
+                       else
+                               sys_offset = sys_peer->offset;
                        sys_jitter = sys_peer->jitter;
 #ifdef DEBUG
                        if (debug > 1)
@@ -2234,14 +2267,22 @@ root_distance(
        struct peer *peer
        )
 {
+       double  dist;
+
        /*
         * Careful squeak here. The value returned must be greater than
-        * the minimum root distance in order to avoid clockhop with
-        * highly precise reference clocks.
+        * the minimum root dispersion in order to avoid clockhop with
+        * highly precise reference clocks. In orphan mode lose the peer
+        * root delay, as that is used by the election algorithm.
         */
-       return ((peer->rootdelay + peer->delay) / 2 +
+       if (peer->stratum >= sys_orphan)
+               dist = 0;
+       else
+               dist = peer->rootdelay;
+       dist += max(sys_mindisp, dist + peer->delay) / 2 +
            peer->rootdispersion + peer->disp + clock_phi *
-           (current_time - peer->update) + peer->jitter);
+           (current_time - peer->update) + peer->jitter;
+       return (dist);
 }
 
 /*
@@ -2261,15 +2302,15 @@ peer_xmit(
         * If the crypto is broken, don't make it worse. Otherwise,
         * initialize the header fields.
         */
-       if (peer->flash & TEST9)
-               return;
-
        xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, peer->version,
            peer->hmode);
        xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
        xpkt.ppoll = peer->hpoll;
        xpkt.precision = sys_precision;
-       xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
+       if (sys_stratum >= sys_orphan)
+               xpkt.rootdelay = HTONS_FP(DTOFP(sys_orphandelay));
+       else
+               xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
        xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion));
        xpkt.refid = sys_refid;
        HTONL_FP(&sys_reftime, &xpkt.reftime);
@@ -2395,9 +2436,16 @@ peer_xmit(
                 * synchronized, so the agreement must be postponed
                 * until then. In any case, if a new keylist is
                 * generated, the autokey values are pushed.
+                *
+                * If the crypto bit is set, don't send requests.
                 */
                case MODE_ACTIVE:
                case MODE_PASSIVE:
+                       if (peer->flash & TEST9)
+                               break;
+                       /*
+                        * Parameter and certificate.
+                        */
                        if (!peer->crypto)
                                exten = crypto_args(peer, CRYPTO_ASSOC,
                                    sys_hostname);
@@ -2470,8 +2518,15 @@ peer_xmit(
                 * requests them and the protocol blinds it using the
                 * agreed key. It is a protocol error if the client has
                 * the parameters but the server does not.
+                *
+                * If the crypto bit is lit, don't send requests.
                 */
                case MODE_CLIENT:
+                       if (peer->flash & TEST9)
+                               break;
+                       /*
+                        * Parameter and certificate.
+                        */
                        if (!peer->crypto)
                                exten = crypto_args(peer, CRYPTO_ASSOC,
                                    sys_hostname);
@@ -2514,10 +2569,11 @@ peer_xmit(
                }
 
                /*
-                * Build the extension fields if available. If an error
-                * occured, the crypto machinery broke or was
-                * misconfigured, so plaint the log and douse the
-                * boiler.
+                * Build the extension fields as directed. A response to
+                * a request is always sent, even if an error. If an
+                * error occurs when sending a request, the crypto
+                * machinery broke or was misconfigured. In that case
+                * light the crypto bit to suppress further requests.
                 */
                if (peer->cmmd != NULL) {
                        peer->cmmd->associd = htonl(peer->associd);
@@ -2527,40 +2583,48 @@ peer_xmit(
                        peer->cmmd = NULL;
                }
                if (exten != NULL) {
-                       if (exten->opcode != 0) {
+                       if (exten->opcode != 0)
                                sendlen += crypto_xmit(&xpkt,
                                    &peer->srcadr, sendlen, exten, 0);
-                               free(exten);
-                       } else {
-                               peer_clear(peer, "CRYP");
+                       if (ntohl(exten->opcode) & CRYPTO_ERROR) {
                                peer->flash |= TEST9; /* crypto error */
-                               msyslog(LOG_INFO,
-                                   "transmit: crypto error for %s",
-                                   stoa(&peer->srcadr));
                                free(exten);
                                return;
                        }
+                       free(exten);
                }
 
                /*
                 * If extension fields are present, we must use a
-                * private cookie value of zero. Most intricate.
+                * private cookie value of zero. Don't send if the
+                * crypto bit is set and no extension field is present,
+                * but in that case give back the key. Most intricate.
                 */
-               if (sendlen > LEN_PKT_NOMAC)
+               if (sendlen > LEN_PKT_NOMAC) {
                        session_key(&peer->dstadr->sin, &peer->srcadr,
                            xkeyid, 0, 2);
+               } else if (peer->flash & TEST9) {
+                       authtrust(xkeyid, 0);
+                       return;
+               }
        } 
 #endif /* OPENSSL */
+
+       /*
+        * Stash the transmit timestamp corrected for the encryption
+        * delay. If autokey, give back the key, as we use keys only
+        * once. Check for errors such as missing keys, buffer overflow,
+        * etc.
+        */
        xkeyid = peer->keyid;
        get_systime(&peer->xmt);
        L_ADD(&peer->xmt, &sys_authdelay);
        HTONL_FP(&peer->xmt, &xpkt.xmt);
        authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen);
        if (authlen == 0) {
-               peer_clear(peer, "NKEY");
+               msyslog(LOG_INFO, "transmit: %s key %u not found",
+                   stoa(&peer->srcadr), xkeyid);
                peer->flash |= TEST9;           /* no key found */
-               msyslog(LOG_INFO, "transmit: key %u not found for %s",
-                   xkeyid, stoa(&peer->srcadr));
                return;
        }
        sendlen += authlen;
@@ -2673,9 +2737,11 @@ fast_xmit(
        }
        xpkt.ppoll = rpkt->ppoll;
        xpkt.precision = sys_precision;
-       xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
-       xpkt.rootdispersion =
-           HTONS_FP(DTOUFP(sys_rootdispersion));
+       if (sys_stratum >= sys_orphan)
+               xpkt.rootdelay = HTONS_FP(DTOFP(sys_orphandelay));
+       else
+               xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
+       xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion));
        HTONL_FP(&sys_reftime, &xpkt.reftime);
        xpkt.org = rpkt->xmt;
        HTONL_FP(&rbufp->recv_time, &xpkt.rec);
@@ -2810,7 +2876,7 @@ key_expire(
  * A peer is unfit for synchronization if
  * > TEST10 bad leap or stratum below floor or at or above ceiling
  * > TEST11 root distance exceeded
- * > TEST12 a synchronization loop would form
+ * > TEST12 a direct or indirect synchronization loop would form
  * > TEST13 unreachable or noselect
  */
 int                            /* FALSE if fit, TRUE if unfit */
@@ -2821,15 +2887,16 @@ peer_unfit(
        int     rval = 0;
 
        if (peer->leap == LEAP_NOTINSYNC || peer->stratum < sys_floor ||
-           peer->stratum >= sys_ceiling)
+           peer->stratum >= sys_ceiling || (sys_stratum < sys_orphan &&
+           peer->stratum >= sys_orphan))
                rval |= TEST10;         /* stratum out of bounds */
 
        if (root_distance(peer) >= sys_maxdist + clock_phi *
            ULOGTOD(sys_poll))
                rval |= TEST11;         /* distance exceeded */
 
-       if (peer->stratum > 1 && peer->dstadr->addr_refid ==
-           peer->refid)
+       if (peer->stratum > 1 && (peer->refid ==
+           peer->dstadr->addr_refid || peer->refid == sys_refid))
                rval |= TEST12;         /* synch loop */
 
        if (!peer->reach || peer->flags & FLAG_NOSELECT)
@@ -2934,6 +3001,8 @@ init_proto(void)
        sys_precision = (s_char)default_get_precision();
        sys_jitter = LOGTOD(sys_precision);
        sys_rootdelay = 0;
+       sys_orphandelay = (double)(ntp_random() & 0xffff) / 65536. *
+           sys_maxdist;
        sys_rootdispersion = 0;
        L_CLR(&sys_reftime);
        sys_peer = NULL;
@@ -3107,6 +3176,13 @@ proto_config(
                sys_ceiling = (int)dvalue;
                break;
 
+       /*
+        * Set orphan stratum.
+        */
+       case PROTO_ORPHAN:
+               sys_orphan = (int)dvalue;
+               break;
+
        /*
         * Set cohort switch.
         */