original files of m241

This commit is contained in:
neelimap
2026-07-30 11:19:44 +05:30
parent 170c2b3f3a
commit afc7070c1f
12254 changed files with 7655111 additions and 0 deletions
@@ -0,0 +1,287 @@
/*
* digest support for NTP, MD5 and with OpenSSL more
*/
#ifdef HAVE_CONFIG_H
#include <ipntp_config.h>
#endif
#include "ntp_fp.h"
#include "ntp_string.h"
#include "ntp_stdlib.h"
#include "ntp.h"
#include "ntp_md5.h" /* provides OpenSSL digest API */
#include "isc/string.h"
#include "ipntp.h"
typedef struct {
const void * buf;
size_t len;
} robuffT;
typedef struct {
void * buf;
size_t len;
} rwbuffT;
#if defined(OPENSSL) && defined(ENABLE_CMAC)
static size_t
cmac_ctx_size(
CMAC_CTX * ctx)
{
size_t mlen = 0;
if (ctx) {
EVP_CIPHER_CTX * cctx;
if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
mlen = EVP_CIPHER_CTX_block_size(cctx);
}
return mlen;
}
#endif /*OPENSSL && ENABLE_CMAC*/
static size_t
make_mac(
const rwbuffT * digest,
int ktype,
const robuffT * key,
const robuffT * msg)
{
/*
* Compute digest of key concatenated with packet. Note: the
* key type and digest type have been verified when the key
* was created.
*/
size_t retlen = 0;
#ifdef OPENSSL
INIT_SSL();
/* Check if CMAC key type specific code required */
# ifdef ENABLE_CMAC
if (ktype == NID_cmac) {
CMAC_CTX * ctx = NULL;
void const * keyptr = key->buf;
u_char keybuf[AES_128_KEY_SIZE];
/* adjust key size (zero padded buffer) if necessary */
if (AES_128_KEY_SIZE > key->len) {
memcpy(keybuf, keyptr, key->len);
memset((keybuf + key->len), 0,
(AES_128_KEY_SIZE - key->len));
keyptr = keybuf;
}
if (NULL == (ctx = CMAC_CTX_new())) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
goto cmac_fail;
}
if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC);
goto cmac_fail;
}
if (cmac_ctx_size(ctx) > digest->len) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC);
goto cmac_fail;
}
if (!CMAC_Update(ctx, msg->buf, msg->len)) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC);
goto cmac_fail;
}
if (!CMAC_Final(ctx, digest->buf, &retlen)) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC);
retlen = 0;
}
cmac_fail:
if (ctx)
CMAC_CTX_free(ctx);
}
else
# endif /*ENABLE_CMAC*/
{ /* generic MAC handling */
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
u_int uilen = 0;
if ( ! ctx) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.",
OBJ_nid2sn(ktype));
goto mac_fail;
}
#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
/* make sure MD5 is allowd */
EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
#endif
/* [Bug 3457] DON'T use plain EVP_DigestInit! It would
* kill the flags! */
if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.",
OBJ_nid2sn(ktype));
goto mac_fail;
}
if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
OBJ_nid2sn(ktype));
goto mac_fail;
}
if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
OBJ_nid2sn(ktype));
goto mac_fail;
}
if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
OBJ_nid2sn(ktype));
goto mac_fail;
}
if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
OBJ_nid2sn(ktype));
uilen = 0;
}
mac_fail:
retlen = (size_t)uilen;
if (ctx)
EVP_MD_CTX_free(ctx);
}
#else /* !OPENSSL follows */
if (ktype == NID_md5)
{
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
u_int uilen = 0;
if (digest->len < 16) {
msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
}
else if ( ! ctx) {
msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed.");
}
else {
EVP_DigestInit(ctx, EVP_get_digestbynid(ktype));
EVP_DigestUpdate(ctx, key->buf, key->len);
EVP_DigestUpdate(ctx, msg->buf, msg->len);
EVP_DigestFinal(ctx, digest->buf, &uilen);
}
if (ctx)
EVP_MD_CTX_free(ctx);
retlen = (size_t)uilen;
}
else
{
msyslog(LOG_ERR, "MAC encrypt: invalid key type %d" , ktype);
}
#endif /* !OPENSSL */
return retlen;
}
/*
* MD5authencrypt - generate message digest
*
* Returns length of MAC including key ID and digest.
*/
size_t
MD5authencrypt(
int type, /* hash algorithm */
const u_char * key, /* key pointer */
size_t klen, /* key length */
u_int32 * pkt, /* packet pointer */
size_t length /* packet length */
)
{
u_char digest[EVP_MAX_MD_SIZE];
rwbuffT digb = { digest, sizeof(digest) };
robuffT keyb = { key, klen };
robuffT msgb = { pkt, length };
size_t dlen = 0;
dlen = make_mac(&digb, type, &keyb, &msgb);
/* If the MAC is longer than the MAX then truncate it. */
if (dlen > MAX_MDG_LEN)
dlen = MAX_MDG_LEN;
memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen);
return (dlen + KEY_MAC_LEN);
}
/*
* MD5authdecrypt - verify MD5 message authenticator
*
* Returns one if digest valid, zero if invalid.
*/
int
MD5authdecrypt(
int type, /* hash algorithm */
const u_char * key, /* key pointer */
size_t klen, /* key length */
u_int32 * pkt, /* packet pointer */
size_t length, /* packet length */
size_t size /* MAC size */
)
{
u_char digest[EVP_MAX_MD_SIZE];
rwbuffT digb = { digest, sizeof(digest) };
robuffT keyb = { key, klen };
robuffT msgb = { pkt, length };
size_t dlen = 0;
dlen = make_mac(&digb, type, &keyb, &msgb);
/* If the MAC is longer than the MAX then truncate it. */
if (dlen > MAX_MDG_LEN)
dlen = MAX_MDG_LEN;
if (size != (size_t)dlen + KEY_MAC_LEN) {
msyslog(LOG_ERR,
"MAC decrypt: MAC length error");
return (0);
}
return !isc_tsmemcmp(digest,
(u_char *)pkt + length + KEY_MAC_LEN, dlen);
}
/*
* Calculate the reference id from the address. If it is an IPv4
* address, use it as is. If it is an IPv6 address, do a md5 on
* it and use the bottom 4 bytes.
* The result is in network byte order.
*/
u_int32
addr2refid(sockaddr_u *addr)
{
u_char digest[EVP_MAX_MD_SIZE];
u_int32 addr_refid;
EVP_MD_CTX *ctx;
u_int len;
if (IS_IPV4(addr))
return (NSRCADR(addr));
INIT_SSL();
ctx = EVP_MD_CTX_new();
# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
/* MD5 is not used as a crypto hash here. */
EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
# endif
/* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the
* flags! */
if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
msyslog(LOG_ERR,
"MD5 init failed");
EVP_MD_CTX_free(ctx); /* pedantic... but safe */
ipntp_exit_callback(ipcom_getpid());
}
EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
sizeof(struct in6_addr));
EVP_DigestFinal(ctx, digest, &len);
EVP_MD_CTX_free(ctx);
memcpy(&addr_refid, digest, sizeof(addr_refid));
return (addr_refid);
}
@@ -0,0 +1,702 @@
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#ifdef MPE
/*
* MPE lacks adjtime(), so we define our own. But note that time slewing has
* a sub-second accuracy bug documented in SR 5003462838 which prevents ntpd
* from being able to maintain clock synch. Because of the bug, this adjtime()
* implementation as used by ntpd has a side-effect of screwing up the hardware
* PDC clock, which will need to be reset with a reboot.
*
* This problem affects all versions of MPE at the time of this writing (when
* MPE/iX 7.0 is the most current). It only causes bad things to happen when
* doing continuous clock synchronization with ntpd; note that you CAN run ntpd
* with "disable ntp" in ntp.conf if you wish to provide a time server.
*
* The one-time clock adjustment functionality of ntpdate and ntp_timeset can
* be used without screwing up the PDC clock.
*
*/
#include <time.h>
int adjtime(struct timeval *delta, struct timeval *olddelta);
int adjtime(struct timeval *delta, struct timeval *olddelta)
{
/* Documented, supported MPE system intrinsics. */
extern void GETPRIVMODE(void);
extern void GETUSERMODE(void);
/* Undocumented, unsupported MPE internal functions. */
extern long long current_correction_usecs(void);
extern long long get_time(void);
extern void get_time_change_info(long long *, char *, char *);
extern long long pdc_time(int *);
extern void set_time_correction(long long, int, int);
extern long long ticks_to_micro(long long);
long long big_sec, big_usec, new_correction = 0LL;
long long prev_correction;
if (delta != NULL) {
/* Adjustment required. Convert delta to 64-bit microseconds. */
big_sec = (long)delta->tv_sec;
big_usec = delta->tv_usec;
new_correction = (big_sec * 1000000LL) + big_usec;
}
GETPRIVMODE();
/* Determine how much of a previous correction (if any) we're interrupting. */
prev_correction = current_correction_usecs();
if (delta != NULL) {
/* Adjustment required. */
#if 0
/* Speculative code disabled until bug SR 5003462838 is fixed. This bug
prevents accurate time slewing, and indeed renders ntpd inoperable. */
if (prev_correction != 0LL) {
/* A previous adjustment did not complete. Since the PDC UTC clock was
immediately jumped at the start of the previous adjustment, we must
explicitly reset it to the value of the MPE local time clock minus the
time zone offset. */
char pwf_since_boot, recover_pwf_time;
long long offset_ticks, offset_usecs, pdc_usecs_current, pdc_usecs_wanted;
int hpe_status;
get_time_change_info(&offset_ticks, &pwf_since_boot, &recover_pwf_time);
offset_usecs = ticks_to_micro(offset_ticks);
pdc_usecs_wanted = get_time() - offset_usecs;
pdc_usecs_current = pdc_time(&hpe_status);
if (hpe_status == 0)
/* Force new PDC time by starting an extra correction. */
set_time_correction(pdc_usecs_wanted - pdc_usecs_current,0,1);
}
#endif /* 0 */
/* Immediately jump the PDC time to the new value, and then initiate a
gradual MPE time correction slew. */
set_time_correction(new_correction,0,1);
}
GETUSERMODE();
if (olddelta != NULL) {
/* Caller wants to know remaining amount of previous correction. */
(long)olddelta->tv_sec = prev_correction / 1000000LL;
olddelta->tv_usec = prev_correction % 1000000LL;
}
return 0;
}
#endif /* MPE */
#ifdef NEED_HPUX_ADJTIME
/*************************************************************************/
/* (c) Copyright Tai Jin, 1988. All Rights Reserved. */
/* Hewlett-Packard Laboratories. */
/* */
/* Permission is hereby granted for unlimited modification, use, and */
/* distribution. This software is made available with no warranty of */
/* any kind, express or implied. This copyright notice must remain */
/* intact in all versions of this software. */
/* */
/* The author would appreciate it if any bug fixes and enhancements were */
/* to be sent back to him for incorporation into future versions of this */
/* software. Please send changes to tai@iag.hp.com or ken@sdd.hp.com. */
/*************************************************************************/
/*
* Revision history
*
* 9 Jul 94 David L. Mills, Unibergity of Delabunch
* Implemented variable threshold to limit age of
* corrections; reformatted code for readability.
*/
#ifndef lint
static char RCSid[] = "adjtime.c,v 3.1 1993/07/06 01:04:42 jbj Exp";
#endif
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <time.h>
#include <signal.h>
#include "adjtime.h"
#define abs(x) ((x) < 0 ? -(x) : (x))
/*
* The following paramters are appropriate for an NTP adjustment
* interval of one second.
*/
#define ADJ_THRESH 200 /* initial threshold */
#define ADJ_DELTA 4 /* threshold decrement */
static long adjthresh; /* adjustment threshold */
static long saveup; /* corrections accumulator */
/*
* clear_adjtime - reset accumulator and threshold variables
*/
void
_clear_adjtime(void)
{
saveup = 0;
adjthresh = ADJ_THRESH;
}
/*
* adjtime - hp-ux copout of the standard Unix adjtime() system call
*/
int
adjtime(
register struct timeval *delta,
register struct timeval *olddelta
)
{
struct timeval newdelta;
/*
* Corrections greater than one second are done immediately.
*/
if (delta->tv_sec) {
adjthresh = ADJ_THRESH;
saveup = 0;
return(_adjtime(delta, olddelta));
}
/*
* Corrections less than one second are accumulated until
* tripping a threshold, which is initially set at ADJ_THESH and
* reduced in ADJ_DELTA steps to zero. The idea here is to
* introduce large corrections quickly, while making sure that
* small corrections are introduced without excessive delay. The
* idea comes from the ARPAnet routing update algorithm.
*/
saveup += delta->tv_usec;
if (abs(saveup) >= adjthresh) {
adjthresh = ADJ_THRESH;
newdelta.tv_sec = 0;
newdelta.tv_usec = saveup;
saveup = 0;
return(_adjtime(&newdelta, olddelta));
} else {
adjthresh -= ADJ_DELTA;
}
/*
* While nobody uses it, return the residual before correction,
* as per Unix convention.
*/
if (olddelta)
olddelta->tv_sec = olddelta->tv_usec = 0;
return(0);
}
/*
* _adjtime - does the actual work
*/
int
_adjtime(
register struct timeval *delta,
register struct timeval *olddelta
)
{
register int mqid;
MsgBuf msg;
register MsgBuf *msgp = &msg;
/*
* Get the key to the adjtime message queue (note that we must
* get it every time because the queue might have been removed
* and recreated)
*/
if ((mqid = msgget(KEY, 0)) == -1)
return (-1);
msgp->msgb.mtype = CLIENT;
msgp->msgb.tv = *delta;
if (olddelta)
msgp->msgb.code = DELTA2;
else
msgp->msgb.code = DELTA1;
/*
* Tickle adjtimed and snatch residual, if indicated. Lots of
* fanatic error checking here.
*/
if (msgsnd(mqid, &msgp->msgp, MSGSIZE, 0) == -1)
return (-1);
if (olddelta) {
if (msgrcv(mqid, &msgp->msgp, MSGSIZE, SERVER, 0) == -1)
return (-1);
*olddelta = msgp->msgb.tv;
}
return (0);
}
#else
# if NEED_QNX_ADJTIME
/*
* Emulate adjtime() using QNX ClockAdjust().
* Chris Burghart <burghart@atd.ucar.edu>, 11/2001
* Miroslaw Pabich <miroslaw_pabich@o2.pl>, 09/2005
*
* This is an implementation of adjtime() for QNX.
* ClockAdjust() is used to tweak the system clock for about
* 1 second period until the desired delta is achieved.
* Time correction slew is limited to reasonable value.
* Internal rounding and relative errors are reduced.
*/
# include <sys/neutrino.h>
# include <sys/time.h>
# include <ntp_stdlib.h>
/*
* Time correction slew limit. QNX is a hard real-time system,
* so don't adjust system clock too fast.
*/
#define CORR_SLEW_LIMIT 0.02 /* [s/s] */
/*
* Period of system clock adjustment. It should be equal to adjtime
* execution period (1s). If slightly less than 1s (0.95-0.99), then olddelta
* residual error (introduced by execution period jitter) will be reduced.
*/
#define ADJUST_PERIOD 0.97 /* [s] */
int
adjtime (struct timeval *delta, struct timeval *olddelta)
{
double delta_nsec;
double delta_nsec_old;
struct _clockadjust adj;
struct _clockadjust oldadj;
/*
* How many nanoseconds are we adjusting?
*/
if (delta != NULL)
delta_nsec = 1e9 * (long)delta->tv_sec + 1e3 * delta->tv_usec;
else
delta_nsec = 0;
/*
* Build the adjust structure and call ClockAdjust()
*/
if (delta_nsec != 0)
{
struct _clockperiod period;
long count;
long increment;
long increment_limit;
int isneg = 0;
/*
* Convert to absolute value for future processing
*/
if (delta_nsec < 0)
{
isneg = 1;
delta_nsec = -delta_nsec;
}
/*
* Get the current clock period (nanoseconds)
*/
if (ClockPeriod (CLOCK_REALTIME, 0, &period, 0) == -1)
return -1;
/*
* Compute count and nanoseconds increment
*/
count = 1e9 * ADJUST_PERIOD / period.nsec;
increment = delta_nsec / count + .5;
/* Reduce relative error */
if (count > increment + 1)
{
increment = 1 + (long)((delta_nsec - 1) / count);
count = delta_nsec / increment + .5;
}
/*
* Limit the adjust increment to appropriate value
*/
increment_limit = CORR_SLEW_LIMIT * period.nsec;
if (increment > increment_limit)
{
increment = increment_limit;
count = delta_nsec / increment + .5;
/* Reduce relative error */
if (increment > count + 1)
{
count = 1 + (long)((delta_nsec - 1) / increment);
increment = delta_nsec / count + .5;
}
}
adj.tick_nsec_inc = isneg ? -increment : increment;
adj.tick_count = count;
}
else
{
adj.tick_nsec_inc = 0;
adj.tick_count = 0;
}
if (ClockAdjust (CLOCK_REALTIME, &adj, &oldadj) == -1)
return -1;
/*
* Build olddelta
*/
delta_nsec_old = (double)oldadj.tick_count * oldadj.tick_nsec_inc;
if (olddelta != NULL)
{
if (delta_nsec_old != 0)
{
/* Reduce rounding error */
delta_nsec_old += (delta_nsec_old < 0) ? -500 : 500;
olddelta->tv_sec = delta_nsec_old / 1e9;
olddelta->tv_usec = (long)(delta_nsec_old - 1e9
* (long)olddelta->tv_sec) / 1000;
}
else
{
olddelta->tv_sec = 0;
olddelta->tv_usec = 0;
}
}
return 0;
}
# else /* no special adjtime() needed */
int adjtime_bs;
# endif
#endif
#ifdef HAVE_VXWORKS_ADJTIME
#include <ipcom_type.h>
#include <ipcom_time.h>
#include "ntp_syslog.h"
#include "declcond.h"
/* clear system clock adjustment to be 0 */
void adjtime_clear (void)
{
struct timeval tm;
tm.tv_sec = 0;
tm.tv_usec = 0;
(void)ipcom_adjtime(&tm, IP_NULL);
}
int adjtime (struct timeval *delta, struct timeval *olddelta)
{
if (ipcom_adjtime(delta, olddelta) < 0)
{
#ifdef NTP_DEBUG
if (debug > 3)
msyslog(LOG_ERR, "Failed in calling ipcom_adjtime: (%li:%li) old(%li:%li)",
delta->tv_sec, delta->tv_usec, olddelta->tv_sec, olddelta->tv_usec);
#endif
return -1;
}
return 0;
}
#else
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_err.h>
#include <time.h>
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
#include "ntp_vxworks.h"
#define SinMS 1000000L
int adjtime( struct timeval *delta, struct timeval *olddelta )
{
struct Ip_timeval tm;
(void)ipcom_gettimeofday(&tm, IP_NULL);
if (delta->tv_sec > 0 || (delta->tv_sec == 0 && delta->tv_usec > 0))
{
tm.tv_sec += delta->tv_sec;
tm.tv_usec += delta->tv_usec;
if (tm.tv_usec > SinMS)
{
tm.tv_usec -= SinMS;
tm.tv_sec += 1;
}
}
else /* delta is a negative value. */
{
tm.tv_sec += delta->tv_sec;
tm.tv_usec += delta->tv_usec;
if (tm.tv_usec < 0)
{
tm.tv_usec += SinMS;
tm.tv_sec -= 1;
}
}
#ifdef NTP_DEBUG
if (debug > 3)
msyslog(LOG_DEBUG, "%s1: (%li:%li) old(%li:%li)",
__FUNCTION__, delta->tv_sec, delta->tv_usec,
olddelta->tv_sec, olddelta->tv_usec);
#endif
(void)ipcom_settimeofday(&tm, IP_NULL);
return 0;
}
#endif /* !HAVE_VXWORKS_ADJTIME */
/* The software precision is low. These following codes is suitable for HW adjust time */
#if 0
#define USECS_PER_SEC 1000000
#define ADJTIME_MAX (0x7fffffff/(USECS_PER_SEC*NTP_SYSCLKRATEGET)) /* = ~35 s at 60 Hz */
static Ip_s32 adjTime = 0; /* Time left to adjust in clocke ticks */
static Ipcom_mutex adjTimeMsem = IP_NULL;
static Ip_pid_t adjTime_tid = 0;
int adj_debug = 0;
void usrTimeAdj(void)
{
struct Ip_timeval tm;
struct Ip_timeval tm_res;
ipcom_proc_init();
/* assume that clock resolution is <= 1 second */
tm_res.tv_sec = 0;
tm_res.tv_usec = (1000000 / NTP_SYSCLKRATEGET);
#ifdef NTP_DEBUG
if (debug > 3)
msyslog(LOG_DEBUG, "tadjTime task start");
#endif
for (;;)
{
if (adjTime == 0)
{
adjTime_tid = 0;
#ifdef NTP_DEBUG
if (debug > 3)
msyslog(LOG_DEBUG, "tadjTime task exit");
#endif
goto exit;
}
(void)ipcom_millisleep(250);
(void)ipcom_gettimeofday(&tm, IP_NULL);
if (adjTime > 0)
{
tm.tv_usec += tm_res.tv_usec;
if (tm.tv_usec > SinMS)
{
tm.tv_usec -= SinMS;
tm.tv_sec += 1;
}
ipcom_mutex_lock(adjTimeMsem);
{
adjTime--;
}
ipcom_mutex_unlock(adjTimeMsem);
}
else
{
tm.tv_usec -= tm_res.tv_usec;
if (tm.tv_usec < 0)
{
tm.tv_usec += SinMS;
tm.tv_sec -= 1;
}
ipcom_mutex_lock(adjTimeMsem);
{
adjTime++;
}
ipcom_mutex_unlock(adjTimeMsem);
}
/*printf("adjTime %d set %d,%d\n", adjTime, tv.tv_sec,tv.tv_nsec );*/
(void)ipcom_settimeofday(&tm, IP_NULL);
} /* FOREVER */
exit:
ipcom_proc_exit();
}
Ip_s32 adjtime( struct timeval *delta, struct timeval *olddelta )
{
int adjTime_in_usec = adjTime * USECS_PER_SEC;
double adjTime2;
#ifdef NTP_DEBUG
if (adj_debug)
msyslog(LOG_DEBUG, "%s1: %i (%li:%li) old(%li:%li)",
__FUNCTION__, adjTime,
delta->tv_sec, delta->tv_usec,
olddelta->tv_sec, olddelta->tv_usec);
if (delta->tv_sec)
msyslog(LOG_DEBUG, "%s1: %i (%li:%li) old(%li:%li)",
__FUNCTION__, adjTime,
delta->tv_sec, delta->tv_usec,
olddelta->tv_sec, olddelta->tv_usec);
#endif
if ( (delta->tv_sec > ADJTIME_MAX) || (delta->tv_sec < -ADJTIME_MAX) )
{
return( -1 );
}
if(adjTimeMsem == IP_NULL)
{
if (ipcom_mutex_create(&adjTimeMsem) != IPCOM_SUCCESS)
return -1;
}
ipcom_mutex_lock(adjTimeMsem);
{
olddelta->tv_sec = (adjTime_in_usec / USECS_PER_SEC);
olddelta->tv_usec = (adjTime_in_usec % USECS_PER_SEC);
adjTime2 = (double)(((delta->tv_sec * (double)USECS_PER_SEC) + delta->tv_usec) * NTP_SYSCLKRATEGET)/
(double)USECS_PER_SEC;
if (adj_debug)
msyslog(LOG_DEBUG, "%s1: %.6f", __FUNCTION__, adjTime2);
/* round up */
if (adjTime2 > 0)
adjTime2 += 0.5;
else
adjTime2 -= 0.5;
if (adj_debug)
msyslog(LOG_DEBUG, "%s1: %.6f", __FUNCTION__, adjTime2);
adjTime = (int) adjTime2;
}
ipcom_mutex_unlock(adjTimeMsem);
#ifdef NTP_DEBUG
if (adj_debug)
msyslog(LOG_DEBUG, "%s1: %i",
__FUNCTION__, adjTime);
#endif
if (!adjTime)
{
/* if the adjustment is less then the resolution it can't be adjusted */
return 0;
}
if (adjTime_tid == 0)
{
Ipcom_proc_attr attr;
ipcom_proc_attr_init(&attr);
attr.priority = IPCOM_PRIORITY_MIN;
attr.flags |= IPCOM_PROC_FLAG_FP;
attr.stacksize = IPCOM_PROC_STACK_DEFAULT;
if(ipcom_proc_acreate("tAdjTime", (Ipcom_proc_func)usrTimeAdj, &attr, &adjTime_tid))
{
return -1;
}
}
#ifdef NTP_DEBUG
if (adj_debug)
msyslog(LOG_DEBUG, "%s2: %i (%li:%li) old(%li:%li)",
__FUNCTION__, adjTime,
delta->tv_sec, delta->tv_usec,
olddelta->tv_sec, olddelta->tv_usec);
#endif
return( 0 );
} /* adjtime() */
void kill_adjtimeTask ( void )
{
if (adjTime_tid != 0)
{
ipcom_mutex_lock(adjTimeMsem);
adjTime = 0;
ipcom_mutex_unlock(adjTimeMsem);
/* call ipcom_sleep to make the tAdjTime task exit */
ipcom_millisleep(100);
/*
if (adjTimeMsem != IP_NULL)
(void)ipcom_mutex_delete(&adjTimeMsem);
adjTimeMsem = IP_NULL;
*/
adjTime_tid = 0;
}
adjTime = 0; /* Time left to adjust in clocke ticks */
adj_debug = 0;
}
/* test codes */
void adjtimetest(int s)
{
struct timeval delta;
struct timeval olddelta;
delta.tv_sec = s;
delta.tv_usec = 0;
printf("new: %li:%li\n", delta.tv_sec, delta.tv_usec);
if (adjtime( &delta, &olddelta ) != 0)
{
printf("ADJTIME ERROR\n");
return;
}
printf("old: %li:%li -> new %li:%li\n", olddelta.tv_sec, olddelta.tv_usec, delta.tv_sec, delta.tv_usec);
}
void setdate(char* str)
{
struct tm tm ;
struct timespec tv ;
tm.tm_sec = (str[10] -'0')*10 + str[11] - '0' ;
tm.tm_min = (str[8] -'0')*10 + str[9] - '0' ;
tm.tm_hour = (str[6] -'0')*10 + str[7] - '0' ;
tm.tm_mday = (str[4] -'0')*10 + str[5] - '0' ;
tm.tm_mon = (str[2] -'0')*10 + str[3] - '0' - 1; /* Jan == 0 */
tm.tm_year = (str[0] -'0')*10 + str[1] - '0' + 100;
tm.tm_wday = 0 ;
tm.tm_yday = 0 ;
tm.tm_isdst = 0 ;
tv.tv_sec = mktime( &tm );
tv.tv_nsec = 0;
printf("sec: %li\n",tv.tv_sec);
clock_settime( CLOCK_REALTIME, &tv );
}
#endif /* 0 */
@@ -0,0 +1,15 @@
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
_sccsid:.asciz "11/19/91 ULTRIX @(#)adjtime.c 6.1"
#endif not lint
#include "SYS.h"
SYSCALL(adjtimex)
ret
@@ -0,0 +1,51 @@
/*
* atoint - convert an ascii string to a signed long, with error checking
*/
#include <ipntp_config.h>
#include <sys/types.h>
#include <ctype.h>
#include "ntp_types.h"
#include "ntp_stdlib.h"
int
atoint(
const char *str,
long *ival
)
{
register long u;
register const char *cp;
register int isneg;
register int oflow_digit;
cp = str;
if (*cp == '-') {
cp++;
isneg = 1;
oflow_digit = '8';
} else {
isneg = 0;
oflow_digit = '7';
}
if (*cp == '\0')
return 0;
u = 0;
while (*cp != '\0') {
if (!isdigit((unsigned char)*cp))
return 0;
if (u > 214748364 || (u == 214748364 && *cp > oflow_digit))
return 0; /* overflow */
u = (u << 3) + (u << 1);
u += *cp++ - '0'; /* ascii dependent */
}
if (isneg)
*ival = -u;
else
*ival = u;
return 1;
}
@@ -0,0 +1,122 @@
/*
* atolfp - convert an ascii string to an l_fp number
*/
#include <ipntp_config.h>
#include <stdio.h>
#include <ctype.h>
#include "ntp_fp.h"
#include "ntp_string.h"
#include "ntp_assert.h"
/*
* Powers of 10
*/
static u_long ten_to_the_n[10] = {
0,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
};
int
atolfp(
const char *str,
l_fp *lfp
)
{
register const char *cp;
register u_long dec_i;
register u_long dec_f;
char *ind;
int ndec;
int isneg;
static const char *digits = "0123456789";
REQUIRE(str != NULL);
isneg = 0;
dec_i = dec_f = 0;
ndec = 0;
cp = str;
/*
* We understand numbers of the form:
*
* [spaces][-|+][digits][.][digits][spaces|\n|\0]
*/
while (isspace((unsigned char)*cp))
cp++;
if (*cp == '-') {
cp++;
isneg = 1;
}
if (*cp == '+')
cp++;
if (*cp != '.' && !isdigit((unsigned char)*cp))
return 0;
while (*cp != '\0' && (ind = strchr(digits, *cp)) != NULL) {
dec_i = (dec_i << 3) + (dec_i << 1); /* multiply by 10 */
dec_i += (u_long)(ind - digits);
cp++;
}
if (*cp != '\0' && !isspace((unsigned char)*cp)) {
if (*cp++ != '.')
return 0;
while (ndec < 9 && *cp != '\0'
&& (ind = strchr(digits, *cp)) != NULL) {
ndec++;
dec_f = (dec_f << 3) + (dec_f << 1); /* *10 */
dec_f += (u_long)(ind - digits);
cp++;
}
while (isdigit((unsigned char)*cp))
cp++;
if (*cp != '\0' && !isspace((unsigned char)*cp))
return 0;
}
if (ndec > 0) {
register u_long tmp;
register u_long bit;
register u_long ten_fact;
ten_fact = ten_to_the_n[ndec];
tmp = 0;
bit = 0x80000000;
while (bit != 0) {
dec_f <<= 1;
if (dec_f >= ten_fact) {
tmp |= bit;
dec_f -= ten_fact;
}
bit >>= 1;
}
if ((dec_f << 1) > ten_fact)
tmp++;
dec_f = tmp;
}
if (isneg)
M_NEG(dec_i, dec_f);
lfp->l_ui = dec_i;
lfp->l_uf = dec_f;
return 1;
}
@@ -0,0 +1,42 @@
#include <ipntp_config.h>
#include <sys/types.h>
#include <ctype.h>
#include "ntp_types.h"
#include "ntp_stdlib.h"
/*
* atouint() - convert an ascii string representing a whole base 10
* number to u_long *uval, returning TRUE if successful.
* Does not modify *uval and returns FALSE if str is not
* a positive base10 integer or is too large for a u_int32.
* this function uses u_long but should use u_int32, and
* probably be renamed.
*/
int
atouint(
const char *str,
u_long *uval
)
{
u_long u;
const char *cp;
cp = str;
if ('\0' == *cp)
return 0;
u = 0;
while ('\0' != *cp) {
if (!isdigit((unsigned char)*cp))
return 0;
if (u > 429496729 || (u == 429496729 && *cp >= '6'))
return 0; /* overflow */
/* hand-optimized u *= 10; */
u = (u << 3) + (u << 1);
u += *cp++ - '0'; /* not '\0' */
}
*uval = u;
return 1;
}
@@ -0,0 +1,519 @@
/*
* audio.c - audio interface for reference clock audio drivers
*/
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#if defined(HAVE_SYS_AUDIOIO_H) || defined(HAVE_SUN_AUDIOIO_H) || \
defined(HAVE_SYS_SOUNDCARD_H) || defined(HAVE_MACHINE_SOUNDCARD_H)
#include "audio.h"
#include "ntp_stdlib.h"
#include "ntp_syslog.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdio.h>
#include "ntp_string.h"
#ifdef HAVE_SYS_AUDIOIO_H
# include <sys/audioio.h>
#endif /* HAVE_SYS_AUDIOIO_H */
#ifdef HAVE_SUN_AUDIOIO_H
# include <sys/ioccom.h>
# include <sun/audioio.h>
#endif /* HAVE_SUN_AUDIOIO_H */
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif /* HAVE_SYS_IOCTL_H */
#include <fcntl.h>
#ifdef HAVE_MACHINE_SOUNDCARD_H
# include <machine/soundcard.h>
# define PCM_STYLE_SOUND
#else
# ifdef HAVE_SYS_SOUNDCARD_H
# include <sys/soundcard.h>
# define PCM_STYLE_SOUND
# endif
#endif
#ifdef PCM_STYLE_SOUND
# include <ctype.h>
#endif
/*
* 4.4BSD-Lite switched to an unsigned long ioctl arg. Detect common
* derivatives here, and apply that type. To make the following code
* less verbose we make a proper typedef.
* The joy of IOCTL programming...
*/
# if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__) || defined __OpenBSD__
typedef unsigned long ioctl_arg_T;
#else
typedef int ioctl_arg_T;
#endif
/*
* Global variables
*/
#ifdef HAVE_SYS_AUDIOIO_H
static struct audio_device device; /* audio device ident */
#endif /* HAVE_SYS_AUDIOIO_H */
#ifdef PCM_STYLE_SOUND
# define INIT_FILE "/etc/ntp.audio"
static ioctl_arg_T agc = SOUND_MIXER_WRITE_RECLEV; /* or IGAIN or LINE */
static ioctl_arg_T audiomonitor = SOUND_MIXER_WRITE_VOLUME; /* or OGAIN */
static int devmask = 0;
static int recmask = 0;
static char cf_c_dev[100], cf_i_dev[100], cf_agc[100], cf_monitor[100];
static const char *m_names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
#else /* not PCM_STYLE_SOUND */
static struct audio_info info; /* audio device info */
#endif /* not PCM_STYLE_SOUND */
static int ctl_fd; /* audio control file descriptor */
#ifdef PCM_STYLE_SOUND
static void audio_config_read (int, const char **, const char **);
static int mixer_name (const char *, int);
int
mixer_name(
const char *m_name,
int m_mask
)
{
int i;
for (i = 0; i < SOUND_MIXER_NRDEVICES; ++i)
if (((1 << i) & m_mask)
&& !strcmp(m_names[i], m_name))
break;
return (SOUND_MIXER_NRDEVICES == i)
? -1
: i
;
}
/*
* Check:
*
* /etc/ntp.audio# where # is the unit number
* /etc/ntp.audio.# where # is the unit number
* /etc/ntp.audio
*
* for contents of the form:
*
* idev /dev/input_device
* cdev /dev/control_device
* agc pcm_input_device {igain,line,line1,...}
* monitor pcm_monitor_device {ogain,...}
*
* The device names for the "agc" and "monitor" keywords
* can be found by running either the "mixer" program or the
* util/audio-pcm program.
*
* Great hunks of this subroutine were swiped from refclock_oncore.c
*/
static void
audio_config_read(
int unit,
const char **c_dev, /* Control device */
const char **i_dev /* input device */
)
{
FILE *fd;
char device[20], line[100], ab[100];
snprintf(device, sizeof(device), "%s%d", INIT_FILE, unit);
if ((fd = fopen(device, "r")) == NULL) {
printf("audio_config_read: <%s> NO\n", device);
snprintf(device, sizeof(device), "%s.%d", INIT_FILE,
unit);
if ((fd = fopen(device, "r")) == NULL) {
printf("audio_config_read: <%s> NO\n", device);
snprintf(device, sizeof(device), "%s",
INIT_FILE);
if ((fd = fopen(device, "r")) == NULL) {
printf("audio_config_read: <%s> NO\n",
device);
return;
}
}
}
printf("audio_config_read: reading <%s>\n", device);
while (fgets(line, sizeof line, fd)) {
char *cp, *cc, *ca;
int i;
/* Remove comments */
if ((cp = strchr(line, '#')))
*cp = '\0';
/* Remove any trailing spaces */
for (i = strlen(line);
i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]);
)
line[--i] = '\0';
/* Remove leading space */
for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++)
continue;
/* Stop if nothing left */
if (!*cc)
continue;
/* Uppercase the command and find the arg */
for (ca = cc; *ca; ca++) {
if (isascii((unsigned char)*ca)) {
if (islower((unsigned char)*ca)) {
*ca = toupper((unsigned char)*ca);
} else if (isspace((unsigned char)*ca) || (*ca == '='))
break;
}
}
/* Remove space (and possible =) leading the arg */
for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++)
continue;
if (!strncmp(cc, "IDEV", 4) &&
1 == sscanf(ca, "%99s", ab)) {
strlcpy(cf_i_dev, ab, sizeof(cf_i_dev));
printf("idev <%s>\n", ab);
} else if (!strncmp(cc, "CDEV", 4) &&
1 == sscanf(ca, "%99s", ab)) {
strlcpy(cf_c_dev, ab, sizeof(cf_c_dev));
printf("cdev <%s>\n", ab);
} else if (!strncmp(cc, "AGC", 3) &&
1 == sscanf(ca, "%99s", ab)) {
strlcpy(cf_agc, ab, sizeof(cf_agc));
printf("agc <%s> %d\n", ab, i);
} else if (!strncmp(cc, "MONITOR", 7) &&
1 == sscanf(ca, "%99s", ab)) {
strlcpy(cf_monitor, ab, sizeof(cf_monitor));
printf("monitor <%s> %d\n", ab, mixer_name(ab, -1));
}
}
fclose(fd);
return;
}
#endif /* PCM_STYLE_SOUND */
/*
* audio_init - open and initialize audio device
*
* This code works with SunOS 4.x, Solaris 2.x, and PCM; however, it is
* believed generic and applicable to other systems with a minor twid
* or two. All it does is open the device, set the buffer size (Solaris
* only), preset the gain and set the input port. It assumes that the
* codec sample rate (8000 Hz), precision (8 bits), number of channels
* (1) and encoding (ITU-T G.711 mu-law companded) have been set by
* default.
*/
int
audio_init(
const char *dname, /* device name */
int bufsiz, /* buffer size */
int unit /* device unit (0-3) */
)
{
#ifdef PCM_STYLE_SOUND
# define ACTL_DEV "/dev/mixer%d"
char actl_dev[30];
# ifdef HAVE_STRUCT_SND_SIZE
struct snd_size s_size;
# endif
# ifdef AIOGFMT
snd_chan_param s_c_p;
# endif
#endif
int fd;
int rval;
const char *actl =
#ifdef PCM_STYLE_SOUND
actl_dev
#else
"/dev/audioctl"
#endif
;
#ifdef PCM_STYLE_SOUND
snprintf(actl_dev, sizeof(actl_dev), ACTL_DEV, unit);
audio_config_read(unit, &actl, &dname);
/* If we have values for cf_c_dev or cf_i_dev, use them. */
if (*cf_c_dev)
actl = cf_c_dev;
if (*cf_i_dev)
dname = cf_i_dev;
#endif
/*
* Open audio device
*/
fd = open(dname, O_RDWR | O_NONBLOCK, 0777);
if (fd < 0) {
msyslog(LOG_ERR, "audio_init: %s %m", dname);
return (fd);
}
/*
* Open audio control device.
*/
ctl_fd = open(actl, O_RDWR);
if (ctl_fd < 0) {
msyslog(LOG_ERR, "audio_init: invalid control device <%s>",
actl);
close(fd);
return(ctl_fd);
}
/*
* Set audio device parameters.
*/
#ifdef PCM_STYLE_SOUND
printf("audio_init: <%s> bufsiz %d\n", dname, bufsiz);
rval = fd;
# ifdef HAVE_STRUCT_SND_SIZE
if (ioctl(fd, AIOGSIZE, &s_size) == -1)
printf("audio_init: AIOGSIZE: %s\n", strerror(errno));
else
printf("audio_init: orig: play_size %d, rec_size %d\n",
s_size.play_size, s_size.rec_size);
s_size.play_size = s_size.rec_size = bufsiz;
printf("audio_init: want: play_size %d, rec_size %d\n",
s_size.play_size, s_size.rec_size);
if (ioctl(fd, AIOSSIZE, &s_size) == -1)
printf("audio_init: AIOSSIZE: %s\n", strerror(errno));
else
printf("audio_init: set: play_size %d, rec_size %d\n",
s_size.play_size, s_size.rec_size);
# endif /* HAVE_STRUCT_SND_SIZE */
# ifdef SNDCTL_DSP_SETFRAGMENT
{
int tmp = (16 << 16) + 6; /* 16 fragments, each 2^6 bytes */
if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1)
printf("audio_init: SNDCTL_DSP_SETFRAGMENT: %s\n",
strerror(errno));
}
# endif /* SNDCTL_DSP_SETFRAGMENT */
# ifdef AIOGFMT
if (ioctl(fd, AIOGFMT, &s_c_p) == -1)
printf("audio_init: AIOGFMT: %s\n", strerror(errno));
else
printf("audio_init: play_rate %lu, rec_rate %lu, play_format %#lx, rec_format %#lx\n",
s_c_p.play_rate, s_c_p.rec_rate, s_c_p.play_format, s_c_p.rec_format);
# endif
/* Grab the device and record masks */
if (ioctl(ctl_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
printf("SOUND_MIXER_READ_DEVMASK: %s\n", strerror(errno));
if (ioctl(ctl_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
printf("SOUND_MIXER_READ_RECMASK: %s\n", strerror(errno));
/* validate and set any specified config file stuff */
if (cf_agc[0] != '\0') {
int i;
/* recmask */
i = mixer_name(cf_agc, recmask);
if (i >= 0)
agc = MIXER_WRITE(i);
else
printf("input %s not in recmask %#x\n",
cf_agc, recmask);
}
if (cf_monitor[0] != '\0') {
int i;
/* devmask */
i = mixer_name(cf_monitor, devmask);
if (i >= 0)
audiomonitor = MIXER_WRITE(i);
else
printf("monitor %s not in devmask %#x\n",
cf_monitor, devmask);
}
#else /* not PCM_STYLE_SOUND */
AUDIO_INITINFO(&info);
info.play.gain = AUDIO_MAX_GAIN;
info.play.port = AUDIO_SPEAKER;
# ifdef HAVE_SYS_AUDIOIO_H
info.record.buffer_size = bufsiz;
# endif /* HAVE_SYS_AUDIOIO_H */
rval = ioctl(ctl_fd, AUDIO_SETINFO, (char *)&info);
if (rval < 0) {
msyslog(LOG_ERR, "audio: invalid control device parameters");
close(ctl_fd);
close(fd);
return(rval);
}
rval = fd;
#endif /* not PCM_STYLE_SOUND */
return (rval);
}
/*
* audio_gain - adjust codec gains and port
*/
int
audio_gain(
int gain, /* volume level (gain) 0-255 */
int mongain, /* input to output mix (monitor gain) 0-255 */
int port /* selected I/O port: 1 mic/2 line in */
)
{
int rval;
static int o_mongain = -1;
static int o_port = -1;
#ifdef PCM_STYLE_SOUND
int l, r;
rval = 0;
r = l = 100 * gain / 255; /* Normalize to 0-100 */
# ifdef NTP_DEBUG
if (debug > 1)
printf("audio_gain: gain %d/%d\n", gain, l);
# endif
#if 0 /* not a good idea to do this; connector wiring dependency */
/* figure out what channel(s) to use. just nuke right for now. */
r = 0 ; /* setting to zero nicely mutes the channel */
#endif
l |= r << 8;
if (cf_agc[0] != '\0')
rval = ioctl(ctl_fd, agc, &l);
else
rval = ioctl(ctl_fd
, (2 == port)
? SOUND_MIXER_WRITE_LINE
: SOUND_MIXER_WRITE_MIC
, &l);
if (-1 == rval) {
printf("audio_gain: agc write: %s\n", strerror(errno));
return rval;
}
if (o_mongain != mongain) {
r = l = 100 * mongain / 255; /* Normalize to 0-100 */
# ifdef NTP_DEBUG
if (debug > 1)
printf("audio_gain: mongain %d/%d\n", mongain, l);
# endif
l |= r << 8;
if (cf_monitor[0] != '\0')
rval = ioctl(ctl_fd, audiomonitor, &l );
else
rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_VOLUME,
&l);
if (-1 == rval) {
printf("audio_gain: mongain write: %s\n",
strerror(errno));
return (rval);
}
o_mongain = mongain;
}
if (o_port != port) {
# ifdef NTP_DEBUG
if (debug > 1)
printf("audio_gain: port %d\n", port);
# endif
l = (1 << ((port == 2) ? SOUND_MIXER_LINE : SOUND_MIXER_MIC));
rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_RECSRC, &l);
if (rval == -1) {
printf("SOUND_MIXER_WRITE_RECSRC: %s\n",
strerror(errno));
return (rval);
}
# ifdef NTP_DEBUG
if (debug > 1) {
if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &l) == -1)
printf("SOUND_MIXER_WRITE_RECSRC: %s\n",
strerror(errno));
else
printf("audio_gain: recsrc is %d\n", l);
}
# endif
o_port = port;
}
#else /* not PCM_STYLE_SOUND */
ioctl(ctl_fd, AUDIO_GETINFO, (char *)&info);
info.record.encoding = AUDIO_ENCODING_ULAW;
info.record.error = 0;
info.record.gain = gain;
if (o_mongain != mongain)
o_mongain = info.monitor_gain = mongain;
if (o_port != port)
o_port = info.record.port = port;
rval = ioctl(ctl_fd, AUDIO_SETINFO, (char *)&info);
if (rval < 0) {
msyslog(LOG_ERR, "audio_gain: %m");
return (rval);
}
rval = info.record.error;
#endif /* not PCM_STYLE_SOUND */
return (rval);
}
/*
* audio_show - display audio parameters
*
* This code doesn't really do anything, except satisfy curiousity and
* verify the ioctl's work.
*/
void
audio_show(void)
{
#ifdef PCM_STYLE_SOUND
int recsrc = 0;
printf("audio_show: ctl_fd %d\n", ctl_fd);
if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
printf("SOUND_MIXER_READ_RECSRC: %s\n", strerror(errno));
#else /* not PCM_STYLE_SOUND */
# ifdef HAVE_SYS_AUDIOIO_H
ioctl(ctl_fd, AUDIO_GETDEV, &device);
printf("audio: name %s, version %s, config %s\n",
device.name, device.version, device.config);
# endif /* HAVE_SYS_AUDIOIO_H */
ioctl(ctl_fd, AUDIO_GETINFO, (char *)&info);
printf(
"audio: rate %d, chan %d, prec %d, code %d, gain %d, mon %d, port %d\n",
info.record.sample_rate, info.record.channels,
info.record.precision, info.record.encoding,
info.record.gain, info.monitor_gain, info.record.port);
printf(
"audio: samples %d, eof %d, pause %d, error %d, waiting %d, balance %d\n",
info.record.samples, info.record.eof,
info.record.pause, info.record.error,
info.record.waiting, info.record.balance);
#endif /* not PCM_STYLE_SOUND */
}
#else
int audio_bs;
#endif /* HAVE_{SYS_AUDIOIO,SUN_AUDIOIO,MACHINE_SOUNDCARD,SYS_SOUNDCARD}_H */
@@ -0,0 +1,954 @@
/*
* authkeys.c - routines to manage the storage of authentication keys
*/
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#include <math.h>
#include <stdio.h>
#include "ntp.h"
#include "ntp_fp.h"
#include "ntpd.h"
#include "ntp_lists.h"
#include "ntp_string.h"
#include "ntp_malloc.h"
#include "ntp_stdlib.h"
#include "ntp_keyacc.h"
#include <stdlib.h>
#include "ntp_mem.h"
/*
* Structure to store keys in in the hash table.
*/
typedef struct savekey symkey;
struct savekey {
symkey * hlink; /* next in hash bucket */
DECL_DLIST_LINK(symkey, llink); /* for overall & free lists */
u_char * secret; /* shared secret */
KeyAccT * keyacclist; /* Private key access list */
u_long lifetime; /* remaining lifetime */
keyid_t keyid; /* key identifier */
u_short type; /* OpenSSL digest NID */
size_t secretsize; /* secret octets */
u_short flags; /* KEY_ flags that wave */
};
/* define the payload region of symkey beyond the list pointers */
#define symkey_payload secret
#define KEY_TRUSTED 0x001 /* this key is trusted */
#ifdef NTP_DEBUG
typedef struct symkey_alloc_tag symkey_alloc;
struct symkey_alloc_tag {
symkey_alloc * link;
void * mem; /* enable free() atexit */
};
symkey_alloc * authallocs;
#endif /* NTP_DEBUG */
static u_short auth_log2(size_t);
static void auth_resize_hashtable(void);
static void allocsymkey(keyid_t, u_short,
u_short, u_long, size_t, u_char *, KeyAccT *);
static void freesymkey(symkey *);
void free_auth_mem(void);
symkey key_listhead; /* list of all in-use keys */;
/*
* The hash table. This is indexed by the low order bits of the
* keyid. We make this fairly big for potentially busy servers.
*/
#define DEF_AUTHHASHSIZE 64
/*#define HASHMASK ((HASHSIZE)-1)*/
#define KEYHASH(keyid) ((keyid) & authhashmask)
int authhashdisabled;
u_short authhashbuckets = DEF_AUTHHASHSIZE;
u_short authhashmask = DEF_AUTHHASHSIZE - 1;
symkey **key_hash;
u_long authkeynotfound; /* keys not found */
u_long authkeylookups; /* calls to lookup keys */
u_long authnumkeys; /* number of active keys */
u_long authkeyexpired; /* key lifetime expirations */
u_long authkeyuncached; /* cache misses */
u_long authnokey; /* calls to encrypt with no key */
u_long authencryptions; /* calls to encrypt */
u_long authdecryptions; /* calls to decrypt */
/*
* Storage for free symkey structures. We malloc() such things but
* never free them.
*/
symkey *authfreekeys;
int authnumfreekeys;
#define MEMINC 16 /* number of new free ones to get */
/*
* The key cache. We cache the last key we looked at here.
* Note: this should hold the last *trusted* key. Also the
* cache is only loaded when the digest type / MAC algorithm
* is valid.
*/
keyid_t cache_keyid; /* key identifier */
u_char *cache_secret; /* secret */
size_t cache_secretsize; /* secret length */
int cache_type; /* OpenSSL digest NID */
u_short cache_flags; /* flags that wave */
KeyAccT *cache_keyacclist; /* key access list */
/* --------------------------------------------------------------------
* manage key access lists
* --------------------------------------------------------------------
*/
/* allocate and populate new access node and pushes it on the list.
* Returns the new head.
*/
KeyAccT*
keyacc_new_push(
KeyAccT * head,
const sockaddr_u * addr,
unsigned int subnetbits
)
{
KeyAccT * node = emalloc(sizeof(KeyAccT));
memcpy(&node->addr, addr, sizeof(sockaddr_u));
node->subnetbits = subnetbits;
node->next = head;
return node;
}
/* ----------------------------------------------------------------- */
/* pop and deallocate the first node of a list of access nodes, if
* the list is not empty. Returns the tail of the list.
*/
KeyAccT*
keyacc_pop_free(
KeyAccT *head
)
{
KeyAccT * next = NULL;
if (head) {
next = head->next;
efree(head);
}
return next;
}
/* ----------------------------------------------------------------- */
/* deallocate the list; returns an empty list. */
KeyAccT*
keyacc_all_free(
KeyAccT * head
)
{
while (head)
head = keyacc_pop_free(head);
return head;
}
/* ----------------------------------------------------------------- */
/* scan a list to see if it contains a given address. Return the
* default result value in case of an empty list.
*/
int /*BOOL*/
keyacc_contains(
const KeyAccT *head,
const sockaddr_u *addr,
int defv)
{
if (head) {
do {
if (keyacc_amatch(&head->addr, addr,
head->subnetbits))
return TRUE;
} while (NULL != (head = head->next));
return FALSE;
} else {
return !!defv;
}
}
#if CHAR_BIT != 8
# error "don't know how to handle bytes with that bit size"
#endif
/* ----------------------------------------------------------------- */
/* check two addresses for a match, taking a prefix length into account
* when doing the compare.
*
* The ISC lib contains a similar function with not entirely specified
* semantics, so it seemed somewhat cleaner to do this from scratch.
*
* Note 1: It *is* assumed that the addresses are stored in network byte
* order, that is, most significant byte first!
*
* Note 2: "no address" compares unequal to all other addresses, even to
* itself. This has the same semantics as NaNs have for floats: *any*
* relational or equality operation involving a NaN returns FALSE, even
* equality with itself. "no address" is either a NULL pointer argument
* or an address of type AF_UNSPEC.
*/
int/*BOOL*/
keyacc_amatch(
const sockaddr_u * a1,
const sockaddr_u * a2,
unsigned int mbits
)
{
const uint8_t * pm1;
const uint8_t * pm2;
uint8_t msk;
unsigned int len;
/* 1st check: If any address is not an address, it's inequal. */
if ( !a1 || (AF_UNSPEC == AF(a1)) ||
!a2 || (AF_UNSPEC == AF(a2)) )
return FALSE;
/* We could check pointers for equality here and shortcut the
* other checks if we find object identity. But that use case is
* too rare to care for it.
*/
/* 2nd check: Address families must be the same. */
if (AF(a1) != AF(a2))
return FALSE;
/* type check: address family determines buffer & size */
switch (AF(a1)) {
case AF_INET:
/* IPv4 is easy: clamp size, get byte pointers */
if (mbits > sizeof(NSRCADR(a1)) * 8)
mbits = sizeof(NSRCADR(a1)) * 8;
pm1 = (const void*)&NSRCADR(a1);
pm2 = (const void*)&NSRCADR(a2);
break;
case AF_INET6:
/* IPv6 is slightly different: Both scopes must match,
* too, before we even consider doing a match!
*/
if ( ! SCOPE_EQ(a1, a2))
return FALSE;
if (mbits > sizeof(NSRCADR6(a1)) * 8)
mbits = sizeof(NSRCADR6(a1)) * 8;
pm1 = (const void*)&NSRCADR6(a1);
pm2 = (const void*)&NSRCADR6(a2);
break;
default:
/* don't know how to compare that!?! */
return FALSE;
}
/* Split bit length into byte length and partial byte mask.
* Note that the byte mask extends from the MSB of a byte down,
* and that zero shift (--> mbits % 8 == 0) results in an
* all-zero mask.
*/
msk = 0xFFu ^ (0xFFu >> (mbits & 7));
len = mbits >> 3;
/* 3rd check: Do memcmp() over full bytes, if any */
if (len && memcmp(pm1, pm2, len))
return FALSE;
/* 4th check: compare last incomplete byte, if any */
if (msk && ((pm1[len] ^ pm2[len]) & msk))
return FALSE;
/* If none of the above failed, we're successfully through. */
return TRUE;
}
/*
* init_auth - initialize internal data
*/
void
init_auth(void)
{
size_t newalloc;
authhashdisabled = 0;
authhashbuckets = DEF_AUTHHASHSIZE;
authhashmask = DEF_AUTHHASHSIZE - 1;
authkeynotfound = 0;
authkeylookups = 0;
authnumkeys = 0;
authkeyexpired = 0;
authkeyuncached = 0;
authnokey = 0;
authencryptions = 0;
authdecryptions = 0;
authfreekeys = NULL;
authnumfreekeys = 0;
memset(&cache_keyid, 0, sizeof(keyid_t));
cache_secret = NULL;
cache_secretsize = 0;
cache_type = 0;
cache_flags = 0;
/*
* Initialize hash table and free list
*/
newalloc = authhashbuckets * sizeof(key_hash[0]);
key_hash = emalloc(newalloc);
memset(key_hash, '\0', newalloc);
memset(&key_listhead, 0, sizeof(symkey));
INIT_DLIST(key_listhead, llink);
#ifdef NTP_DEBUG
atexit(&free_auth_mem);
#endif
}
/*
* free_auth_mem - assist in leak detection by freeing all dynamic
* allocations from this module.
*/
void
free_auth_mem(void)
{
symkey * sk;
#ifdef NTP_DEBUG
symkey_alloc * alloc;
symkey_alloc * next_alloc;
#endif
while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) {
freesymkey(sk);
}
efree(key_hash);
key_hash = NULL;
cache_keyid = 0;
cache_flags = 0;
cache_keyacclist = NULL;
#ifdef NTP_DEBUG
for (alloc = authallocs; alloc != NULL; alloc = next_alloc) {
next_alloc = alloc->link;
efree(alloc->mem);
}
#endif
authfreekeys = NULL;
authnumfreekeys = 0;
}
/*
* auth_moremem - get some more free key structures
*/
void
auth_moremem(
int keycount
)
{
symkey * sk;
int i;
#ifdef NTP_DEBUG
void * base;
symkey_alloc * allocrec;
# define MOREMEM_EXTRA_ALLOC (sizeof(*allocrec))
#else
# define MOREMEM_EXTRA_ALLOC (0)
#endif
i = (keycount > 0)
? keycount
: MEMINC;
sk = eallocarrayxz(i, sizeof(*sk), MOREMEM_EXTRA_ALLOC);
#ifdef NTP_DEBUG
base = sk;
#endif
authnumfreekeys += i;
for (; i > 0; i--, sk++) {
LINK_SLIST(authfreekeys, sk, llink.f);
}
#ifdef NTP_DEBUG
allocrec = (void *)sk;
allocrec->mem = base;
LINK_SLIST(authallocs, allocrec, link);
#endif
}
/*
* auth_prealloc_symkeys
*/
void
auth_prealloc_symkeys(
int keycount
)
{
int allocated;
int additional;
allocated = authnumkeys + authnumfreekeys;
additional = keycount - allocated;
if (additional > 0)
auth_moremem(additional);
auth_resize_hashtable();
}
static u_short
auth_log2(size_t x)
{
/*
** bithack to calculate floor(log2(x))
**
** This assumes
** - (sizeof(size_t) is a power of two
** - CHAR_BITS is a power of two
** - returning zero for arguments <= 0 is OK.
**
** Does only shifts, masks and sums in integer arithmetic in
** log2(CHAR_BIT*sizeof(size_t)) steps. (that is, 5/6 steps for
** 32bit/64bit size_t)
*/
int s;
int r = 0;
size_t m = ~(size_t)0;
for (s = sizeof(size_t) / 2 * CHAR_BIT; s != 0; s >>= 1) {
m <<= s;
if (x & m)
r += s;
else
x <<= s;
}
return (u_short)r;
}
int/*BOOL*/
ipaddr_match_masked(const sockaddr_u *,const sockaddr_u *,
unsigned int mbits);
static void
authcache_flush_id(
keyid_t id
)
{
if (cache_keyid == id) {
cache_keyid = 0;
cache_type = 0;
cache_flags = 0;
cache_secret = NULL;
cache_secretsize = 0;
cache_keyacclist = NULL;
}
}
/*
* auth_resize_hashtable
*
* Size hash table to average 4 or fewer entries per bucket initially,
* within the bounds of at least 4 and no more than 15 bits for the hash
* table index. Populate the hash table.
*/
static void
auth_resize_hashtable(void)
{
u_long totalkeys;
u_short hashbits;
u_short hash;
size_t newalloc;
symkey * sk;
totalkeys = authnumkeys + authnumfreekeys;
hashbits = auth_log2(totalkeys / 4) + 1;
hashbits = max(4, hashbits);
hashbits = min(15, hashbits);
authhashbuckets = 1 << hashbits;
authhashmask = authhashbuckets - 1;
newalloc = authhashbuckets * sizeof(key_hash[0]);
key_hash = erealloc(key_hash, newalloc);
memset(key_hash, '\0', newalloc);
ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
hash = KEYHASH(sk->keyid);
LINK_SLIST(key_hash[hash], sk, hlink);
ITER_DLIST_END()
}
/*
* allocsymkey - common code to allocate and link in symkey
*
* secret must be allocated with a free-compatible allocator. It is
* owned by the referring symkey structure, and will be free()d by
* freesymkey().
*/
static void
allocsymkey(
keyid_t id,
u_short flags,
u_short type,
u_long lifetime,
size_t secretsize,
u_char * secret,
KeyAccT * ka
)
{
symkey * sk;
symkey ** bucket;
bucket = &key_hash[KEYHASH(id)];
if (authnumfreekeys < 1)
auth_moremem(-1);
UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f);
DEBUG_ENSURE(sk != NULL);
sk->keyid = id;
sk->flags = flags;
sk->type = type;
sk->secretsize = secretsize;
sk->secret = secret;
sk->keyacclist = ka;
sk->lifetime = lifetime;
LINK_SLIST(*bucket, sk, hlink);
LINK_TAIL_DLIST(key_listhead, sk, llink);
authnumfreekeys--;
authnumkeys++;
}
/*
* freesymkey - common code to remove a symkey and recycle its entry.
*/
static void
freesymkey(
symkey * sk
)
{
symkey ** bucket;
symkey * unlinked;
if (NULL == sk)
return;
authcache_flush_id(sk->keyid);
keyacc_all_free(sk->keyacclist);
bucket = &key_hash[KEYHASH(sk->keyid)];
if (sk->secret != NULL) {
memset(sk->secret, '\0', sk->secretsize);
efree((void *)sk->secret);
}
UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey);
DEBUG_ENSURE(sk == unlinked);
UNLINK_DLIST(sk, llink);
memset((char *)sk + offsetof(symkey, symkey_payload), '\0',
sizeof(*sk) - offsetof(symkey, symkey_payload));
LINK_SLIST(authfreekeys, sk, llink.f);
authnumkeys--;
authnumfreekeys++;
}
/*
* auth_findkey - find a key in the hash table
*/
struct savekey *
auth_findkey(
keyid_t id
)
{
symkey * sk;
for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink)
if (id == sk->keyid)
return sk;
return NULL;
}
/*
* auth_havekey - return TRUE if the key id is zero or known. The
* key needs not to be trusted.
*/
int
auth_havekey(
keyid_t id
)
{
return
(0 == id) ||
(cache_keyid == id) ||
(NULL != auth_findkey(id));
}
/*
* authhavekey - return TRUE and cache the key, if zero or both known
* and trusted.
*/
int
authhavekey(
keyid_t id
)
{
symkey * sk;
authkeylookups++;
if (0 == id || cache_keyid == id)
return !!(KEY_TRUSTED & cache_flags);
/*
* Search the bin for the key. If not found, or found but the key
* type is zero, somebody marked it trusted without specifying a
* key or key type. In this case consider the key missing.
*/
authkeyuncached++;
sk = auth_findkey(id);
if ((sk == NULL) || (sk->type == 0)) {
authkeynotfound++;
return FALSE;
}
/*
* If the key is not trusted, the key is not considered found.
*/
if ( ! (KEY_TRUSTED & sk->flags)) {
authnokey++;
return FALSE;
}
/*
* The key is found and trusted. Initialize the key cache.
*/
cache_keyid = sk->keyid;
cache_type = sk->type;
cache_flags = sk->flags;
cache_secret = sk->secret;
cache_secretsize = sk->secretsize;
cache_keyacclist = sk->keyacclist;
return TRUE;
}
/*
* authtrust - declare a key to be trusted/untrusted
*/
void
authtrust(
keyid_t id,
u_long trust
)
{
symkey * sk;
u_long lifetime;
/*
* Search bin for key; if it does not exist and is untrusted,
* forget it.
*/
sk = auth_findkey(id);
if (!trust && sk == NULL)
return;
/*
* There are two conditions remaining. Either it does not
* exist and is to be trusted or it does exist and is or is
* not to be trusted.
*/
if (sk != NULL) {
/*
* Key exists. If it is to be trusted, say so and update
* its lifetime. If no longer trusted, return it to the
* free list. Flush the cache first to be sure there are
* no discrepancies.
*/
authcache_flush_id(id);
if (trust > 0) {
sk->flags |= KEY_TRUSTED;
if (trust > 1)
sk->lifetime = current_time + trust;
else
sk->lifetime = 0;
} else {
freesymkey(sk);
}
return;
}
/*
* keyid is not present, but the is to be trusted. We allocate
* a new key, but do not specify a key type or secret.
*/
if (trust > 1) {
lifetime = current_time + trust;
} else {
lifetime = 0;
}
allocsymkey(id, KEY_TRUSTED, 0, lifetime, 0, NULL, NULL);
}
/*
* authistrusted - determine whether a key is trusted
*/
int
authistrusted(
keyid_t id
)
{
symkey * sk;
if (id == cache_keyid)
return !!(KEY_TRUSTED & cache_flags);
authkeyuncached++;
sk = auth_findkey(id);
if (sk == NULL || !(KEY_TRUSTED & sk->flags)) {
authkeynotfound++;
return FALSE;
}
return TRUE;
}
/*
* authistrustedip - determine if the IP is OK for the keyid
*/
int
authistrustedip(
keyid_t keyno,
sockaddr_u * sau
)
{
symkey * sk;
if (keyno == cache_keyid) {
return (KEY_TRUSTED & cache_flags) &&
keyacc_contains(cache_keyacclist, sau, TRUE);
}
if (NULL != (sk = auth_findkey(keyno))) {
authkeyuncached++;
return (KEY_TRUSTED & sk->flags) &&
keyacc_contains(sk->keyacclist, sau, TRUE);
}
authkeynotfound++;
return FALSE;
}
/* Note: There are two locations below where 'strncpy()' is used. While
* this function is a hazard by itself, it's essential that it is used
* here. Bug 1243 involved that the secret was filled with NUL bytes
* after the first NUL encountered, and 'strlcpy()' simply does NOT have
* this behaviour. So disabling the fix and reverting to the buggy
* behaviour due to compatibility issues MUST also fill with NUL and
* this needs 'strncpy'. Also, the secret is managed as a byte blob of a
* given size, and eventually truncating it and replacing the last byte
* with a NUL would be a bug.
* perlinger@ntp.org 2015-10-10
*/
void
MD5auth_setkey(
keyid_t keyno,
int keytype,
const u_char *key,
size_t secretsize,
KeyAccT *ka
)
{
symkey * sk;
u_char * secret;
DEBUG_ENSURE(keytype <= USHRT_MAX);
DEBUG_ENSURE(secretsize < 4 * 1024);
/*
* See if we already have the key. If so just stick in the
* new value.
*/
sk = auth_findkey(keyno);
if (sk != NULL && keyno == sk->keyid) {
/* TALOS-CAN-0054: make sure we have a new buffer! */
if (NULL != sk->secret) {
memset(sk->secret, 0, sk->secretsize);
efree(sk->secret);
}
sk->secret = emalloc(secretsize + 1);
sk->type = (u_short)keytype;
sk->secretsize = secretsize;
/* make sure access lists don't leak here! */
if (ka != sk->keyacclist) {
keyacc_all_free(sk->keyacclist);
sk->keyacclist = ka;
}
#ifndef DISABLE_BUG1243_FIX
memcpy(sk->secret, key, secretsize);
#else
/* >MUST< use 'strncpy()' here! See above! */
strncpy((char *)sk->secret, (const char *)key,
secretsize);
#endif
authcache_flush_id(keyno);
return;
}
/*
* Need to allocate new structure. Do it.
*/
secret = emalloc(secretsize + 1);
#ifndef DISABLE_BUG1243_FIX
memcpy(secret, key, secretsize);
#else
/* >MUST< use 'strncpy()' here! See above! */
strncpy((char *)secret, (const char *)key, secretsize);
#endif
allocsymkey(keyno, 0, (u_short)keytype, 0,
secretsize, secret, ka);
#ifdef NTP_DEBUG
if (debug >= 4) {
size_t j;
printf("auth_setkey: key %d type %d len %d ", (int)keyno,
keytype, (int)secretsize);
for (j = 0; j < secretsize; j++) {
printf("%02x", secret[j]);
}
printf("\n");
}
#endif
}
/*
* auth_delkeys - delete non-autokey untrusted keys, and clear all info
* except the trusted bit of non-autokey trusted keys, in
* preparation for rereading the keys file.
*/
void
auth_delkeys(void)
{
symkey * sk;
ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
if (sk->keyid > NTP_MAXKEY) { /* autokey */
continue;
}
/*
* Don't lose info as to which keys are trusted. Make
* sure there are no dangling pointers!
*/
if (KEY_TRUSTED & sk->flags) {
if (sk->secret != NULL) {
memset(sk->secret, 0, sk->secretsize);
efree(sk->secret);
sk->secret = NULL; /* TALOS-CAN-0054 */
}
sk->keyacclist = keyacc_all_free(sk->keyacclist);
sk->secretsize = 0;
sk->lifetime = 0;
} else {
freesymkey(sk);
}
ITER_DLIST_END()
}
/*
* auth_agekeys - delete keys whose lifetimes have expired
*/
void
auth_agekeys(void)
{
symkey * sk;
ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
if (sk->lifetime > 0 && current_time > sk->lifetime) {
freesymkey(sk);
authkeyexpired++;
}
ITER_DLIST_END()
DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n",
current_time, authnumkeys, authkeyexpired));
}
/*
* authencrypt - generate message authenticator
*
* Returns length of authenticator field, zero if key not found.
*/
size_t
authencrypt(
keyid_t keyno,
u_int32 * pkt,
size_t length
)
{
/*
* A zero key identifier means the sender has not verified
* the last message was correctly authenticated. The MAC
* consists of a single word with value zero.
*/
authencryptions++;
pkt[length / 4] = htonl(keyno);
if (0 == keyno) {
return 4;
}
if (!authhavekey(keyno)) {
return 0;
}
return MD5authencrypt(cache_type,
cache_secret, cache_secretsize,
pkt, length);
}
/*
* authdecrypt - verify message authenticator
*
* Returns TRUE if authenticator valid, FALSE if invalid or not found.
*/
int
authdecrypt(
keyid_t keyno,
u_int32 * pkt,
size_t length,
size_t size
)
{
/*
* A zero key identifier means the sender has not verified
* the last message was correctly authenticated. For our
* purpose this is an invalid authenticator.
*/
authdecryptions++;
if (0 == keyno || !authhavekey(keyno) || size < 4) {
return FALSE;
}
return MD5authdecrypt(cache_type,
cache_secret, cache_secretsize,
pkt, length, size);
}
@@ -0,0 +1,409 @@
/*
* authreadkeys.c - routines to support the reading of the key file
*/
#include <ipntp_config.h>
#include <stdio.h>
#include <ctype.h>
/*#include "ntpd.h"*/ /* Only for DPRINTF */
/*#include "ntp_fp.h"*/
#include "ntp.h"
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
#include "ntp_keyacc.h"
#include "ntp_mem.h"
#ifdef OPENSSL
#include "openssl/objects.h"
#include "openssl/evp.h"
#endif /* OPENSSL */
/* Forwards */
static char *nexttok (char **);
/*
* nexttok - basic internal tokenizing routine
*/
static char *
nexttok(
char **str
)
{
register char *cp;
char *starttok;
cp = *str;
/*
* Space past white space
*/
while (*cp == ' ' || *cp == '\t')
cp++;
/*
* Save this and space to end of token
*/
starttok = cp;
while (*cp != '\0' && *cp != '\n' && *cp != ' '
&& *cp != '\t' && *cp != '#')
cp++;
/*
* If token length is zero return an error, else set end of
* token to zero and return start.
*/
if (starttok == cp)
return NULL;
if (*cp == ' ' || *cp == '\t')
*cp++ = '\0';
else
*cp = '\0';
*str = cp;
return starttok;
}
/* TALOS-CAN-0055: possibly DoS attack by setting the key file to the
* log file. This is hard to prevent (it would need to check two files
* to be the same on the inode level, which will not work so easily with
* Windows or VMS) but we can avoid the self-amplification loop: We only
* log the first 5 errors, silently ignore the next 10 errors, and give
* up when when we have found more than 15 errors.
*
* This avoids the endless file iteration we will end up with otherwise,
* and also avoids overflowing the log file.
*
* Nevertheless, once this happens, the keys are gone since this would
* require a save/swap strategy that is not easy to apply due to the
* data on global/static level.
*/
static const u_int nerr_loglimit = 5u;
static const u_int nerr_maxlimit = 15;
static void log_maybe(u_int*, const char*, ...) NTP_PRINTF(2, 3);
typedef struct keydata KeyDataT;
struct keydata {
KeyDataT *next; /* queue/stack link */
KeyAccT *keyacclist; /* key access list */
keyid_t keyid; /* stored key ID */
u_short keytype; /* stored key type */
u_short seclen; /* length of secret */
u_char secbuf[1]; /* begin of secret (formal only)*/
};
static void
log_maybe(
u_int *pnerr,
const char *fmt ,
...)
{
va_list ap;
if ((NULL == pnerr) || (++(*pnerr) <= nerr_loglimit)) {
va_start(ap, fmt);
mvsyslog(LOG_ERR, fmt, ap);
va_end(ap);
}
}
static void
free_keydata(
KeyDataT *node
)
{
KeyAccT *kap;
if (node) {
while (node->keyacclist) {
kap = node->keyacclist;
node->keyacclist = kap->next;
efree(kap);
}
/* purge secrets from memory before free()ing it */
memset(node, 0, sizeof(*node) + node->seclen);
efree(node);
}
}
/*
* authreadkeys - (re)read keys from a file.
*/
int
authreadkeys(
const char *file
)
{
FILE *fp;
char *line;
char *token;
keyid_t keyno;
int keytype;
char buf[512]; /* lots of room for line */
u_char keystr[32]; /* Bug 2537 */
size_t len;
size_t j;
u_int nerr;
KeyDataT *list = NULL;
KeyDataT *next = NULL;
/*
* Open file. Complain and return if it can't be opened.
*/
fp = fopen(file, "r");
if (fp == NULL) {
msyslog(LOG_ERR, "authreadkeys: file '%s': %m",
file);
goto onerror;
}
INIT_SSL();
/*
* Now read lines from the file, looking for key entries. Put
* the data into temporary store for later propagation to avoid
* two-pass processing.
*/
nerr = 0;
while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
if (nerr > nerr_maxlimit)
break;
token = nexttok(&line);
if (token == NULL)
continue;
/*
* First is key number. See if it is okay.
*/
keyno = atoi(token);
if (keyno < 1) {
log_maybe(&nerr,
"authreadkeys: cannot change key %s",
token);
continue;
}
if (keyno > NTP_MAXKEY) {
log_maybe(&nerr,
"authreadkeys: key %s > %d reserved for Autokey",
token, NTP_MAXKEY);
continue;
}
/*
* Next is keytype. See if that is all right.
*/
token = nexttok(&line);
if (token == NULL) {
log_maybe(&nerr,
"authreadkeys: no key type for key %d",
(int)keyno);
continue;
}
/* We want to silently ignore keys where we do not
* support the requested digest type. OTOH, we want to
* make sure the file is well-formed. That means we
* have to process the line completely and have to
* finally throw away the result... This is a bit more
* work, but it also results in better error detection.
*/
#ifdef OPENSSL
/*
* The key type is the NID used by the message digest
* algorithm. There are a number of inconsistencies in
* the OpenSSL database. We attempt to discover them
* here and prevent use of inconsistent data later.
*/
keytype = keytype_from_text(token, NULL);
if (keytype == 0) {
log_maybe(NULL,
"authreadkeys: invalid type for key %d",
(int)keyno);
# ifdef ENABLE_CMAC
} else if (NID_cmac != keytype &&
EVP_get_digestbynid(keytype) == NULL) {
log_maybe(NULL,
"authreadkeys: no algorithm for key %d",
(int)keyno);
keytype = 0;
# endif /* ENABLE_CMAC */
}
#else /* !OPENSSL follows */
/*
* The key type is unused, but is required to be 'M' or
* 'm' for compatibility.
*/
if (!(*token == 'M' || *token == 'm')) {
log_maybe(NULL,
"authreadkeys: invalid type for key %d",
(int)keyno);
keytype = 0;
} else {
keytype = KEY_TYPE_MD5;
}
#endif /* !OPENSSL */
/*
* Finally, get key and insert it. If it is longer than 20
* characters, it is a binary string encoded in hex;
* otherwise, it is a text string of printable ASCII
* characters.
*/
token = nexttok(&line);
if (token == NULL) {
log_maybe(&nerr,
"authreadkeys: no key for key %d", (int)keyno);
continue;
}
next = NULL;
len = strlen(token);
if (len <= 20) { /* Bug 2537 */
next = emalloc(sizeof(KeyDataT) + len);
next->keyacclist = NULL;
next->keyid = keyno;
next->keytype = keytype;
next->seclen = len;
memcpy(next->secbuf, token, len);
} else {
static const char hex[] = "0123456789abcdef";
u_char temp;
char *ptr;
size_t jlim;
jlim = min(len, 2 * sizeof(keystr));
for (j = 0; j < jlim; j++) {
ptr = strchr(hex, tolower((unsigned char)token[j]));
if (ptr == NULL)
break; /* abort decoding */
temp = (u_char)(ptr - hex);
if (j & 1)
keystr[j / 2] |= temp;
else
keystr[j / 2] = temp << 4;
}
if (j < jlim) {
log_maybe(&nerr,
"authreadkeys: invalid hex digit for key %d",
(int)keyno);
continue;
}
len = jlim/2; /* hmmmm.... what about odd length?!? */
next = emalloc(sizeof(KeyDataT) + len);
next->keyacclist = NULL;
next->keyid = keyno;
next->keytype = keytype;
next->seclen = len;
memcpy(next->secbuf, keystr, len);
}
token = nexttok(&line);
if (token != NULL) { /* A comma-separated IP access list */
char *tp = token;
while (tp) {
char *i;
char *snp; /* subnet text pointer */
unsigned int snbits;
sockaddr_u addr;
i = strchr(tp, (int)',');
if (i) {
*i = '\0';
}
snp = strchr(tp, (int)'/');
if (snp) {
char *sp;
*snp++ = '\0';
snbits = 0;
sp = snp;
while (*sp != '\0') {
if (!isdigit((unsigned char)*sp))
break;
if (snbits > 1000)
break; /* overflow */
snbits = 10 * snbits + (*sp++ - '0'); /* ascii dependent */
}
if (*sp != '\0') {
log_maybe(&nerr,
"authreadkeys: Invalid character in subnet specification for <%s/%s> in key %d",
sp, snp, keyno);
goto nextip;
}
} else {
snbits = UINT_MAX;
}
if (is_ip_address(tp, AF_UNSPEC, &addr)) {
/* Make sure that snbits is valid for addr */
if ((snbits < UINT_MAX) &&
( (IS_IPV4(&addr) && snbits > 32) ||
(IS_IPV6(&addr) && snbits > 128))) {
log_maybe(NULL,
"authreadkeys: excessive subnet mask <%s/%s> for key %d",
tp, snp, keyno);
}
next->keyacclist = keyacc_new_push(
next->keyacclist, &addr, snbits);
} else {
log_maybe(&nerr,
"authreadkeys: invalid IP address <%s> for key %d",
tp, keyno);
}
nextip:
if (i) {
tp = i + 1;
} else {
tp = 0;
}
}
}
/* check if this has to be weeded out... */
if (0 == keytype) {
free_keydata(next);
next = NULL;
continue;
}
INSIST(NULL != next);
next->next = list;
list = next;
}
fclose(fp);
if (nerr > 0) {
const char * why = "";
if (nerr > nerr_maxlimit)
why = " (emergency break)";
msyslog(LOG_ERR,
"authreadkeys: rejecting file '%s' after %u error(s)%s",
file, nerr, why);
goto onerror;
}
/* first remove old file-based keys */
auth_delkeys();
/* insert the new key material */
while (NULL != (next = list)) {
list = next->next;
MD5auth_setkey(next->keyid, next->keytype,
next->secbuf, next->seclen, next->keyacclist);
next->keyacclist = NULL; /* consumed by MD5auth_setkey */
free_keydata(next);
}
return (1);
onerror:
/* Mop up temporary storage before bailing out. */
while (NULL != (next = list)) {
list = next->next;
free_keydata(next);
}
return (0);
}
@@ -0,0 +1,34 @@
/*
* authusekey - decode a key from ascii and use it
*/
#include <ipntp_config.h>
#include <stdio.h>
#include <ctype.h>
#include "ntp_types.h"
#include "ntp_string.h"
#include "ntp_stdlib.h"
/*
* Types of ascii representations for keys. "Standard" means a 64 bit
* hex number in NBS format, i.e. with the low order bit of each byte
* a parity bit. "NTP" means a 64 bit key in NTP format, with the
* high order bit of each byte a parity bit. "Ascii" means a 1-to-8
* character string whose ascii representation is used as the key.
*/
int
authusekey(
keyid_t keyno,
int keytype,
const u_char *str
)
{
size_t len;
len = strlen((const char *)str);
if (0 == len)
return 0;
MD5auth_setkey(keyno, keytype, str, len, NULL);
return 1;
}
@@ -0,0 +1,38 @@
/*
* buftvtots - pull a Unix-format (struct timeval) time stamp out of
* an octet stream and convert it to a l_fp time stamp.
* This is useful when using the clock line discipline.
*/
#ifdef HAVE_CONFIG_H
#include "ipntp_config.h"
#endif
#include "ntp_fp.h"
#include "ntp_string.h"
#include "timevalops.h"
#ifndef SYS_WINNT
int
buftvtots(
const char *bufp,
l_fp *ts
)
{
struct timeval tv;
/*
* copy to adhere to alignment restrictions
*/
memcpy(&tv, bufp, sizeof(tv));
/*
* and use it
*/
if (tv.tv_usec > MICROSECONDS - 1)
return FALSE;
*ts = tval_stamp_to_lfp(tv);
return TRUE;
}
#endif /* !SYS_WINNT */
@@ -0,0 +1,41 @@
/*
* caljulian - determine the Julian date from an NTP time.
*
* (Note: since we use the GREGORIAN calendar, this should be renamed to
* 'calgregorian' eventually...)
*/
#include <ipntp_config.h>
#include <sys/types.h>
#include "ntp_types.h"
#include "ntp_calendar.h"
#if !(defined(ISC_CHECK_ALL) || defined(ISC_CHECK_NONE) || \
defined(ISC_CHECK_ENSURE) || defined(ISC_CHECK_INSIST) || \
defined(ISC_CHECK_INVARIANT))
# define ISC_CHECK_ALL
#endif
#include "ntp_assert.h"
void
caljulian(
uint32_t ntp,
struct calendar * jt
)
{
vint64 vlong;
ntpcal_split split;
INSIST(NULL != jt);
/*
* Unfold ntp time around current time into NTP domain. Split
* into days and seconds, shift days into CE domain and
* process the parts.
*/
vlong = ntpcal_ntp_to_ntp(ntp, NULL);
split = ntpcal_daysplit(&vlong);
ntpcal_daysplit_to_date(jt, &split, DAY_NTP_STARTS);
}
@@ -0,0 +1,68 @@
/*
* caltontp - convert a date to an NTP time
*/
#include <ipntp_config.h>
#include <sys/types.h>
#include "ntp_types.h"
#include "ntp_calendar.h"
#include "ntp_stdlib.h"
#include "ntp_assert.h"
#include "ntp_unixtime.h"
/*
* Juergen Perlinger, 2008-11-12
* Add support for full calendar calculatios. If the day-of-year is provided
* (that is, not zero) it will be used instead of month and day-of-month;
* otherwise a full turn through the calendar calculations will be taken.
*
* I know that Harlan Stenn likes to see assertions in production code, and I
* agree there, but it would be a tricky thing here. The algorithm is quite
* capable of producing sensible answers even to seemingly weird inputs: the
* date <any year here>-03-00, the 0.th March of the year, will be automtically
* treated as the last day of February, no matter whether the year is a leap
* year or not. So adding constraints is merely for the benefit of the callers,
* because the only thing we can check for consistency is our input, produced
* by somebody else.
*
* BTW: A total roundtrip using 'caljulian' would be a quite shaky thing:
* Because of the truncation of the NTP time stamp to 32 bits and the epoch
* unfolding around the current time done by 'caljulian' the roundtrip does
* *not* necessarily reproduce the input, especially if the time spec is more
* than 68 years off from the current time...
*/
uint32_t
caltontp(
const struct calendar *jt
)
{
int32_t eraday; /* CE Rata Die number */
vint64 ntptime;/* resulting NTP time */
REQUIRE(jt != NULL);
REQUIRE(jt->month <= 13); /* permit month 0..13! */
REQUIRE(jt->monthday <= 32);
REQUIRE(jt->yearday <= 366);
REQUIRE(jt->hour <= 24);
REQUIRE(jt->minute <= MINSPERHR);
REQUIRE(jt->second <= SECSPERMIN);
/*
* First convert the date to he corresponding RataDie
* number. If yearday is not zero, assume that it contains a
* useable value and avoid all calculations involving month
* and day-of-month. Do a full evaluation otherwise.
*/
if (jt->yearday)
eraday = ntpcal_year_to_ystart(jt->year)
+ jt->yearday - 1;
else
eraday = ntpcal_date_to_rd(jt);
ntptime = ntpcal_dayjoin(eraday - DAY_NTP_STARTS,
ntpcal_etime_to_seconds(jt->hour, jt->minute,
jt->second));
return ntptime.d_s.lo;
}
@@ -0,0 +1,88 @@
/*
* calyearstart - determine the NTP time at midnight of January 1 in
* the year of the given date.
*/
#include <ipntp_config.h>
#include <sys/types.h>
#include "ntp_types.h"
#include "ntp_calendar.h"
#include "ntp_stdlib.h"
#include "ntp_assert.h"
/*
* Juergen Perlinger, 2010-05-02
*
* Redone in terms of the calendar functions. It's rather simple:
* - expand the NTP time stamp
* - split into days and seconds since midnight, dropping the partial day
* - get full number of days before year start in NTP epoch
* - convert to seconds, truncated to 32 bits.
*/
u_int32
calyearstart(u_int32 ntptime, const time_t *pivot)
{
u_int32 ndays; /* elapsed days since NTP starts */
vint64 vlong;
ntpcal_split split;
vlong = ntpcal_ntp_to_ntp(ntptime, pivot);
split = ntpcal_daysplit(&vlong);
ndays = ntpcal_rd_to_ystart(split.hi + DAY_NTP_STARTS)
- DAY_NTP_STARTS;
return (u_int32)(ndays * SECSPERDAY);
}
/*
* calmonthstart - get NTP time at midnight of the first day of the
* current month.
*/
u_int32
calmonthstart(u_int32 ntptime, const time_t *pivot)
{
u_int32 ndays; /* elapsed days since NTP starts */
vint64 vlong;
ntpcal_split split;
vlong = ntpcal_ntp_to_ntp(ntptime, pivot);
split = ntpcal_daysplit(&vlong);
ndays = ntpcal_rd_to_mstart(split.hi + DAY_NTP_STARTS)
- DAY_NTP_STARTS;
return (u_int32)(ndays * SECSPERDAY);
}
/*
* calweekstart - get NTP time at midnight of the last Monday on or
* before the current date.
*/
u_int32
calweekstart(u_int32 ntptime, const time_t *pivot)
{
u_int32 ndays; /* elapsed days since NTP starts */
vint64 vlong;
ntpcal_split split;
vlong = ntpcal_ntp_to_ntp(ntptime, pivot);
split = ntpcal_daysplit(&vlong);
ndays = ntpcal_weekday_le(split.hi + DAY_NTP_STARTS, CAL_MONDAY)
- DAY_NTP_STARTS;
return (u_int32)(ndays * SECSPERDAY);
}
/*
* caldaystart - get NTP time at midnight of the current day.
*/
u_int32
caldaystart(u_int32 ntptime, const time_t *pivot)
{
vint64 vlong;
ntpcal_split split;
vlong = ntpcal_ntp_to_ntp(ntptime, pivot);
split = ntpcal_daysplit(&vlong);
return ntptime - split.lo;
}
@@ -0,0 +1,149 @@
/*
* clocktime - compute the NTP date from a day of year, hour, minute
* and second.
*/
#include <ipntp_config.h>
#include "ntp_fp.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
#include "ntp_calendar.h"
/*
* We check that the time be within CLOSETIME seconds of the receive
* time stamp. This is about 4 hours, which hopefully should be wide
* enough to collect most data, while close enough to keep things from
* getting confused.
*/
#define CLOSETIME (4u*60u*60u)
/*
* Since we try to match years, the result of a full search will not
* change when we are already less than a half year from the receive
* time stamp. Since the length of a year is variable we use a
* slightly narrower limit; this might require a full evaluation near
* the edge, but will make sure we always get the correct result.
*/
#define NEARTIME (182u * SECSPERDAY)
/*
* local calendar helpers
*/
static int32 ntp_to_year(u_int32);
static u_int32 year_to_ntp(int32);
/*
* Take a time spec given as day-of-year, hour, minute and second as
* well as a GMT offset in hours and convert it to a NTP time stamp in
* '*ts_ui'. The value will be in the range (rec_ui-0.5yrs) to
* (rec_ui+0.5yrs). A hint for the current start-of-year will be
* read from '*yearstart'.
*
* On return '*ts_ui' will always the best matching solution, and
* '*yearstart' will receive the associated start-of-year.
*
* The function will tell if the result in 'ts_ui' is in CLOSETIME
* (+/-4hrs) around the receive time by returning a non-zero value.
*
* Note: The function puts no constraints on the value ranges for the
* time specification, but evaluates the effective seconds in
* 32-bit arithmetic.
*/
int
clocktime(
int yday , /* day-of-year */
int hour , /* hour of day */
int minute , /* minute of hour */
int second , /* second of minute */
int tzoff , /* hours west of GMT */
u_int32 rec_ui , /* pivot value */
u_long *yearstart, /* cached start-of-year, should be fixed to u_int32 */
u_int32 *ts_ui ) /* effective time stamp */
{
u_int32 ystt[3]; /* year start */
u_int32 test[3]; /* result time stamp */
u_int32 diff[3]; /* abs difference to receive */
int32 y, tmp, idx, min;
/*
* Compute the offset into the year in seconds. Note that
* this could come out to be a negative number.
*/
tmp = ((int32)second +
SECSPERMIN * ((int32)minute +
MINSPERHR * ((int32)hour + (int32)tzoff +
HRSPERDAY * ((int32)yday - 1))));
/*
* Based on the cached year start, do a first attempt. Be
* happy and return if this gets us better than NEARTIME to
* the receive time stamp. Do this only if the cached year
* start is not zero, which will not happen after 1900 for the
* next few thousand years.
*/
if (*yearstart) {
/* -- get time stamp of potential solution */
test[0] = (u_int32)(*yearstart) + tmp;
/* -- calc absolute difference to receive time */
diff[0] = test[0] - rec_ui;
if (diff[0] >= 0x80000000u)
diff[0] = ~diff[0] + 1;
/* -- can't get closer if diff < NEARTIME */
if (diff[0] < NEARTIME) {
*ts_ui = test[0];
return diff[0] < CLOSETIME;
}
}
/*
* Now the dance begins. Based on the receive time stamp and
* the seconds offset in 'tmp', we make an educated guess
* about the year to start with. This takes us on the spot
* with a fuzz of +/-1 year.
*
* We calculate the effective timestamps for the three years
* around the guess and select the entry with the minimum
* absolute difference to the receive time stamp.
*/
y = ntp_to_year(rec_ui - tmp);
for (idx = 0; idx < 3; idx++) {
/* -- get year start of potential solution */
ystt[idx] = year_to_ntp(y + idx - 1);
/* -- get time stamp of potential solution */
test[idx] = ystt[idx] + tmp;
/* -- calc absolute difference to receive time */
diff[idx] = test[idx] - rec_ui;
if (diff[idx] >= 0x80000000u)
diff[idx] = ~diff[idx] + 1;
}
/* -*- assume current year fits best, then search best fit */
for (min = 1, idx = 0; idx < 3; idx++)
if (diff[idx] < diff[min])
min = idx;
/* -*- store results and update year start */
*ts_ui = test[min];
*yearstart = ystt[min];
/* -*- tell if we could get into CLOSETIME*/
return diff[min] < CLOSETIME;
}
static int32
ntp_to_year(
u_int32 ntp)
{
vint64 t;
ntpcal_split s;
t = ntpcal_ntp_to_ntp(ntp, NULL);
s = ntpcal_daysplit(&t);
s = ntpcal_split_eradays(s.hi + DAY_NTP_STARTS - 1, NULL);
return s.hi + 1;
}
static u_int32
year_to_ntp(
int32 year)
{
u_int32 days;
days = ntpcal_days_in_years(year-1) - DAY_NTP_STARTS + 1;
return days * SECSPERDAY;
}
@@ -0,0 +1,123 @@
/*
* Data for pretty printing clock types
*/
#include <ipntp_config.h>
#include <stdio.h>
#include "ntp_fp.h"
#include "ntp.h"
#include "lib_strbuf.h"
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
struct clktype clktypes[] = {
{ REFCLK_NONE, "unspecified type (0)",
"UNKNOWN" },
{ REFCLK_LOCALCLOCK, "Undisciplined local clock (1)",
"LOCAL" },
{ REFCLK_GPS_TRAK, "TRAK 8810 GPS Receiver (2)",
"GPS_TRAK" },
{ REFCLK_WWV_PST, "PSTI/Traconex WWV/WWVH Receiver (3)",
"WWV_PST" },
{ REFCLK_SPECTRACOM, "Spectracom (generic) Receivers (4)",
"SPECTRACOM" },
{ REFCLK_TRUETIME, "TrueTime (generic) Receivers (5)",
"TRUETIME" },
{ REFCLK_IRIG_AUDIO, "IRIG Audio Decoder (6)",
"IRIG_AUDIO" },
{ REFCLK_CHU_AUDIO, "CHU Audio Demodulator/Decoder (7)",
"CHU_AUDIO" },
{ REFCLK_PARSE, "Generic reference clock driver (8)",
"GENERIC" },
{ REFCLK_GPS_MX4200, "Magnavox MX4200 GPS Receiver (9)",
"GPS_MX4200" },
{ REFCLK_GPS_AS2201, "Austron 2201A GPS Receiver (10)",
"GPS_AS2201" },
{ REFCLK_GPS_ARBITER, "Arbiter 1088A/B GPS Receiver (11)",
"GPS_ARBITER" },
{ REFCLK_IRIG_TPRO, "KSI/Odetics TPRO/S IRIG Interface (12)",
"IRIG_TPRO" },
{ REFCLK_ATOM_LEITCH, "Leitch CSD 5300 Master Clock Controller (13)",
"ATOM_LEITCH" },
{ REFCLK_MSF_EES, "EES M201 MSF Receiver (14)",
"MSF_EES" },
{ REFCLK_NONE, "not used (15)",
"NOT_USED" },
{ REFCLK_IRIG_BANCOMM, "Bancomm GPS/IRIG Receiver (16)",
"GPS_BANC" },
{ REFCLK_GPS_DATUM, "Datum Precision Time System (17)",
"GPS_DATUM" },
{ REFCLK_ACTS, "Automated Computer Time Service (18)",
"ACTS_MODEM" },
{ REFCLK_WWV_HEATH, "Heath WWV/WWVH Receiver (19)",
"WWV_HEATH" },
{ REFCLK_GPS_NMEA, "Generic NMEA GPS Receiver (20)",
"GPS_NMEA" },
{ REFCLK_GPS_VME, "TrueTime GPS-VME Interface (21)",
"GPS_VME" },
{ REFCLK_ATOM_PPS, "PPS Clock Discipline (22)",
"PPS" },
{ REFCLK_NONE, "not used (23)",
"NOT_USED" },
{ REFCLK_NONE, "not used (24)",
"NOT_USED" },
{ REFCLK_NONE, "not used (25)",
"NOT_USED" },
{ REFCLK_GPS_HP, "HP 58503A GPS Time & Frequency Receiver (26)",
"GPS_HP" },
{ REFCLK_ARCRON_MSF, "ARCRON MSF (and DCF77) Receiver (27)",
"MSF_ARCRON" },
{ REFCLK_SHM, "Clock attached thru shared Memory (28)",
"SHM" },
{ REFCLK_PALISADE, "Trimble Navigation Palisade GPS (29)",
"GPS_PALISADE" },
{ REFCLK_ONCORE, "Motorola UT Oncore GPS (30)",
"GPS_ONCORE" },
{ REFCLK_GPS_JUPITER, "Rockwell Jupiter GPS (31)",
"GPS_JUPITER" },
{ REFCLK_CHRONOLOG, "Chrono-log K (32)",
"CHRONOLOG" },
{ REFCLK_DUMBCLOCK, "Dumb generic hh:mm:ss local clock (33)",
"DUMBCLOCK" },
{ REFCLK_ULINK, "Ultralink M320 WWVB receiver (34)",
"ULINK_M320"},
{ REFCLK_PCF, "Conrad parallel port radio clock (35)",
"PCF"},
{ REFCLK_WWV_AUDIO, "WWV/H Audio Demodulator/Decoder (36)",
"WWV_AUDIO"},
{ REFCLK_FG, "Forum Graphic GPS Dating Station (37)",
"GPS_FG"},
{ REFCLK_HOPF_SERIAL, "hopf Elektronic serial line receiver (38)",
"HOPF_S"},
{ REFCLK_HOPF_PCI, "hopf Elektronic PCI receiver (39)",
"HOPF_P"},
{ REFCLK_JJY, "JJY receiver (40)",
"JJY"},
{ REFCLK_TT560, "TrueTime 560 IRIG-B decoder (41)",
"TT_IRIG"},
{ REFCLK_ZYFER, "Zyfer GPStarplus receiver (42)",
"GPS_ZYFER" },
{ REFCLK_RIPENCC, "RIPE NCC Trimble driver (43)",
"GPS_RIPENCC" },
{ REFCLK_NEOCLOCK4X, "NeoClock4X DCF77 / TDF receiver (44)",
"NEOCLK4X"},
{ REFCLK_TSYNCPCI, "Spectracom TSYNC PCI timing board (45)",
"PCI_TSYNC"},
{ REFCLK_GPSDJSON, "GPSD JSON socket (46)",
"GPSD_JSON"},
{ -1, "", "" }
};
const char *
clockname(
int num
)
{
register struct clktype *clk;
for (clk = clktypes; clk->code != -1; clk++) {
if (num == clk->code)
return (clk->abbrev);
}
return (NULL);
}
@@ -0,0 +1,164 @@
/*
* decodenetnum - return a net number (this is crude, but careful)
*/
#include <ipntp_config.h>
#include <sys/types.h>
#include <ctype.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include "ntp.h"
#include "ntp_stdlib.h"
/* If the given string position points to a decimal digit, parse the
* number. If this is not possible, or the parsing did not consume the
* whole string, or if the result exceeds the maximum value, return the
* default value.
*/
static unsigned long
_num_or_dflt(
char * sval,
unsigned long maxval,
unsigned long defval
)
{
char * ep;
unsigned long num;
if (!(sval && isdigit(*(unsigned char*)sval)))
return defval;
num = strtoul(sval, &ep, 10);
if (!*ep && num <= maxval)
return num;
return defval;
}
/* If the given string position is not NULL and does not point to the
* terminator, replace the character with NUL and advance the pointer.
* Return the resulting position.
*/
static inline char*
_chop(
char * sp)
{
if (sp && *sp)
*sp++ = '\0';
return sp;
}
/* If the given string position points to the given char, advance the
* pointer and return the result. Otherwise, return NULL.
*/
static inline char*
_skip(
char * sp,
int ch)
{
if (sp && *(unsigned char*)sp == ch)
return (sp + 1);
return NULL;
}
/*
* decodenetnum convert text IP address and port to sockaddr_u
*
* Returns FALSE (->0) for failure, TRUE (->1) for success.
*/
int
decodenetnum(
const char *num,
sockaddr_u *net
)
{
/* Building a parser is more fun in Haskell, but here we go...
*
* This works through 'inet_pton()' taking the brunt of the
* work, after some string manipulations to split off URI
* brackets, ports and scope identifiers. The heuristics are
* simple but must hold for all _VALID_ addresses. inet_pton()
* will croak on bad ones later, but replicating the whole
* parser logic to detect errors is wasteful.
*/
sockaddr_u netnum;
char buf[64]; /* working copy of input */
char *haddr=buf;
unsigned int port=NTP_PORT, scope=0;
unsigned short afam=AF_UNSPEC;
/* copy input to working buffer with length check */
if (strlcpy(buf, num, sizeof(buf)) >= sizeof(buf))
return FALSE;
/* Identify address family and possibly the port, if given. If
* this results in AF_UNSPEC, we will fail in the next step.
*/
if (*haddr == '[') {
char * endp = strchr(++haddr, ']');
if (endp) {
port = _num_or_dflt(_skip(_chop(endp), ':'),
0xFFFFu, port);
afam = strchr(haddr, ':') ? AF_INET6 : AF_INET;
}
} else {
char *col = strchr(haddr, ':');
char *dot = strchr(haddr, '.');
if (col == dot) {
/* no dot, no colon: bad! */
afam = AF_UNSPEC;
} else if (!col) {
/* no colon, only dot: IPv4! */
afam = AF_INET;
} else if (!dot || col < dot) {
/* no dot or 1st colon before 1st dot: IPv6! */
afam = AF_INET6;
} else {
/* 1st dot before 1st colon: must be IPv4 with port */
afam = AF_INET;
port = _num_or_dflt(_chop(col), 0xFFFFu, port);
}
}
/* Since we don't know about additional members in the address
* structures, we wipe the result buffer thoroughly:
*/
memset(&netnum, 0, sizeof(netnum));
/* For AF_INET6, evaluate and remove any scope suffix. Have
* inet_pton() do the real work for AF_INET and AF_INET6, bail
* out otherwise:
*/
switch (afam) {
case AF_INET:
if (inet_pton(afam, haddr, &netnum.sa4.sin_addr) <= 0)
return FALSE;
netnum.sa4.sin_port = htons((unsigned short)port);
break;
case AF_INET6:
scope = _num_or_dflt(_chop(strchr(haddr, '%')), 0xFFFFFFFFu, scope);
if (inet_pton(afam, haddr, &netnum.sa6.sin6_addr) <= 0)
return FALSE;
netnum.sa6.sin6_port = htons((unsigned short)port);
netnum.sa6.sin6_scope_id = scope;
break;
case AF_UNSPEC:
default:
return FALSE;
}
/* Collect the remaining pieces and feed the output, which was
* not touched so far:
*/
netnum.sa.sa_family = afam;
memcpy(net, &netnum, sizeof(netnum));
return TRUE;
}
@@ -0,0 +1,161 @@
/*
* dofptoa - do the grunge work to convert an fp number to ascii
*/
#include <ipntp_config.h>
#include <stdio.h>
#include "ntp_fp.h"
#include "lib_strbuf.h"
#include "ntp_string.h"
#include "ntp_stdlib.h"
char *
dofptoa(
u_fp fpv,
char sign,
short ndec,
int msec
)
{
register u_char *cp, *cpend;
register u_long val;
register short dec;
u_char cbuf[12];
u_char *cpdec;
char *buf;
char *bp;
/*
* Get a string buffer before starting
*/
LIB_GETBUF(buf);
/*
* Zero out the buffer
*/
ZERO(cbuf);
/*
* Set the pointers to point at the first
* decimal place. Get a local copy of the value.
*/
cp = cpend = &cbuf[5];
val = fpv;
/*
* If we have to, decode the integral part
*/
if (!(val & 0xffff0000))
cp--;
else {
register u_short sv = (u_short)(val >> 16);
register u_short tmp;
register u_short ten = 10;
do {
tmp = sv;
sv = (u_short) (sv/ten);
*(--cp) = (u_char)(tmp - ((sv<<3) + (sv<<1)));
} while (sv != 0);
}
/*
* Figure out how much of the fraction to do
*/
if (msec) {
dec = (short)(ndec + 3);
if (dec < 3)
dec = 3;
cpdec = &cbuf[8];
} else {
dec = ndec;
cpdec = cpend;
}
if (dec > 6)
dec = 6;
if (dec > 0) {
do {
val &= 0xffff;
val = (val << 3) + (val << 1);
*cpend++ = (u_char)(val >> 16);
} while (--dec > 0);
}
if (val & 0x8000) {
register u_char *tp;
/*
* Round it. Ick.
*/
tp = cpend;
--tp;
*tp = (u_char)(*tp + 1);
while (*tp >= 10) {
*tp = 0;
--tp;
*tp = (u_char)(*tp + 1);
}
}
/*
* Remove leading zeroes if necessary
*/
while (cp < (cpdec -1) && *cp == 0)
cp++;
/*
* Copy it into the buffer, asciizing as we go.
*/
bp = buf;
if (sign)
*bp++ = sign;
while (cp < cpend) {
if (cp == cpdec)
*bp++ = '.';
*bp++ = (char)(*cp++ + '0');
}
*bp = '\0';
return buf;
}
char *
fptoa(
s_fp fpv,
short ndec
)
{
u_fp plusfp;
int neg;
neg = (fpv < 0);
if (neg) {
plusfp = (u_fp)(-fpv);
} else {
plusfp = (u_fp)fpv;
}
return dofptoa(plusfp, (neg?'-':0), ndec, FALSE);
}
char *
fptoms(
s_fp fpv,
short ndec
)
{
u_fp plusfp;
int neg;
neg = (fpv < 0);
if (neg) {
plusfp = (u_fp)(-fpv);
} else {
plusfp = (u_fp)fpv;
}
return dofptoa(plusfp, (neg?'-':0), ndec, TRUE);
}
@@ -0,0 +1,175 @@
/*
* dolfptoa - do the grunge work of converting an l_fp number to decimal
*/
#include <ipntp_config.h>
#include <stdio.h>
#include "ntp_fp.h"
#include "lib_strbuf.h"
#include "ntp_string.h"
#include "ntp_stdlib.h"
char *
dolfptoa(
u_int32 fpi,
u_int32 fpv,
char sign,
short ndec,
int msec
)
{
u_char *cp, *cpend, *cpdec;
int dec;
u_char cbuf[24];
char *buf, *bp;
/*
* Get a string buffer before starting
*/
LIB_GETBUF(buf);
/*
* Zero the character buffer
*/
ZERO(cbuf);
/*
* Work on the integral part. This should work reasonable on
* all machines with 32 bit arithmetic. Please note that 32 bits
* can *always* be represented with at most 10 decimal digits,
* including a possible rounding from the fractional part.
*/
cp = cpend = cpdec = &cbuf[10];
for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) {
/* can add another digit */
u_int32 digit;
digit = fpi;
fpi /= 10U;
digit -= (fpi << 3) + (fpi << 1); /* i*10 */
*--cp = (u_char)digit;
}
/*
* Done that, now deal with the problem of the fraction. First
* determine the number of decimal places.
*/
dec = ndec;
if (dec < 0)
dec = 0;
if (msec) {
dec += 3;
cpdec += 3;
}
if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf))
dec = (int)(sizeof(cbuf) - (cpend - cbuf));
/*
* If there's a fraction to deal with, do so.
*/
for (/*NOP*/; dec > 0 && fpv != 0; dec--) {
u_int32 digit, tmph, tmpl;
/*
* The scheme here is to multiply the fraction
* (0.1234...) by ten. This moves a junk of BCD into
* the units part. record that and iterate.
* multiply by shift/add in two dwords.
*/
digit = 0;
M_LSHIFT(digit, fpv);
tmph = digit;
tmpl = fpv;
M_LSHIFT(digit, fpv);
M_LSHIFT(digit, fpv);
M_ADD(digit, fpv, tmph, tmpl);
*cpend++ = (u_char)digit;
}
/* decide whether to round or simply extend by zeros */
if (dec > 0) {
/* only '0' digits left -- just reposition end */
cpend += dec;
} else {
/* some bits remain in 'fpv'; do round */
u_char *tp = cpend;
int carry = ((fpv & 0x80000000) != 0);
for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) {
--tp;
*tp = (u_char)(*tp + 1);
if (*tp == 10)
*tp = 0;
else
carry = FALSE;
}
if (tp < cp) /* rounding from 999 to 1000 or similiar? */
cp = tp;
}
/*
* We've now got the fraction in cbuf[], with cp pointing at
* the first character, cpend pointing past the last, and
* cpdec pointing at the first character past the decimal.
* Remove leading zeros, then format the number into the
* buffer.
*/
while (cp < cpdec && *cp == 0)
cp++;
if (cp >= cpdec)
cp = cpdec - 1;
bp = buf;
if (sign)
*bp++ = sign;
while (cp < cpend) {
if (cp == cpdec)
*bp++ = '.';
*bp++ = (char)(*cp++) + '0';
}
*bp = '\0';
/*
* Done!
*/
return buf;
}
char *
mfptoa(
u_int32 fpi,
u_int32 fpf,
short ndec
)
{
int isneg;
isneg = M_ISNEG(fpi);
if (isneg) {
M_NEG(fpi, fpf);
}
return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, FALSE);
}
char *
mfptoms(
u_int32 fpi,
u_int32 fpf,
short ndec
)
{
int isneg;
isneg = M_ISNEG(fpi);
if (isneg) {
M_NEG(fpi, fpf);
}
return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, TRUE);
}
@@ -0,0 +1,160 @@
/*
* emalloc - return new memory obtained from the system. Belch if none.
*/
#include <ipntp_config.h>
#include "ntp_types.h"
#include "ntp_malloc.h"
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
extern void ipntp_exit_callback(Ip_pid_t pid);
#ifndef _WRS_CONFIG_LP64
#define SIZE_MAX 0xFFFFFFFFU
#else
#define SIZE_MAX 0xFFFFFFFFFFFFFFFFULL
#endif /* _WRS_CONFIG_LP64 */
/*
* When using the debug MS CRT allocator, each allocation stores the
* callsite __FILE__ and __LINE__, which is then displayed at process
* termination, to track down leaks. We don't want all of our
* allocations to show up as coming from emalloc.c, so we preserve the
* original callsite's source file and line using macros which pass
* __FILE__ and __LINE__ as parameters to these routines.
* Other debug malloc implementations can be used by defining
* EREALLOC_IMPL() as ports/winnt/include/config.h does.
*/
#if 0
void *
ereallocz(
void * ptr,
size_t newsz,
size_t priorsz,
int zero_init
#ifdef EREALLOC_CALLSITE /* ntp_malloc.h */
,
const char * file,
int line
#endif
)
{
char * mem;
size_t allocsz;
if (0 == newsz)
allocsz = 1;
else
allocsz = newsz;
mem = EREALLOC_IMPL(ptr, allocsz, file, line);
if (NULL == mem) {
msyslog_term = TRUE;
#ifndef EREALLOC_CALLSITE
msyslog(LOG_ERR, "fatal out of memory (%lu bytes)",
(u_long)newsz);
#else
msyslog(LOG_ERR,
"fatal out of memory %s line %d (%lu bytes)",
file, line, (u_long)newsz);
#endif
exit(1);
}
if (zero_init && newsz > priorsz)
zero_mem(mem + priorsz, newsz - priorsz);
return mem;
}
#endif
/* oreallocarray.c is licensed under the following:
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
void *
oreallocarrayxz(
void *optr,
size_t nmemb,
size_t size,
size_t extra
#ifdef EREALLOC_CALLSITE /* ntp_malloc.h */
,
const char * file,
int line
#endif
)
{
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
#ifndef EREALLOC_CALLSITE
msyslog(LOG_ERR, "fatal allocation size overflow");
#else
msyslog(LOG_ERR,
"fatal allocation size overflow %s line %d",
file, line);
#endif
ipntp_exit_callback(ipcom_getpid());
}
#ifndef EREALLOC_CALLSITE
return ereallocz(optr, extra + (size * nmemb), 0, TRUE);
#else
return ereallocz(optr, extra + (size * nmemb), 0, TRUE, file, line);
#endif
}
char *
estrdup_impl(
const char * str
#ifdef EREALLOC_CALLSITE
,
const char * file,
int line
#endif
)
{
char * copy;
size_t bytes;
bytes = strlen(str) + 1;
copy = ereallocz(NULL, bytes, 0, FALSE
#ifdef EREALLOC_CALLSITE
, file, line
#endif
);
memcpy(copy, str, bytes);
return copy;
}
#if 0
#ifndef EREALLOC_CALLSITE
void *
emalloc(size_t newsz)
{
return ereallocz(NULL, newsz, 0, FALSE);
}
#endif
#endif
@@ -0,0 +1,74 @@
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#ifdef NEED_HPUX_FINDCONFIG
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <unistd.h>
const char *
FindConfig(
const char *base
)
{
static char result[BUFSIZ];
char hostname[BUFSIZ], *cp;
struct stat sbuf;
struct utsname unamebuf;
/* All keyed by initial target being a directory */
strlcpy(result, base, sizeof(result));
if (stat(result, &sbuf) == 0) {
if (S_ISDIR(sbuf.st_mode)) {
/* First choice is my hostname */
if (gethostname(hostname, BUFSIZ) >= 0) {
snprintf(result, sizeof(result), "%s/%s", base, hostname);
if (stat(result, &sbuf) == 0) {
goto outahere;
} else {
/* Second choice is of form default.835 */
(void) uname(&unamebuf);
if (strncmp(unamebuf.machine, "9000/", 5) == 0)
cp = unamebuf.machine + 5;
else
cp = unamebuf.machine;
snprintf(result, sizeof(result), "%s/default.%s", base, cp);
if (stat(result, &sbuf) == 0) {
goto outahere;
} else {
/* Last choice is just default */
snprintf(result, sizeof(result), "%s/default", base);
if (stat(result, &sbuf) == 0) {
goto outahere;
} else {
strlcpy(result,
"/not/found",
sizeof(result));
}
}
}
}
}
}
outahere:
return(result);
}
#else
#include "ntp_stdlib.h"
const char *
FindConfig(
const char *base
)
{
return base;
}
#endif
@@ -0,0 +1,42 @@
/*
* hextoint - convert an ascii string in hex to an unsigned
* long, with error checking
*/
#include <ipntp_config.h>
#include <ctype.h>
#include "ntp_stdlib.h"
int
hextoint(
const char *str,
u_long *pu
)
{
register u_long u;
register const char *cp;
cp = str;
if (*cp == '\0')
return 0;
u = 0;
while (*cp != '\0') {
if (!isxdigit((unsigned char)*cp))
return 0;
if (u & 0xF0000000)
return 0; /* overflow */
u <<= 4;
if ('0' <= *cp && *cp <= '9')
u += *cp++ - '0';
else if ('a' <= *cp && *cp <= 'f')
u += *cp++ - 'a' + 10;
else if ('A' <= *cp && *cp <= 'F')
u += *cp++ - 'A' + 10;
else
return 0;
}
*pu = u;
return 1;
}
@@ -0,0 +1,70 @@
/*
* hextolfp - convert an ascii hex string to an l_fp number
*/
#include <ipntp_config.h>
#include <stdio.h>
#include <ctype.h>
#include "ntp_fp.h"
#include "ntp_string.h"
#include "ntp_stdlib.h"
int
hextolfp(
const char *str,
l_fp *lfp
)
{
register const char *cp;
register const char *cpstart;
register u_long dec_i;
register u_long dec_f;
char *ind = NULL;
static const char *digits = "0123456789abcdefABCDEF";
dec_i = dec_f = 0;
cp = str;
/*
* We understand numbers of the form:
*
* [spaces]8_hex_digits[.]8_hex_digits[spaces|\n|\0]
*/
while (isspace((unsigned char)*cp))
cp++;
cpstart = cp;
while (*cp != '\0' && (cp - cpstart) < 8 &&
(ind = strchr(digits, *cp)) != NULL) {
dec_i = dec_i << 4; /* multiply by 16 */
dec_i += ((ind - digits) > 15)
? (u_long)(ind - digits - 6)
: (u_long)(ind - digits);
cp++;
}
if ((cp - cpstart) < 8 || ind == NULL)
return 0;
if (*cp == '.')
cp++;
cpstart = cp;
while (*cp != '\0' && (cp - cpstart) < 8 &&
(ind = strchr(digits, *cp)) != NULL) {
dec_f = dec_f << 4; /* multiply by 16 */
dec_f += ((ind - digits) > 15)
? (u_long)(ind - digits - 6)
: (u_long)(ind - digits);
cp++;
}
if ((cp - cpstart) < 8 || ind == NULL)
return 0;
if (*cp != '\0' && !isspace((unsigned char)*cp))
return 0;
lfp->l_ui = dec_i;
lfp->l_uf = dec_f;
return 1;
}
@@ -0,0 +1,60 @@
/*
* humandate.c - convert an NTP (or the current) time to something readable
*/
#include <ntp_config.h>
#include <stdio.h>
#include "ntp_fp.h"
#include "ntp_unixtime.h" /* includes <sys/time.h> and <time.h> */
#include "lib_strbuf.h"
#include "ntp_stdlib.h"
/* This is used in msyslog.c; we don't want to clutter up the log with
the year and day of the week, etc.; just the minimal date and time. */
const char *
humanlogtime(void)
{
char * bp;
time_t cursec;
struct tm * tm;
cursec = time(NULL);
tm = localtime(&cursec);
if (!tm)
return "-- --- --:--:--";
LIB_GETBUF(bp);
snprintf(bp, LIB_BUFLENGTH, "%2d %s %02d:%02d:%02d",
tm->tm_mday, months[tm->tm_mon],
tm->tm_hour, tm->tm_min, tm->tm_sec);
return bp;
}
/*
* humantime() -- like humanlogtime() but without date, and with the
* time to display given as an argument.
*/
const char *
humantime(
time_t cursec
)
{
char * bp;
struct tm * tm;
tm = localtime(&cursec);
if (!tm)
return "--:--:--";
LIB_GETBUF(bp);
snprintf(bp, LIB_BUFLENGTH, "%02d:%02d:%02d",
tm->tm_hour, tm->tm_min, tm->tm_sec);
return bp;
}
@@ -0,0 +1,178 @@
/*
* Program to control ICOM radios
*
* This is a ripoff of the utility routines in the ICOM software
* distribution. The only function provided is to load the radio
* frequency. All other parameters must be manually set before use.
*/
#include <config.h>
#include <ntp_stdlib.h>
#include <ntp_tty.h>
#include <l_stdlib.h>
#include <icom.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#ifdef SYS_WINNT
#undef write /* ports/winnt/include/config.h: #define write _write */
extern int async_write(int, const void *, unsigned int);
#define write(fd, data, octets) async_write(fd, data, octets)
#endif
/*
* Packet routines
*
* These routines send a packet and receive the response. If an error
* (collision) occurs on transmit, the packet is resent. If an error
* occurs on receive (timeout), all input to the terminating FI is
* discarded and the packet is resent. If the maximum number of retries
* is not exceeded, the program returns the number of octets in the user
* buffer; otherwise, it returns zero.
*
* ICOM frame format
*
* Frames begin with a two-octet preamble PR-PR followyd by the
* transceiver address RE, controller address TX, control code CN, zero
* or more data octets DA (depending on command), and terminator FI.
* Since the bus is bidirectional, every octet output is echoed on
* input. Every valid frame sent is answered with a frame in the same
* format, but with the RE and TX fields interchanged. The CN field is
* set to NAK if an error has occurred. Otherwise, the data are returned
* in this and following DA octets. If no data are returned, the CN
* octet is set to ACK.
*
* +------+------+------+------+------+--//--+------+
* | PR | PR | RE | TX | CN | DA | FI |
* +------+------+------+------+------+--//--+------+
*/
/*
* Scraps
*/
#define DICOM /dev/icom/ /* ICOM port link */
/*
* Local function prototypes
*/
static void doublefreq (double, u_char *, int);
/*
* icom_freq(fd, ident, freq) - load radio frequency
*
* returns:
* 0 (ok)
* -1 (error)
* 1 (short write to device)
*/
int
icom_freq(
int fd, /* file descriptor */
int ident, /* ICOM radio identifier */
double freq /* frequency (MHz) */
)
{
u_char cmd[] = {PAD, PR, PR, 0, TX, V_SFREQ, 0, 0, 0, 0, FI,
FI};
int temp;
int rc;
cmd[3] = (char)ident;
if (ident == IC735)
temp = 4;
else
temp = 5;
doublefreq(freq * 1e6, &cmd[6], temp);
rc = write(fd, cmd, temp + 7);
if (rc == -1) {
msyslog(LOG_ERR, "icom_freq: write() failed: %m");
return -1;
} else if (rc != temp + 7) {
msyslog(LOG_ERR, "icom_freq: only wrote %d of %d bytes.",
rc, temp+7);
return 1;
}
return 0;
}
/*
* doublefreq(freq, y, len) - double to ICOM frequency with padding
*/
static void
doublefreq( /* returns void */
double freq, /* frequency */
u_char *x, /* radio frequency */
int len /* length (octets) */
)
{
int i;
char s1[16];
char *y;
snprintf(s1, sizeof(s1), " %10.0f", freq);
y = s1 + 10;
i = 0;
while (*y != ' ') {
x[i] = *y-- & 0x0f;
x[i] = x[i] | ((*y-- & 0x0f) << 4);
i++;
}
for ( ; i < len; i++)
x[i] = 0;
x[i] = FI;
}
/*
* icom_init() - open and initialize serial interface
*
* This routine opens the serial interface for raw transmission; that
* is, character-at-a-time, no stripping, checking or monkeying with the
* bits. For Unix, an input operation ends either with the receipt of a
* character or a 0.5-s timeout.
*/
int
icom_init(
const char *device, /* device name/link */
int speed, /* line speed */
int trace /* trace flags */ )
{
TTY ttyb;
int fd;
int rc;
int saved_errno;
fd = tty_open(device, O_RDWR, 0777);
if (fd < 0)
return -1;
rc = tcgetattr(fd, &ttyb);
if (rc < 0) {
saved_errno = errno;
close(fd);
errno = saved_errno;
return -1;
}
ttyb.c_iflag = 0; /* input modes */
ttyb.c_oflag = 0; /* output modes */
ttyb.c_cflag = IBAUD|CS8|CLOCAL; /* control modes (no read) */
ttyb.c_lflag = 0; /* local modes */
ttyb.c_cc[VMIN] = 0; /* min chars */
ttyb.c_cc[VTIME] = 5; /* receive timeout */
cfsetispeed(&ttyb, (u_int)speed);
cfsetospeed(&ttyb, (u_int)speed);
rc = tcsetattr(fd, TCSANOW, &ttyb);
if (rc < 0) {
saved_errno = errno;
close(fd);
errno = saved_errno;
return -1;
}
return (fd);
}
/* end program */
@@ -0,0 +1,551 @@
/*
* iosignal.c - input/output routines for ntpd. The socket-opening code
* was shamelessly stolen from ntpd.
*/
/*
* [Bug 158]
* Do the #includes differently, as under some versions of Linux
* sys/param.h has a #undef CONFIG_PHONE line in it.
*
* As we have ~40 CONFIG_ variables, I don't feel like renaming them
* every time somebody adds a new macro to some system header.
*/
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#include <stdio.h>
#include <signal.h>
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif /* HAVE_SYS_PARAM_H */
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#include <arpa/inet.h>
#if _BSDI_VERSION >= 199510
# include <ifaddrs.h>
#endif
# ifdef __QNXNTO__
# include <fcntl.h>
# include <unix.h>
# define FNDELAY O_NDELAY
# endif
#include "ntp_machine.h"
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_if.h"
#include "ntp_stdlib.h"
#include "iosignal.h"
#include <ipcom_type.h>
#include <ipcom_os.h>
#include <ipntp.h>
#if defined(HAVE_SIGNALED_IO)
static RETSIGTYPE sigio_handler (int);
/* consistency safegurad to catch BLOCK/UNBLOCK oversights */
static int sigio_block_count = 0;
/* main inputhandler to be called on SIGIO */
static input_handler_t *input_handler_callback = NULL;
# if defined(HAVE_SIGACTION)
/*
* If sigaction() is used for signal handling and a signal is
* pending then the kernel blocks the signal before it calls
* the signal handler.
*
* The variable below is used to take care that the SIGIO signal
* is not unintentionally unblocked inside the sigio_handler()
* if the handler executes a piece of code that is normally
* bracketed by BLOCKIO()/UNBLOCKIO() calls.
*/
static int sigio_handler_active = 0;
# endif
/*
* SIGPOLL and SIGIO ROUTINES.
*/
/*
* TTY initialization routines.
*/
int
init_clock_sig(
struct refclockio *rio
)
{
# ifdef USE_TTY_SIGPOLL
{
/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0)
{
msyslog(LOG_ERR,
"init_clock_sig: ioctl(I_SETSIG, S_INPUT) failed: %m");
return 1;
}
return 0;
}
# else
/*
* Special cases first!
*/
/* Was: defined(SYS_HPUX) */
# if defined(FIOSSAIOOWN) && defined(FIOSNBIO) && defined(FIOSSAIOSTAT)
#define CLOCK_DONE
{
int pgrp, on = 1;
/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
pgrp = (int)ipcom_getpid();
if (ioctl(rio->fd, FIOSSAIOOWN, (char *)&pgrp) == -1)
{
msyslog(LOG_ERR, "ioctl(FIOSSAIOOWN) fails for clock I/O: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
/*NOTREACHED*/
}
/*
* set non-blocking, async I/O on the descriptor
*/
if (ioctl(rio->fd, FIOSNBIO, (char *)&on) == -1)
{
msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails for clock I/O: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
/*NOTREACHED*/
}
if (ioctl(rio->fd, FIOSSAIOSTAT, (char *)&on) == -1)
{
msyslog(LOG_ERR, "ioctl(FIOSSAIOSTAT) fails for clock I/O: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
/*NOTREACHED*/
}
return 0;
}
# endif /* SYS_HPUX: FIOSSAIOOWN && FIOSNBIO && FIOSSAIOSTAT */
/* Was: defined(SYS_AIX) && !defined(_BSD) */
# if !defined(_BSD) && defined(_AIX) && defined(FIOASYNC) && defined(FIOSETOWN)
/*
* SYSV compatibility mode under AIX.
*/
#define CLOCK_DONE
{
int pgrp, on = 1;
/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
if (ioctl(rio->fd, FIOASYNC, (char *)&on) == -1)
{
msyslog(LOG_ERR, "ioctl(FIOASYNC) fails for clock I/O: %m");
return 1;
}
pgrp = -getpid();
if (ioctl(rio->fd, FIOSETOWN, (char*)&pgrp) == -1)
{
msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails for clock I/O: %m");
return 1;
}
if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0)
{
msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
return 1;
}
return 0;
}
# endif /* AIX && !BSD: !_BSD && FIOASYNC && FIOSETOWN */
# ifndef CLOCK_DONE
{
/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
# if defined(TIOCSCTTY) && defined(USE_FSETOWNCTTY)
/*
* there are, however, always exceptions to the rules
* one is, that OSF accepts SETOWN on TTY fd's only, iff they are
* CTTYs. SunOS and HPUX do not semm to have this restriction.
* another question is: how can you do multiple SIGIO from several
* ttys (as they all should be CTTYs), wondering...
*
* kd 95-07-16
*/
if (ioctl(rio->fd, TIOCSCTTY, 0) == -1)
{
msyslog(LOG_ERR, "ioctl(TIOCSCTTY, 0) fails for clock I/O: %m");
return 1;
}
# endif /* TIOCSCTTY && USE_FSETOWNCTTY */
if (fcntl(rio->fd, F_SETOWN, getpid()) == -1)
{
msyslog(LOG_ERR, "fcntl(F_SETOWN) fails for clock I/O: %m");
return 1;
}
if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0)
{
msyslog(LOG_ERR,
"fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
return 1;
}
return 0;
}
# endif /* CLOCK_DONE */
# endif /* !USE_TTY_SIGPOLL */
}
void
init_socket_sig(
int fd
)
{
# ifdef USE_UDP_SIGPOLL
{
if (ioctl(fd, I_SETSIG, S_INPUT) < 0)
{
msyslog(LOG_ERR,
"init_socket_sig: ioctl(I_SETSIG, S_INPUT) failed: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
}
}
# else /* USE_UDP_SIGPOLL */
{
int pgrp;
# ifdef FIOASYNC
int on = 1;
# endif
# if defined(FIOASYNC)
if (ioctl(fd, FIOASYNC, (char *)&on) == -1)
{
msyslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
/*NOTREACHED*/
}
# elif defined(FASYNC)
{
int flags;
if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
{
msyslog(LOG_ERR, "fcntl(F_GETFL) fails: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
/*NOTREACHED*/
}
if (fcntl(fd, F_SETFL, flags|FASYNC) < 0)
{
msyslog(LOG_ERR, "fcntl(...|FASYNC) fails: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
/*NOTREACHED*/
}
}
# else
# include "Bletch: Need asynchronous I/O!"
# endif
# ifdef UDP_BACKWARDS_SETOWN
pgrp = -getpid();
# else
pgrp = getpid();
# endif
# if defined(SIOCSPGRP)
if (ioctl(fd, SIOCSPGRP, (char *)&pgrp) == -1)
{
msyslog(LOG_ERR, "ioctl(SIOCSPGRP) fails: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
/*NOTREACHED*/
}
# elif defined(FIOSETOWN)
if (ioctl(fd, FIOSETOWN, (char*)&pgrp) == -1)
{
msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
/*NOTREACHED*/
}
# elif defined(F_SETOWN)
if (fcntl(fd, F_SETOWN, pgrp) == -1)
{
msyslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m - EXITING");
ipntp_exit_callback(ipcom_getpid());
/*NOTREACHED*/
}
# else
# include "Bletch: Need to set process(group) to receive SIG(IO|POLL)"
# endif
}
# endif /* USE_UDP_SIGPOLL */
}
static RETSIGTYPE
sigio_handler(
int sig
)
{
int saved_errno = errno;
l_fp ts;
get_systime(&ts);
# if defined(HAVE_SIGACTION)
sigio_handler_active++;
if (sigio_handler_active != 1) /* This should never happen! */
msyslog(LOG_ERR, "sigio_handler: sigio_handler_active != 1");
# endif
INSIST(input_handler_callback != NULL);
(*input_handler_callback)(&ts);
# if defined(HAVE_SIGACTION)
sigio_handler_active--;
if (sigio_handler_active != 0) /* This should never happen! */
msyslog(LOG_ERR, "sigio_handler: sigio_handler_active != 0");
# endif
errno = saved_errno;
}
/*
* Signal support routines.
*/
# ifdef HAVE_SIGACTION
void
set_signal(input_handler_t *input)
{
INSIST(input != NULL);
input_handler_callback = input;
using_sigio = TRUE;
# ifdef USE_SIGIO
(void) signal_no_reset(SIGIO, sigio_handler);
# endif
# ifdef USE_SIGPOLL
(void) signal_no_reset(SIGPOLL, sigio_handler);
# endif
}
void
block_io_and_alarm(void)
{
sigset_t set;
if (sigemptyset(&set))
msyslog(LOG_ERR, "block_io_and_alarm: sigemptyset() failed: %m");
# if defined(USE_SIGIO)
if (sigaddset(&set, SIGIO))
msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGIO) failed: %m");
# endif
# if defined(USE_SIGPOLL)
if (sigaddset(&set, SIGPOLL))
msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGPOLL) failed: %m");
# endif
if (sigaddset(&set, SIGALRM))
msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGALRM) failed: %m");
if (sigprocmask(SIG_BLOCK, &set, NULL))
msyslog(LOG_ERR, "block_io_and_alarm: sigprocmask() failed: %m");
}
void
block_sigio(void)
{
if ( sigio_handler_active == 0 ) /* not called from within signal handler */
{
sigset_t set;
++sigio_block_count;
if (sigio_block_count > 1)
msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1");
if (sigio_block_count < 1)
msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1");
if (sigemptyset(&set))
msyslog(LOG_ERR, "block_sigio: sigemptyset() failed: %m");
# if defined(USE_SIGIO)
if (sigaddset(&set, SIGIO))
msyslog(LOG_ERR, "block_sigio: sigaddset(SIGIO) failed: %m");
# endif
# if defined(USE_SIGPOLL)
if (sigaddset(&set, SIGPOLL))
msyslog(LOG_ERR, "block_sigio: sigaddset(SIGPOLL) failed: %m");
# endif
if (sigprocmask(SIG_BLOCK, &set, NULL))
msyslog(LOG_ERR, "block_sigio: sigprocmask() failed: %m");
}
}
void
unblock_io_and_alarm(void)
{
sigset_t unset;
if (sigemptyset(&unset))
msyslog(LOG_ERR, "unblock_io_and_alarm: sigemptyset() failed: %m");
# if defined(USE_SIGIO)
if (sigaddset(&unset, SIGIO))
msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGIO) failed: %m");
# endif
# if defined(USE_SIGPOLL)
if (sigaddset(&unset, SIGPOLL))
msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGPOLL) failed: %m");
# endif
if (sigaddset(&unset, SIGALRM))
msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGALRM) failed: %m");
if (sigprocmask(SIG_UNBLOCK, &unset, NULL))
msyslog(LOG_ERR, "unblock_io_and_alarm: sigprocmask() failed: %m");
}
void
unblock_sigio(void)
{
if ( sigio_handler_active == 0 ) /* not called from within signal handler */
{
sigset_t unset;
--sigio_block_count;
if (sigio_block_count > 0)
msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0");
if (sigio_block_count < 0)
msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0");
if (sigemptyset(&unset))
msyslog(LOG_ERR, "unblock_sigio: sigemptyset() failed: %m");
# if defined(USE_SIGIO)
if (sigaddset(&unset, SIGIO))
msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGIO) failed: %m");
# endif
# if defined(USE_SIGPOLL)
if (sigaddset(&unset, SIGPOLL))
msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGPOLL) failed: %m");
# endif
if (sigprocmask(SIG_UNBLOCK, &unset, NULL))
msyslog(LOG_ERR, "unblock_sigio: sigprocmask() failed: %m");
}
}
void
wait_for_signal(void)
{
sigset_t old;
if (sigprocmask(SIG_UNBLOCK, NULL, &old))
msyslog(LOG_ERR, "wait_for_signal: sigprocmask() failed: %m");
# if defined(USE_SIGIO)
if (sigdelset(&old, SIGIO))
msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGIO) failed: %m");
# endif
# if defined(USE_SIGPOLL)
if (sigdelset(&old, SIGPOLL))
msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGPOLL) failed: %m");
# endif
if (sigdelset(&old, SIGALRM))
msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGALRM) failed: %m");
if (sigsuspend(&old) && (errno != EINTR))
msyslog(LOG_ERR, "wait_for_signal: sigsuspend() failed: %m");
}
# else /* !HAVE_SIGACTION */
/*
* Must be an old bsd system.
* We assume there is no SIGPOLL.
*/
void
block_io_and_alarm(void)
{
int mask;
mask = sigmask(SIGIO) | sigmask(SIGALRM);
if (sigblock(mask))
msyslog(LOG_ERR, "block_io_and_alarm: sigblock() failed: %m");
}
void
block_sigio(void)
{
int mask;
++sigio_block_count;
if (sigio_block_count > 1)
msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1");
if (sigio_block_count < 1)
msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1");
mask = sigmask(SIGIO);
if (sigblock(mask))
msyslog(LOG_ERR, "block_sigio: sigblock() failed: %m");
}
void
set_signal(input_handler_t *input)
{
INSIST(input != NULL);
input_handler_callback = input;
using_sigio = TRUE;
(void) signal_no_reset(SIGIO, sigio_handler);
}
void
unblock_io_and_alarm(void)
{
int mask, omask;
mask = sigmask(SIGIO) | sigmask(SIGALRM);
omask = sigblock(0);
omask &= ~mask;
(void) sigsetmask(omask);
}
void
unblock_sigio(void)
{
int mask, omask;
--sigio_block_count;
if (sigio_block_count > 0)
msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0");
if (sigio_block_count < 0)
msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0");
mask = sigmask(SIGIO);
omask = sigblock(0);
omask &= ~mask;
(void) sigsetmask(omask);
}
void
wait_for_signal(void)
{
int mask, omask;
mask = sigmask(SIGIO) | sigmask(SIGALRM);
omask = sigblock(0);
omask &= ~mask;
if (sigpause(omask) && (errno != EINTR))
msyslog(LOG_ERR, "wait_for_signal: sigspause() failed: %m");
}
# endif /* HAVE_SIGACTION */
#else
int NotAnEmptyCompilationUnit;
#endif
@@ -0,0 +1,89 @@
/*
* is_ip_address
*
*/
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#include "ntp_assert.h"
#include "ntp_stdlib.h"
#include "safecast.h"
/* Don't include ISC's version of IPv6 variables and structures */
#define ISC_IPV6_H 1
#include <isc/netaddr.h>
#include <isc/sockaddr.h>
/*
* Code to tell if we have an IP address
* If we have then return the sockaddr structure
* and set the return value
* see the bind9/getaddresses.c for details
*/
int
is_ip_address(
const char * host,
u_short af,
sockaddr_u * addr
)
{
struct in_addr in4;
struct addrinfo hints;
struct addrinfo *result;
struct sockaddr_in6 *resaddr6;
char tmpbuf[128];
char *pch;
REQUIRE(host != NULL);
REQUIRE(addr != NULL);
ZERO_SOCK(addr);
/*
* Try IPv4, then IPv6. In order to handle the extended format
* for IPv6 scoped addresses (address%scope_ID), we'll use a local
* working buffer of 128 bytes. The length is an ad-hoc value, but
* should be enough for this purpose; the buffer can contain a string
* of at least 80 bytes for scope_ID in addition to any IPv6 numeric
* addresses (up to 46 bytes), the delimiter character and the
* terminating NULL character.
*/
if (AF_UNSPEC == af || AF_INET == af)
if (inet_pton(AF_INET, host, &in4) == 1) {
AF(addr) = AF_INET;
SET_ADDR4N(addr, in4.s_addr);
return TRUE;
}
if (AF_UNSPEC == af || AF_INET6 == af)
if (sizeof(tmpbuf) > strlen(host)) {
if ('[' == host[0]) {
strlcpy(tmpbuf, &host[1], sizeof(tmpbuf));
pch = strchr(tmpbuf, ']');
if (pch != NULL)
*pch = '\0';
} else {
strlcpy(tmpbuf, host, sizeof(tmpbuf));
}
ZERO(hints);
hints.ai_family = AF_INET6;
hints.ai_flags |= AI_NUMERICHOST;
if (getaddrinfo(tmpbuf, NULL, &hints, &result) == 0) {
AF(addr) = AF_INET6;
resaddr6 = UA_PTR(struct sockaddr_in6, result->ai_addr);
SET_ADDR6N(addr, resaddr6->sin6_addr);
SET_SCOPE(addr, resaddr6->sin6_scope_id);
freeaddrinfo(result);
return TRUE;
}
}
/*
* If we got here it was not an IP address
*/
return FALSE;
}
@@ -0,0 +1,42 @@
/*
* lib_strbuf - library string storage
*/
#ifdef HAVE_CONFIG_H
#include <ipntp_config.h>
#endif
#include <isc/net.h>
#include <isc/result.h>
#include "ntp_fp.h"
#include "ntp_stdlib.h"
#include "lib_strbuf.h"
/*
* Storage declarations
*/
int debug;
libbufstr lib_stringbuf[LIB_NUMBUF];
int lib_nextbuf;
int ipv4_works;
int ipv6_works;
int lib_inited;
/*
* initialization routine. Might be needed if the code is ROMized.
*/
void
init_lib(void)
{
if (lib_inited)
return;
ipv4_works = (ISC_R_SUCCESS == isc_net_probeipv4());
ipv6_works = (ISC_R_SUCCESS == isc_net_probeipv6());
init_systime();
debug = 0;
lib_nextbuf = 0;
memset(lib_stringbuf, 0, sizeof(libbufstr)*LIB_NUMBUF);
lib_inited = TRUE;
}
@@ -0,0 +1,348 @@
/*
* libssl_compat.c -- OpenSSL v1.1 compatibility functions
*
* ---------------------------------------------------------------------
* Written by Juergen Perlinger <perlinger@ntp.org> for the NTP project
*
* Based on an idea by Kurt Roeckx <kurt@roeckx.be>
*
* ---------------------------------------------------------------------
* This is a clean room implementation of shim functions that have
* counterparts in the OpenSSL v1.1 API but not in earlier versions. So
* while OpenSSL broke binary compatibility with v1.1, this shim module
* should provide the necessary source code compatibility with older
* versions of OpenSSL.
* ---------------------------------------------------------------------
*/
#include "ipntp_config.h"
#include "ntp_types.h"
#include <string.h>
#include "ntp_stdlib.h"
#include "ntp_types.h"
#include "ntp_mem.h"
#include "libssl_compat.h"
/* ----------------------------------------------------------------- */
#ifdef OPENSSL
# include <string.h>
# include <openssl/bn.h>
# include <openssl/evp.h>
#endif
/* ----------------------------------------------------------------- */
/* ----------------------------------------------------------------- */
#if defined(OPENSSL) && OPENSSL_VERSION_NUMBER < 0x10100000L
/* ----------------------------------------------------------------- */
#include "ntp_assert.h"
/* --------------------------------------------------------------------
* replace a BIGNUM owned by the caller with another one if it's not
* NULL, taking over the ownership of the new value. This clears & frees
* the old value -- the clear might be overkill, but it's better to err
* on the side of paranoia here.
*/
static void
replace_bn_nn(
BIGNUM ** ps,
BIGNUM * n
)
{
if (n) {
REQUIRE(*ps != n);
BN_clear_free(*ps);
*ps = n;
}
}
/* --------------------------------------------------------------------
* allocation and deallocation of prime number callbacks
*/
BN_GENCB*
sslshimBN_GENCB_new(void)
{
return emalloc(sizeof(BN_GENCB));
}
void
sslshimBN_GENCB_free(
BN_GENCB *cb
)
{
efree(cb);
}
/* --------------------------------------------------------------------
* allocation and deallocation of message digests
*/
EVP_MD_CTX*
sslshim_EVP_MD_CTX_new(void)
{
EVP_MD_CTX * ctx;
if (NULL != (ctx = emalloc(sizeof(EVP_MD_CTX))))
EVP_MD_CTX_init(ctx);
return ctx;
}
void
sslshim_EVP_MD_CTX_free(
EVP_MD_CTX * pctx
)
{
efree(pctx);
}
/* --------------------------------------------------------------------
* get EVP keys and key type
*/
int
sslshim_EVP_PKEY_id(
const EVP_PKEY *pkey
)
{
return (pkey) ? pkey->type : EVP_PKEY_NONE;
}
int
sslshim_EVP_PKEY_base_id(
const EVP_PKEY *pkey
)
{
return (pkey) ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE;
}
RSA*
sslshim_EVP_PKEY_get0_RSA(
EVP_PKEY * pkey
)
{
return (pkey) ? pkey->pkey.rsa : NULL;
}
DSA*
sslshim_EVP_PKEY_get0_DSA(
EVP_PKEY * pkey
)
{
return (pkey) ? pkey->pkey.dsa : NULL;
}
/* --------------------------------------------------------------------
* set/get RSA params
*/
void
sslshim_RSA_get0_key(
const RSA * prsa,
const BIGNUM ** pn,
const BIGNUM ** pe,
const BIGNUM ** pd
)
{
REQUIRE(prsa != NULL);
if (pn)
*pn = prsa->n;
if (pe)
*pe = prsa->e;
if (pd)
*pd = prsa->d;
}
int
sslshim_RSA_set0_key(
RSA * prsa,
BIGNUM * n,
BIGNUM * e,
BIGNUM * d
)
{
REQUIRE(prsa != NULL);
if (!((prsa->n || n) && (prsa->e || e)))
return 0;
replace_bn_nn(&prsa->n, n);
replace_bn_nn(&prsa->e, e);
replace_bn_nn(&prsa->d, d);
return 1;
}
void
sslshim_RSA_get0_factors(
const RSA * prsa,
const BIGNUM ** pp,
const BIGNUM ** pq
)
{
REQUIRE(prsa != NULL);
if (pp)
*pp = prsa->p;
if (pq)
*pq = prsa->q;
}
int
sslshim_RSA_set0_factors(
RSA * prsa,
BIGNUM * p,
BIGNUM * q
)
{
REQUIRE(prsa != NULL);
if (!((prsa->p || p) && (prsa->q || q)))
return 0;
replace_bn_nn(&prsa->p, p);
replace_bn_nn(&prsa->q, q);
return 1;
}
int
sslshim_RSA_set0_crt_params(
RSA * prsa,
BIGNUM * dmp1,
BIGNUM * dmq1,
BIGNUM * iqmp
)
{
REQUIRE(prsa != NULL);
if (!((prsa->dmp1 || dmp1) &&
(prsa->dmq1 || dmq1) &&
(prsa->iqmp || iqmp) ))
return 0;
replace_bn_nn(&prsa->dmp1, dmp1);
replace_bn_nn(&prsa->dmq1, dmq1);
replace_bn_nn(&prsa->iqmp, iqmp);
return 1;
}
/* --------------------------------------------------------------------
* set/get DSA signature parameters
*/
void
sslshim_DSA_SIG_get0(
const DSA_SIG * psig,
const BIGNUM ** pr,
const BIGNUM ** ps
)
{
REQUIRE(psig != NULL);
if (pr != NULL)
*pr = psig->r;
if (ps != NULL)
*ps = psig->s;
}
int
sslshim_DSA_SIG_set0(
DSA_SIG * psig,
BIGNUM * r,
BIGNUM * s
)
{
REQUIRE(psig != NULL);
if (!(r && s))
return 0;
replace_bn_nn(&psig->r, r);
replace_bn_nn(&psig->s, s);
return 1;
}
/* --------------------------------------------------------------------
* get/set DSA parameters
*/
void
sslshim_DSA_get0_pqg(
const DSA * pdsa,
const BIGNUM ** pp,
const BIGNUM ** pq,
const BIGNUM ** pg
)
{
REQUIRE(pdsa != NULL);
if (pp != NULL)
*pp = pdsa->p;
if (pq != NULL)
*pq = pdsa->q;
if (pg != NULL)
*pg = pdsa->g;
}
int
sslshim_DSA_set0_pqg(
DSA * pdsa,
BIGNUM * p,
BIGNUM * q,
BIGNUM * g
)
{
if (!((pdsa->p || p) && (pdsa->q || q) && (pdsa->g || g)))
return 0;
replace_bn_nn(&pdsa->p, p);
replace_bn_nn(&pdsa->q, q);
replace_bn_nn(&pdsa->g, g);
return 1;
}
void
sslshim_DSA_get0_key(
const DSA * pdsa,
const BIGNUM ** ppub_key,
const BIGNUM ** ppriv_key
)
{
REQUIRE(pdsa != NULL);
if (ppub_key != NULL)
*ppub_key = pdsa->pub_key;
if (ppriv_key != NULL)
*ppriv_key = pdsa->priv_key;
}
int
sslshim_DSA_set0_key(
DSA * pdsa,
BIGNUM * pub_key,
BIGNUM * priv_key
)
{
REQUIRE(pdsa != NULL);
if (!(pdsa->pub_key || pub_key))
return 0;
replace_bn_nn(&pdsa->pub_key, pub_key);
replace_bn_nn(&pdsa->priv_key, priv_key);
return 1;
}
int
sslshim_X509_get_signature_nid(
const X509 *x
)
{
return OBJ_obj2nid(x->sig_alg->algorithm);
}
/* ----------------------------------------------------------------- */
#else /* OPENSSL && OPENSSL_VERSION_NUMBER >= v1.1.0 */
/* ----------------------------------------------------------------- */
NONEMPTY_TRANSLATION_UNIT
/* ----------------------------------------------------------------- */
#endif
/* ----------------------------------------------------------------- */
@@ -0,0 +1,546 @@
/* machines.c - provide special support for peculiar architectures
*
* Real bummers unite !
*
*/
#ifdef HAVE_CONFIG_H
#include "ipntp_config.h"
#endif
#include "ntp.h"
#include "ntp_machine.h"
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
#include "ntp_unixtime.h"
#include "lib_strbuf.h"
#include "ntp_debug.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef SYS_WINNT
int _getch(void); /* Declare the one function rather than include conio.h */
#else
#ifdef SYS_VXWORKS
#include <sys/types.h>
#ifdef NTP_VXWORKS_6
#include <time.h>
#include "ntp_syslog.h"
#else
#include "taskLib.h"
#include "sysLib.h"
#include "time.h"
#include "ntp_syslog.h"
#include "ntp_vxworks.h"
/* some translations to the world of vxWorkings -casey */
/* first some netdb type things */
#include "ioLib.h"
#include <socket.h>
int h_errno;
struct hostent *gethostbyname(char *name)
{
struct hostent *host1;
h_errno = 0; /* we are always successful!!! */
host1 = (struct hostent *) emalloc (sizeof(struct hostent));
host1->h_name = name;
host1->h_addrtype = AF_INET;
host1->h_aliases = name;
host1->h_length = 4;
host1->h_addr_list[0] = (char *)hostGetByName (name);
host1->h_addr_list[1] = NULL;
return host1;
}
struct hostent *gethostbyaddr(char *name, int size, int addr_type)
{
struct hostent *host1;
h_errno = 0; /* we are always successful!!! */
host1 = (struct hostent *) emalloc (sizeof(struct hostent));
host1->h_name = name;
host1->h_addrtype = AF_INET;
host1->h_aliases = name;
host1->h_length = 4;
host1->h_addr_list = NULL;
return host1;
}
struct servent *getservbyname (char *name, char *type)
{
struct servent *serv1;
serv1 = (struct servent *) emalloc (sizeof(struct servent));
serv1->s_name = "ntp"; /* official service name */
serv1->s_aliases = NULL; /* alias list */
serv1->s_port = 123; /* port # */
serv1->s_proto = "udp"; /* protocol to use */
return serv1;
}
#endif
/* second
* vxworks thinks it has insomnia
* we have to sleep for number of seconds
*/
/* I am not sure how valid the granularity is - it is from G. Eger's port */
#define CLK_GRANULARITY 1 /* Granularity of system clock in usec */
/* Used to round down # usecs/tick */
/* On a VCOM-100, PIT gets 8 MHz clk, */
/* & it prescales by 32, thus 4 usec */
/* on mv167, granularity is 1usec anyway*/
/* To defeat rounding, set to 1 */
#define USECS_PER_SEC MILLION /* Microseconds per second */
#define TICK (((USECS_PER_SEC / NTP_SYSCLKRATEGET) / CLK_GRANULARITY) * CLK_GRANULARITY)
/*#define KEY_TYPE_MD5 4*/
/*#define MINDISPERSE .005 min dispersion increment */
/*#define MAXDISTANCE 1. max root distance (select threshold) */
#define MAXHOP 2 /* anti-clockhop threshold */
#ifndef NTP_VXWORKS_6
/* emulate unix sleep
* casey
*/
void sleep(int seconds)
{
taskDelay(seconds*TICK);
}
/* emulate unix alarm
* that pauses and calls SIGALRM after the seconds are up...
* so ... taskDelay() fudged for seconds should amount to the same thing.
* casey
*/
void alarm (int seconds)
{
sleep(seconds);
}
#endif /* NTP_VXWORKS_6 */
#endif /* SYS_VXWORKS */
#ifdef SYS_PTX /* Does PTX still need this? */
/*#include <sys/types.h> */
#include <sys/procstats.h>
int
gettimeofday(
struct timeval *tvp
)
{
/*
* hi, this is Sequents sneak path to get to a clock
* this is also the most logical syscall for such a function
*/
return (get_process_stats(tvp, PS_SELF, (struct procstats *) 0,
(struct procstats *) 0));
}
#endif /* SYS_PTX */
#ifdef MPE
/* This is a substitute for bind() that if called for an AF_INET socket
port less than 1024, GETPRIVMODE() and GETUSERMODE() calls will be done. */
#undef bind
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
extern void GETPRIVMODE(void);
extern void GETUSERMODE(void);
int __ntp_mpe_bind(int s, void *addr, int addrlen);
int __ntp_mpe_bind(int s, void *addr, int addrlen) {
int priv = 0;
int result;
if (addrlen == sizeof(struct sockaddr_in)) { /* AF_INET */
if (((struct sockaddr_in *)addr)->sin_port > 0 &&
((struct sockaddr_in *)addr)->sin_port < 1024) {
priv = 1;
GETPRIVMODE();
}
/* ((struct sockaddr_in *)addr)->sin_addr.s_addr = 0; */
result = bind(s,addr,addrlen);
if (priv == 1) GETUSERMODE();
} else /* AF_UNIX */
result = bind(s,addr,addrlen);
return result;
}
/*
* MPE stupidly requires sfcntl() to be used on sockets instead of fcntl(),
* so we define a wrapper to analyze the file descriptor and call the correct
* function.
*/
#undef fcntl
#include <errno.h>
#include <fcntl.h>
int __ntp_mpe_fcntl(int fd, int cmd, int arg);
int __ntp_mpe_fcntl(int fd, int cmd, int arg) {
int len;
struct sockaddr sa;
extern int sfcntl(int, int, int);
len = sizeof sa;
if (getsockname(fd, &sa, &len) == -1) {
if (errno == EAFNOSUPPORT) /* AF_UNIX socket */
return sfcntl(fd, cmd, arg);
if (errno == ENOTSOCK) /* file or pipe */
return fcntl(fd, cmd, arg);
return (-1); /* unknown getsockname() failure */
} else /* AF_INET socket */
return sfcntl(fd, cmd, arg);
}
/*
* Setitimer emulation support. Note that we implement this using alarm(),
* and since alarm() only delivers one signal, we must re-enable the alarm
* by enabling our own SIGALRM setitimer_mpe_handler routine to be called
* before the real handler routine and re-enable the alarm at that time.
*
* Note that this solution assumes that sigaction(SIGALRM) is called before
* calling setitimer(). If it should ever to become necessary to support
* sigaction(SIGALRM) after calling setitimer(), it will be necessary to trap
* those sigaction() calls.
*/
#include <limits.h>
#include <signal.h>
/*
* Some global data that needs to be shared between setitimer() and
* setitimer_mpe_handler().
*/
struct {
unsigned long current_msec; /* current alarm() value in effect */
unsigned long interval_msec; /* next alarm() value from setitimer */
unsigned long value_msec; /* first alarm() value from setitimer */
struct itimerval current_itimerval; /* current itimerval in effect */
struct sigaction oldact; /* SIGALRM state saved by setitimer */
} setitimer_mpe_ctx = { 0, 0, 0 };
/*
* Undocumented, unsupported function to do alarm() in milliseconds.
*/
extern unsigned int px_alarm(unsigned long, int *);
/*
* The SIGALRM handler routine enabled by setitimer(). Re-enable the alarm or
* restore the original SIGALRM setting if no more alarms are needed. Then
* call the original SIGALRM handler (if any).
*/
static RETSIGTYPE setitimer_mpe_handler(int sig)
{
int alarm_hpe_status;
/* Update the new current alarm value */
setitimer_mpe_ctx.current_msec = setitimer_mpe_ctx.interval_msec;
if (setitimer_mpe_ctx.interval_msec > 0) {
/* Additional intervals needed; re-arm the alarm timer */
px_alarm(setitimer_mpe_ctx.interval_msec,&alarm_hpe_status);
} else {
/* No more intervals, so restore previous original SIGALRM handler */
sigaction(SIGALRM, &setitimer_mpe_ctx.oldact, NULL);
}
/* Call the original SIGALRM handler if it is a function and not just a flag */
if (setitimer_mpe_ctx.oldact.sa_handler != SIG_DFL &&
setitimer_mpe_ctx.oldact.sa_handler != SIG_ERR &&
setitimer_mpe_ctx.oldact.sa_handler != SIG_IGN)
(*setitimer_mpe_ctx.oldact.sa_handler)(SIGALRM);
}
/*
* Our implementation of setitimer().
*/
int
setitimer(int which, struct itimerval *value,
struct itimerval *ovalue)
{
int alarm_hpe_status;
unsigned long remaining_msec, value_msec, interval_msec;
struct sigaction newact;
/*
* Convert the initial interval to milliseconds
*/
if (value->it_value.tv_sec > (UINT_MAX / 1000))
value_msec = UINT_MAX;
else
value_msec = value->it_value.tv_sec * 1000;
value_msec += value->it_value.tv_usec / 1000;
/*
* Convert the reset interval to milliseconds
*/
if (value->it_interval.tv_sec > (UINT_MAX / 1000))
interval_msec = UINT_MAX;
else
interval_msec = value->it_interval.tv_sec * 1000;
interval_msec += value->it_interval.tv_usec / 1000;
if (value_msec > 0 && interval_msec > 0) {
/*
* We'll be starting an interval timer that will be repeating, so we need to
* insert our own SIGALRM signal handler to schedule the repeats.
*/
/* Read the current SIGALRM action */
if (sigaction(SIGALRM, NULL, &setitimer_mpe_ctx.oldact) < 0) {
fprintf(stderr,"MPE setitimer old handler failed, errno=%d\n",errno);
return -1;
}
/* Initialize the new action to call our SIGALRM handler instead */
newact.sa_handler = &setitimer_mpe_handler;
newact.sa_mask = setitimer_mpe_ctx.oldact.sa_mask;
newact.sa_flags = setitimer_mpe_ctx.oldact.sa_flags;
if (sigaction(SIGALRM, &newact, NULL) < 0) {
fprintf(stderr,"MPE setitimer new handler failed, errno=%d\n",errno);
return -1;
}
}
/*
* Return previous itimerval if desired
*/
if (ovalue != NULL) *ovalue = setitimer_mpe_ctx.current_itimerval;
/*
* Save current parameters for later usage
*/
setitimer_mpe_ctx.current_itimerval = *value;
setitimer_mpe_ctx.current_msec = value_msec;
setitimer_mpe_ctx.value_msec = value_msec;
setitimer_mpe_ctx.interval_msec = interval_msec;
/*
* Schedule the first alarm
*/
remaining_msec = px_alarm(value_msec, &alarm_hpe_status);
if (alarm_hpe_status == 0)
return (0);
else
return (-1);
}
/*
* MPE lacks gettimeofday(), so we define our own.
*/
int gettimeofday(struct timeval *tvp)
{
/* Documented, supported MPE functions. */
extern void GETPRIVMODE(void);
extern void GETUSERMODE(void);
/* Undocumented, unsupported MPE functions. */
extern long long get_time(void);
extern void get_time_change_info(long long *, char *, char *);
extern long long ticks_to_micro(long long);
char pwf_since_boot, recover_pwf_time;
long long mpetime, offset_ticks, offset_usec;
GETPRIVMODE();
mpetime = get_time(); /* MPE local time usecs since Jan 1 1970 */
get_time_change_info(&offset_ticks, &pwf_since_boot, &recover_pwf_time);
offset_usec = ticks_to_micro(offset_ticks); /* UTC offset usecs */
GETUSERMODE();
mpetime = mpetime - offset_usec; /* Convert from local time to UTC */
tvp->tv_sec = mpetime / 1000000LL;
tvp->tv_usec = mpetime % 1000000LL;
return 0;
}
/*
* MPE lacks settimeofday(), so we define our own.
*/
#define HAVE_SETTIMEOFDAY
int settimeofday(struct timeval *tvp)
{
/* Documented, supported MPE functions. */
extern void GETPRIVMODE(void);
extern void GETUSERMODE(void);
/* Undocumented, unsupported MPE functions. */
extern void get_time_change_info(long long *, char *, char *);
extern void initialize_system_time(long long, int);
extern void set_time_correction(long long, int, int);
extern long long ticks_to_micro(long long);
char pwf_since_boot, recover_pwf_time;
long long big_sec, big_usec, mpetime, offset_ticks, offset_usec;
big_sec = tvp->tv_sec;
big_usec = tvp->tv_usec;
mpetime = (big_sec * 1000000LL) + big_usec; /* Desired UTC microseconds */
GETPRIVMODE();
set_time_correction(0LL,0,0); /* Cancel previous time correction, if any */
get_time_change_info(&offset_ticks, &pwf_since_boot, &recover_pwf_time);
offset_usec = ticks_to_micro(offset_ticks); /* UTC offset microseconds */
mpetime = mpetime + offset_usec; /* Convert from UTC to local time */
initialize_system_time(mpetime,1);
GETUSERMODE();
return 0;
}
#endif /* MPE */
#define SET_TOD_UNDETERMINED 0
#define SET_TOD_CLOCK_SETTIME 1
#define SET_TOD_SETTIMEOFDAY 2
#define SET_TOD_STIME 3
const char * const set_tod_used[] = {
"undetermined",
"clock_settime",
"settimeofday",
"stime"
};
pset_tod_using set_tod_using = NULL;
int
ntp_set_tod(
struct timeval *tvp,
void *tzp
)
{
static int tod;
int rc;
int saved_errno;
TRACE(1, ("In ntp_set_tod\n"));
rc = -1;
saved_errno = 0;
#ifdef HAVE_CLOCK_SETTIME
if (rc && (SET_TOD_CLOCK_SETTIME == tod || !tod)) {
errno = 0;
rc = ipcom_settimeofday(tvp, IP_NULL);
saved_errno = errno;
TRACE(1, ("ntp_set_tod: clock_settime: %d %m\n", rc));
if (!tod && !rc)
tod = SET_TOD_CLOCK_SETTIME;
}
#endif /* HAVE_CLOCK_SETTIME */
#ifdef HAVE_SETTIMEOFDAY
if (rc && (SET_TOD_SETTIMEOFDAY == tod || !tod)) {
struct timeval adjtv;
/*
* Some broken systems don't reset adjtime() when the
* clock is stepped.
*/
adjtv.tv_sec = adjtv.tv_usec = 0;
adjtime(&adjtv, NULL);
errno = 0;
rc = SETTIMEOFDAY(tvp, tzp);
saved_errno = errno;
TRACE(1, ("ntp_set_tod: settimeofday: %d %m\n", rc));
if (!tod && !rc)
tod = SET_TOD_SETTIMEOFDAY;
}
#endif /* HAVE_SETTIMEOFDAY */
#ifdef HAVE_STIME
if (rc && (SET_TOD_STIME == tod || !tod)) {
long tp = tvp->tv_sec;
errno = 0;
rc = stime(&tp); /* lie as bad as SysVR4 */
saved_errno = errno;
TRACE(1, ("ntp_set_tod: stime: %d %m\n", rc));
if (!tod && !rc)
tod = SET_TOD_STIME;
}
#endif /* HAVE_STIME */
errno = saved_errno; /* for %m below */
TRACE(1, ("ntp_set_tod: Final result: %s: %d %m\n",
set_tod_used[tod], rc));
/*
* Say how we're setting the time of day
*/
if (!rc && NULL != set_tod_using) {
(*set_tod_using)(set_tod_used[tod]);
set_tod_using = NULL;
}
if (rc)
errno = saved_errno;
return rc;
}
#endif /* not SYS_WINNT */
#if defined (SYS_WINNT) || defined (SYS_VXWORKS) || defined(MPE)
/* getpass is used in ntpq.c and ntpdc.c */
static char ntp_password[32];
char *
getpass(const char * prompt)
{
int c, i;
FILE *fi = stdin;
fprintf(stderr, "%s", prompt);
fflush(stderr);
for (i=0; i<sizeof(ntp_password)-1 && ((c=getc(fi))!=EOF && c!='\r'); i++) {
ntp_password[i] = (char) c;
}
ntp_password[i] = '\0';
fputc('\n', stderr);
fflush(stderr);
return ntp_password;
}
#endif /* SYS_WINNT */
@@ -0,0 +1,277 @@
/*
* Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2000, 2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: md5c.c,v 1.1.12.1 2015-03-31 09:17:02 lyang3 Exp $ */
/*! \file
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include "ipntp_config.h"
#include <isc/assertions.h>
#include <isc/md5.h>
#include <isc/platform.h>
#include <isc/string.h>
#include <isc/types.h>
#include <isc/util.h>
#ifdef ISC_PLATFORM_OPENSSLHASH
void
isc_md5_init(isc_md5_t *ctx) {
EVP_DigestInit(ctx, EVP_md5());
}
void
isc_md5_invalidate(isc_md5_t *ctx) {
EVP_MD_CTX_cleanup(ctx);
}
void
isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) {
EVP_DigestUpdate(ctx, (const void *) buf, (size_t) len);
}
void
isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
EVP_DigestFinal(ctx, digest, NULL);
}
#else
static void
byteSwap(isc_uint32_t *buf, unsigned words)
{
unsigned char *p = (unsigned char *)buf;
do {
*buf++ = (isc_uint32_t)((unsigned)p[3] << 8 | p[2]) << 16 |
((unsigned)p[1] << 8 | p[0]);
p += 4;
} while (--words);
}
/*!
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void
isc_md5_init(isc_md5_t *ctx) {
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bytes[0] = 0;
ctx->bytes[1] = 0;
}
void
isc_md5_invalidate(isc_md5_t *ctx) {
memset(ctx, 0, sizeof(isc_md5_t));
}
/*@{*/
/*! The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/*@}*/
/*! This is the central step in the MD5 algorithm. */
#define MD5STEP(f,w,x,y,z,in,s) \
(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
/*!
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void
transform(isc_uint32_t buf[4], isc_uint32_t const in[16]) {
register isc_uint32_t a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/*!
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void
isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) {
isc_uint32_t t;
/* Update byte count */
t = ctx->bytes[0];
if ((ctx->bytes[0] = t + len) < t)
ctx->bytes[1]++; /* Carry from low to high */
t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
if (t > len) {
memcpy((unsigned char *)ctx->in + 64 - t, buf, len);
return;
}
/* First chunk is an odd size */
memcpy((unsigned char *)ctx->in + 64 - t, buf, t);
byteSwap(ctx->in, 16);
transform(ctx->buf, ctx->in);
buf += t;
len -= t;
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteSwap(ctx->in, 16);
transform(ctx->buf, ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*!
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void
isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
unsigned char *p = (unsigned char *)ctx->in + count;
/* Set the first char of padding to 0x80. There is always room. */
*p++ = 0x80;
/* Bytes of padding needed to make 56 bytes (-8..55) */
count = 56 - 1 - count;
if (count < 0) { /* Padding forces an extra block */
memset(p, 0, count + 8);
byteSwap(ctx->in, 16);
transform(ctx->buf, ctx->in);
p = (unsigned char *)ctx->in;
count = 56;
}
memset(p, 0, count);
byteSwap(ctx->in, 14);
/* Append length in bits and transform */
ctx->in[14] = ctx->bytes[0] << 3;
ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
transform(ctx->buf, ctx->in);
byteSwap(ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(isc_md5_t)); /* In case it's sensitive */
}
#endif
@@ -0,0 +1,35 @@
/*
* modetoa - return an asciized mode
*/
#include <ipntp_config.h>
#include <stdio.h>
#include "lib_strbuf.h"
#include "ntp_stdlib.h"
const char *
modetoa(
size_t mode
)
{
char *bp;
static const char * const modestrings[] = {
"unspec",
"sym_active",
"sym_passive",
"client",
"server",
"broadcast",
"control",
"private",
"bclient",
};
if (mode >= COUNTOF(modestrings)) {
LIB_GETBUF(bp);
snprintf(bp, LIB_BUFLENGTH, "mode#%zu", mode);
return bp;
}
return modestrings[mode];
}
@@ -0,0 +1,99 @@
/*
* mstolfp - convert an ascii string in milliseconds to an l_fp number
*/
#include <ipntp_config.h>
#include <stdio.h>
#include <ctype.h>
#include "ntp_fp.h"
#include "ntp_stdlib.h"
int
mstolfp(
const char *str,
l_fp *lfp
)
{
register const char *cp;
register char *bp;
register const char *cpdec;
char buf[100];
/*
* We understand numbers of the form:
*
* [spaces][-|+][digits][.][digits][spaces|\n|\0]
*
* This is one enormous hack. Since I didn't feel like
* rewriting the decoding routine for milliseconds, what
* is essentially done here is to make a copy of the string
* with the decimal moved over three places so the seconds
* decoding routine can be used.
*/
bp = buf;
cp = str;
while (isspace((unsigned char)*cp))
cp++;
if (*cp == '-' || *cp == '+') {
*bp++ = *cp++;
}
if (*cp != '.' && !isdigit((unsigned char)*cp))
return 0;
/*
* Search forward for the decimal point or the end of the string.
*/
cpdec = cp;
while (isdigit((unsigned char)*cpdec))
cpdec++;
/*
* Found something. If we have more than three digits copy the
* excess over, else insert a leading 0.
*/
if ((cpdec - cp) > 3) {
do {
*bp++ = (char)*cp++;
} while ((cpdec - cp) > 3);
} else {
*bp++ = '0';
}
/*
* Stick the decimal in. If we've got less than three digits in
* front of the millisecond decimal we insert the appropriate number
* of zeros.
*/
*bp++ = '.';
if ((cpdec - cp) < 3) {
size_t i = 3 - (cpdec - cp);
do {
*bp++ = '0';
} while (--i > 0);
}
/*
* Copy the remainder up to the millisecond decimal. If cpdec
* is pointing at a decimal point, copy in the trailing number too.
*/
while (cp < cpdec)
*bp++ = (char)*cp++;
if (*cp == '.') {
cp++;
while (isdigit((unsigned char)*cp))
*bp++ = (char)*cp++;
}
*bp = '\0';
/*
* Check to make sure the string is properly terminated. If
* so, give the buffer to the decoding routine.
*/
if (*cp != '\0' && !isspace((unsigned char)*cp))
return 0;
return atolfp(buf, lfp);
}
@@ -0,0 +1,670 @@
/*
* msyslog - either send a message to the terminal or print it on
* the standard output.
*
* Converted to use varargs, much better ... jks
*/
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdio.h>
#include "ntp_string.h"
#include "ntp.h"
#include "ntp_debug.h"
#include "ntp_stdlib.h"
#include "ntp_mem.h"
#ifdef NTP_VXWORKS_7
#include "applUtilLib.h"
#endif
#include <ipcom_syslog.h>
#ifdef SYS_WINNT
# include <stdarg.h>
# include "..\ports\winnt\libntp\messages.h"
#endif
#if defined(SYS_VXWORKS)
#ifdef IPCOM_SYSLOG_FACILITY
#undef IPCOM_SYSLOG_FACILITY
#endif
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPNTP
#ifdef IPCOM_SYSLOG_PRIORITY
#undef IPCOM_SYSLOG_PRIORITY
#endif
#if defined(_WRS_CONFIG_IPNTP_SYSLOG_PRIORITY)
#define IPCOM_SYSLOG_PRIORITY _WRS_CONFIG_IPNTP_SYSLOG_PRIORITY
#else
#define IPCOM_SYSLOG_PRIORITY _WRS_CONFIG_IPCOM_DEFAULT_SYSLOG_PRIORITY
#endif
#define IPCOM_NTP_LOG(x,fm,a) \
do { if ((IPCOM_SYSLOG_PRIORITY >= x) && IPCOM_SYSLOG_ENABLE(x)) \
ipcom_syslog(IPCOM_SYSLOG_FACILITY | x, IPCOM_SYSLOG_BODY(fm),a); } while((0))
#endif
int syslogit = TRUE;
int msyslog_term = FALSE; /* duplicate to stdout/err */
int msyslog_term_pid = TRUE;
int msyslog_include_timestamp = TRUE;
FILE * syslog_file;
char * syslog_fname;
char * syslog_abs_fname;
/* libntp default ntp_syslogmask is all bits lit */
#define INIT_NTP_SYSLOGMASK ~(u_int32)0
u_int32 ntp_syslogmask = INIT_NTP_SYSLOGMASK;
extern char const * progname;
/* Declare the local functions */
void addto_syslog (int, const char *);
#ifndef VSNPRINTF_PERCENT_M
void format_errmsg (char *, size_t, const char *, int);
/* format_errmsg() is under #ifndef VSNPRINTF_PERCENT_M above */
void
format_errmsg(
char * nfmt,
size_t lennfmt,
const char * fmt,
int errval
)
{
char errmsg[256];
char c;
char *n;
const char *f;
size_t len;
n = nfmt;
f = fmt;
while ((c = *f++) != '\0' && n < (nfmt + lennfmt - 1)) {
if (c != '%') {
*n++ = c;
continue;
}
if ((c = *f++) != 'm') {
*n++ = '%';
if ('\0' == c)
break;
*n++ = c;
continue;
}
errno_to_str(errval, errmsg, sizeof(errmsg));
len = strlen(errmsg);
/* Make sure we have enough space for the error message */
if ((n + len) < (nfmt + lennfmt - 1)) {
memcpy(n, errmsg, len);
n += len;
}
}
*n = '\0';
}
#endif /* VSNPRINTF_PERCENT_M */
/*
* errno_to_str() - a thread-safe strerror() replacement.
* Hides the varied signatures of strerror_r().
* For Windows, we have:
* #define errno_to_str isc_strerror
*/
#ifndef errno_to_str
void
errno_to_str(
int err,
char * buf,
size_t bufsiz
)
{
# if defined(STRERROR_R_CHAR_P) || !HAVE_DECL_STRERROR_R
char * pstatic;
buf[0] = '\0';
# ifdef STRERROR_R_CHAR_P
pstatic = strerror_r(err, buf, bufsiz);
# else
pstatic = strerror(err);
# endif
if (NULL == pstatic && '\0' == buf[0])
snprintf(buf, bufsiz, "%s(%d): errno %d",
# ifdef STRERROR_R_CHAR_P
"strerror_r",
# else
"strerror",
# endif
err, errno);
/* protect against believing an int return is a pointer */
else if (pstatic != buf && pstatic > (char *)bufsiz)
strlcpy(buf, pstatic, bufsiz);
# else
int rc;
rc = strerror_r(err, buf, bufsiz);
if (rc < 0)
snprintf(buf, bufsiz, "strerror_r(%d): errno %d",
err, errno);
# endif
}
#endif /* errno_to_str */
/*
* addto_syslog()
* This routine adds the contents of a buffer to the syslog or an
* application-specific logfile.
*/
void
addto_syslog(
int level,
const char * msg
)
{
static char const * prevcall_progname;
static char const * prog;
const char nl[] = "\n";
const char empty[] = "";
FILE * term_file;
int log_to_term;
int log_to_file;
int pid;
const char * nl_or_empty;
const char * human_time;
/* setup program basename static var prog if needed */
if (progname != prevcall_progname) {
prevcall_progname = progname;
prog = strrchr(progname, DIR_SEP);
if (prog != NULL)
prog++;
else
prog = progname;
}
log_to_term = msyslog_term;
log_to_file = FALSE;
#if !defined(VMS) && defined(SYS_VXWORKS)
if (syslogit)
IPCOM_NTP_LOG(level, "%s", msg);
else
#endif
if (syslog_file != NULL)
log_to_file = TRUE;
else
log_to_term = TRUE;
#ifdef NTP_DEBUG
if (debug > 0)
log_to_term = TRUE;
#endif
if (!(log_to_file || log_to_term))
return;
/* syslog() adds the timestamp, name, and pid */
if (msyslog_include_timestamp)
human_time = humanlogtime();
else /* suppress gcc pot. uninit. warning */
human_time = NULL;
if (msyslog_term_pid || log_to_file)
pid = getpid();
else /* suppress gcc pot. uninit. warning */
pid = -1;
/* syslog() adds trailing \n if not present */
if ('\n' != msg[strlen(msg) - 1])
nl_or_empty = nl;
else
nl_or_empty = empty;
if (log_to_term) {
term_file = (level <= LOG_ERR)
? stderr
: stdout;
if (term_file)
{
if (msyslog_include_timestamp)
fprintf(term_file, "%s ", human_time);
if (msyslog_term_pid)
fprintf(term_file, "%s[%d]: ", prog, pid);
fprintf(term_file, "%s%s", msg, nl_or_empty);
#ifdef SYS_VXWORKS
(void) fprintf(term_file, "\n");
#endif
fflush(term_file);
}
}
if (log_to_file) {
if (msyslog_include_timestamp)
fprintf(syslog_file, "%s ", human_time);
fprintf(syslog_file, "%s[%d]: %s%s", prog, pid, msg,
nl_or_empty);
#ifdef SYS_VXWORKS
(void) fprintf(syslog_file, "\n");
#endif
fflush(syslog_file);
}
}
int
mvsnprintf(
char * buf,
size_t bufsiz,
const char * fmt,
va_list ap
)
{
#ifndef VSNPRINTF_PERCENT_M
char nfmt[256];
#else
const char * nfmt = fmt;
#endif
int errval;
/*
* Save the error value as soon as possible
*/
#ifdef SYS_WINNT
errval = GetLastError();
if (NO_ERROR == errval)
#endif /* SYS_WINNT */
errval = errno;
#ifndef VSNPRINTF_PERCENT_M
format_errmsg(nfmt, sizeof(nfmt), fmt, errval);
#else
errno = errval;
#endif
return vsnprintf(buf, bufsiz, nfmt, ap);
}
int
mvfprintf(
FILE * fp,
const char * fmt,
va_list ap
)
{
#ifndef VSNPRINTF_PERCENT_M
char nfmt[256];
#else
const char * nfmt = fmt;
#endif
int errval;
/*
* Save the error value as soon as possible
*/
#ifdef SYS_WINNT
errval = GetLastError();
if (NO_ERROR == errval)
#endif /* SYS_WINNT */
errval = errno;
#ifndef VSNPRINTF_PERCENT_M
format_errmsg(nfmt, sizeof(nfmt), fmt, errval);
#else
errno = errval;
#endif
if (fp)
return vfprintf(fp, nfmt, ap);
else
return 0;
}
int
mfprintf(
FILE * fp,
const char * fmt,
...
)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = mvfprintf(fp, fmt, ap);
va_end(ap);
return rc;
}
int
mprintf(
const char * fmt,
...
)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = mvfprintf(stdout, fmt, ap);
va_end(ap);
return rc;
}
int
msnprintf(
char * buf,
size_t bufsiz,
const char * fmt,
...
)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = mvsnprintf(buf, bufsiz, fmt, ap);
va_end(ap);
return rc;
}
void
msyslog(
int level,
const char * fmt,
...
)
{
char buf[1024];
va_list ap;
va_start(ap, fmt);
mvsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
addto_syslog(level, buf);
}
void
mvsyslog(
int level,
const char * fmt,
va_list ap
)
{
char buf[1024];
mvsnprintf(buf, sizeof(buf), fmt, ap);
addto_syslog(level, buf);
}
/*
* Initialize the logging
*
* Called once per process, including forked children.
*/
void
init_logging(
const char * name,
u_int32 def_syslogmask,
int is_daemon
)
{
static int was_daemon;
char * cp;
const char * pname;
syslogit = TRUE;
msyslog_term = FALSE;
msyslog_term_pid = TRUE;
msyslog_include_timestamp = TRUE;
syslog_file = NULL;
syslog_fname = NULL;
syslog_abs_fname = NULL;
ntp_syslogmask = INIT_NTP_SYSLOGMASK;
/*
* ntpd defaults to only logging sync-category events, when
* NLOG() is used to conditionalize. Other libntp clients
* leave it alone so that all NLOG() conditionals will fire.
* This presumes all bits lit in ntp_syslogmask can't be
* configured via logconfig and all lit is thereby a sentinel
* that ntp_syslogmask is still at its default from libntp,
* keeping in mind this function is called in forked children
* where it has already been called in the parent earlier.
* Forked children pass 0 for def_syslogmask.
*/
if (INIT_NTP_SYSLOGMASK == ntp_syslogmask &&
0 != def_syslogmask)
ntp_syslogmask = def_syslogmask; /* set more via logconfig */
/*
* Logging. This may actually work on the gizmo board. Find a name
* to log with by using the basename
*/
cp = strrchr(name, DIR_SEP);
if (NULL == cp)
pname = name;
else
pname = 1 + cp; /* skip DIR_SEP */
progname = estrdup(pname);
#ifdef SYS_WINNT /* strip ".exe" */
cp = strrchr(progname, '.');
if (NULL != cp && !strcasecmp(cp, ".exe"))
*cp = '\0';
#endif
#if !defined(VMS)
if (is_daemon)
was_daemon = TRUE;
# ifndef LOG_DAEMON
#ifndef SYS_VXWORKS
openlog(progname, LOG_PID);
#endif
# else /* LOG_DAEMON */
# ifndef LOG_NTP
# define LOG_NTP IPCOM_LOG_IPNTP
# endif
openlog(progname, LOG_PID | LOG_NDELAY, (was_daemon)
? LOG_NTP
: 0);
# ifdef NTP_DEBUG
if (debug)
ipcom_setlogmask_on(LOG_UPTO(LOG_DEBUG), IPCOM_LOG_IPNTP);
# endif /* NTP_DEBUG */
# endif /* LOG_DAEMON */
#endif /* !VMS */
}
/*
* change_logfile()
*
* Used to change from syslog to a logfile, or from one logfile to
* another, and to reopen logfiles after forking. On systems where
* ntpd forks, deals with converting relative logfile paths to
* absolute (root-based) because we reopen logfiles after the current
* directory has changed.
*/
int
change_logfile(
const char * fname,
int leave_crumbs
)
{
FILE * new_file;
const char * log_fname;
char * abs_fname;
#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
char curdir[512];
size_t cd_octets;
size_t octets;
#endif /* POSIX */
REQUIRE(fname != NULL);
log_fname = fname;
/*
* In a forked child of a parent which is logging to a file
* instead of syslog, syslog_file will be NULL and both
* syslog_fname and syslog_abs_fname will be non-NULL.
* If we are given the same filename previously opened
* and it's still open, there's nothing to do here.
*/
if (syslog_file != NULL && syslog_fname != NULL &&
0 == strcmp(syslog_fname, log_fname))
return 0;
if (0 == strcmp(log_fname, "stderr")) {
new_file = stderr;
abs_fname = estrdup(log_fname);
} else if (0 == strcmp(log_fname, "stdout")) {
new_file = stdout;
abs_fname = estrdup(log_fname);
} else {
if (syslog_fname != NULL &&
0 == strcmp(log_fname, syslog_fname))
log_fname = syslog_abs_fname;
#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
if (log_fname != syslog_abs_fname &&
DIR_SEP != log_fname[0] &&
0 != strcmp(log_fname, "stderr") &&
0 != strcmp(log_fname, "stdout") &&
NULL != getcwd(curdir, sizeof(curdir))) {
cd_octets = strlen(curdir);
/* trim any trailing '/' */
if (cd_octets > 1 &&
DIR_SEP == curdir[cd_octets - 1])
cd_octets--;
octets = cd_octets;
octets += 1; /* separator '/' */
octets += strlen(log_fname);
octets += 1; /* NUL terminator */
abs_fname = emalloc(octets);
snprintf(abs_fname, octets, "%.*s%c%s",
(int)cd_octets, curdir, DIR_SEP,
log_fname);
} else
#endif
abs_fname = estrdup(log_fname);
TRACE(1, ("attempting to open log %s\n", abs_fname));
new_file = fopen(abs_fname, "a");
}
if (NULL == new_file) {
efree(abs_fname);
return -1;
}
/* leave a pointer in the old log */
if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname))
msyslog(LOG_NOTICE, "switching logging to file %s",
abs_fname);
if (syslog_file != NULL &&
syslog_file != stderr && syslog_file != stdout &&
fileno(syslog_file) != fileno(new_file))
fclose(syslog_file);
syslog_file = new_file;
if (log_fname == syslog_abs_fname) {
efree(abs_fname);
} else {
if (syslog_abs_fname != NULL &&
syslog_abs_fname != syslog_fname)
efree(syslog_abs_fname);
if (syslog_fname != NULL)
efree(syslog_fname);
syslog_fname = estrdup(log_fname);
syslog_abs_fname = abs_fname;
}
syslogit = FALSE;
return 0;
}
/*
* setup_logfile()
*
* Redirect logging to a file if requested with -l/--logfile or via
* ntp.conf logfile directive.
*
* This routine is invoked three different times in the sequence of a
* typical daemon ntpd with DNS lookups to do. First it is invoked in
* the original ntpd process, then again in the daemon after closing
* all descriptors. In both of those cases, ntp.conf has not been
* processed, so only -l/--logfile will trigger logfile redirection in
* those invocations. Finally, if DNS names are resolved, the worker
* child invokes this routine after its fork and close of all
* descriptors. In this case, ntp.conf has been processed and any
* "logfile" directive needs to be honored in the child as well.
*/
void
setup_logfile(
const char * name
)
{
if (NULL == syslog_fname && NULL != name) {
if (-1 == change_logfile(name, TRUE))
msyslog(LOG_ERR, "Cannot open log file %s, %m",
name);
return ;
}
if (NULL == syslog_fname)
return;
if (-1 == change_logfile(syslog_fname, FALSE))
msyslog(LOG_ERR, "Cannot reopen log file %s, %m",
syslog_fname);
}
/* Helper for unit tests, where stdout + stderr are piped to the same
* stream. This works moderately reliable only if both streams are
* unbuffered or line buffered. Unfortunately stdout can be fully
* buffered on pipes or files...
*/
int
change_iobufs(
int how
)
{
int retv = 0;
# ifdef HAVE_SETVBUF
int mode;
switch (how) {
case 0 : mode = _IONBF; break; /* no buffering */
case 1 : mode = _IOLBF; break; /* line buffering */
case 2 : mode = _IOFBF; break; /* full buffering */
default: mode = _IOLBF; break; /* line buffering */
}
retv = 1;
if (setvbuf(stdout, NULL, mode, BUFSIZ) != 0)
retv = -1;
if (setvbuf(stderr, NULL, mode, BUFSIZ) != 0)
retv = -1;
# else
UNUSED_ARG(how);
# endif
return retv;
}
@@ -0,0 +1,56 @@
/*
* netof - return the net address part of an ip address in a sockaddr_storage structure
* (zero out host part)
*/
#include <ipntp_config.h>
#include "ipntp.h"
#include <stdio.h>
#include <syslog.h>
#include "ntp_fp.h"
#include "ntp_net.h"
#include "ntp_stdlib.h"
#include "ntp.h"
sockaddr_u *
netof(
sockaddr_u *hostaddr
)
{
static sockaddr_u netofbuf[8];
static int next_netofbuf;
u_int32 netnum;
sockaddr_u * netaddr;
netaddr = &netofbuf[next_netofbuf];
next_netofbuf = (next_netofbuf + 1) % COUNTOF(netofbuf);
memcpy(netaddr, hostaddr, sizeof(*netaddr));
if (IS_IPV4(netaddr)) {
netnum = SRCADR(netaddr);
/*
* We live in a modern CIDR world where the basement nets, which
* used to be class A, are now probably associated with each
* host address. So, for class-A nets, all bits are significant.
*/
if (IN_CLASSC(netnum))
netnum &= 0xffffff00;
else if (IN_CLASSB(netnum))
netnum &= 0xffff0000;
SET_ADDR4(netaddr, netnum);
} else if (IS_IPV6(netaddr))
/* assume the typical /64 subnet size */
zero_mem(&NSRCADR6(netaddr)[8], 8);
#ifdef NTP_DEBUG
else {
msyslog(LOG_ERR, "netof unknown AF %d", AF(netaddr));
ipntp_exit_callback(ipcom_getpid());
}
#endif
return netaddr;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,634 @@
/*
* ntp_calgps.c - calendar for GPS/GNSS based clocks
*
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
* The contents of 'html/copyright.html' apply.
*
* --------------------------------------------------------------------
*
* This module implements stuff often used with GPS/GNSS receivers
*/
#include <ipntp_config.h>
#include <sys/types.h>
#include "ntp_types.h"
#include "ntp_calendar.h"
#include "ntp_calgps.h"
#include "ntp_stdlib.h"
#include "ntp_unixtime.h"
#include "ntp_fp.h"
#include "ntpd.h"
#include "vint64ops.h"
/* ====================================================================
* misc. helpers -- might go elsewhere sometime?
* ====================================================================
*/
l_fp
ntpfp_with_fudge(
l_fp lfp,
double ofs
)
{
l_fp fpo;
/* calculate 'lfp - ofs' as '(l_fp)(-ofs) + lfp': negating a
* double is cheap, as it only flips one bit...
*/
ofs = -ofs;
DTOLFP(ofs, &fpo);
L_ADD(&fpo, &lfp);
return fpo;
}
/* ====================================================================
* GPS calendar functions
* ====================================================================
*/
/* --------------------------------------------------------------------
* normalization functions for day/time and week/time representations.
* Since we only use moderate offsets (leap second corrections and
* alike) it does not really pay off to do a floor-corrected division
* here. We use compare/decrement/increment loops instead.
* --------------------------------------------------------------------
*/
static void
_norm_ntp_datum(
TNtpDatum * datum
)
{
static const int32_t limit = SECSPERDAY;
if (datum->secs >= limit) {
do
++datum->days;
while ((datum->secs -= limit) >= limit);
} else if (datum->secs < 0) {
do
--datum->days;
while ((datum->secs += limit) < 0);
}
}
static void
_norm_gps_datum(
TGpsDatum * datum
)
{
static const int32_t limit = 7 * SECSPERDAY;
if (datum->wsecs >= limit) {
do
++datum->weeks;
while ((datum->wsecs -= limit) >= limit);
} else if (datum->wsecs < 0) {
do
--datum->weeks;
while ((datum->wsecs += limit) < 0);
}
}
/* --------------------------------------------------------------------
* Add an offset to a day/time and week/time representation.
*
* !!Attention!! the offset should be small, compared to the time period
* (either a day or a week).
* --------------------------------------------------------------------
*/
void
gpsntp_add_offset(
TNtpDatum * datum,
l_fp offset
)
{
/* fraction can be added easily */
datum->frac += offset.l_uf;
datum->secs += (datum->frac < offset.l_uf);
/* avoid integer overflow on the seconds */
if (offset.l_ui >= INT32_MAX)
datum->secs -= (int32_t)~offset.l_ui + 1;
else
datum->secs += (int32_t)offset.l_ui;
_norm_ntp_datum(datum);
}
void
gpscal_add_offset(
TGpsDatum * datum,
l_fp offset
)
{
/* fraction can be added easily */
datum->frac += offset.l_uf;
datum->wsecs += (datum->frac < offset.l_uf);
/* avoid integer overflow on the seconds */
if (offset.l_ui >= INT32_MAX)
datum->wsecs -= (int32_t)~offset.l_ui + 1;
else
datum->wsecs += (int32_t)offset.l_ui;
_norm_gps_datum(datum);
}
/* -------------------------------------------------------------------
* API functions civil calendar and NTP datum
* -------------------------------------------------------------------
*/
static TNtpDatum
_gpsntp_fix_gps_era(
TcNtpDatum * in
)
{
/* force result in basedate era
*
* When calculating this directly in days, we have to execute a
* real modulus calculation, since we're obviously not doing a
* modulus by a power of 2. Executing this as true floor mod
* needs some care and is done under explicit usage of one's
* complement and masking to get mostly branchless code.
*/
static uint32_t const clen = 7*1024;
uint32_t base, days, sign;
TNtpDatum out = *in;
/* Get base in NTP day scale. No overflows here. */
base = (basedate_get_gpsweek() + GPSNTP_WSHIFT) * 7
- GPSNTP_DSHIFT;
days = out.days;
sign = (uint32_t)-(days < base);
days = sign ^ (days - base);
days %= clen;
days = base + (sign & clen) + (sign ^ days);
out.days = days;
return out;
}
TNtpDatum
gpsntp_fix_gps_era(
TcNtpDatum * in
)
{
TNtpDatum out = *in;
_norm_ntp_datum(&out);
return _gpsntp_fix_gps_era(&out);
}
/* ----------------------------------------------------------------- */
static TNtpDatum
_gpsntp_from_daytime(
TcCivilDate * jd,
l_fp fofs,
TcNtpDatum * pivot,
int warp
)
{
static const int32_t shift = SECSPERDAY / 2;
TNtpDatum retv;
/* set result based on pivot -- ops order is important here */
ZERO(retv);
retv.secs = ntpcal_date_to_daysec(jd);
gpsntp_add_offset(&retv, fofs); /* result is normalized */
retv.days = pivot->days;
/* Manual periodic extension without division: */
if (pivot->secs < shift) {
int32_t lim = pivot->secs + shift;
retv.days -= (retv.secs > lim ||
(retv.secs == lim && retv.frac >= pivot->frac));
} else {
int32_t lim = pivot->secs - shift;
retv.days += (retv.secs < lim ||
(retv.secs == lim && retv.frac < pivot->frac));
}
return warp ? _gpsntp_fix_gps_era(&retv) : retv;
}
/* -----------------------------------------------------------------
* Given the time-of-day part of a civil datum and an additional
* (fractional) offset, calculate a full time stamp around a given pivot
* time so that the difference between the pivot and the resulting time
* stamp is less or equal to 12 hours absolute.
*/
TNtpDatum
gpsntp_from_daytime2_ex(
TcCivilDate * jd,
l_fp fofs,
TcNtpDatum * pivot,
int/*BOOL*/ warp
)
{
TNtpDatum dpiv = *pivot;
_norm_ntp_datum(&dpiv);
return _gpsntp_from_daytime(jd, fofs, &dpiv, warp);
}
/* -----------------------------------------------------------------
* This works similar to 'gpsntp_from_daytime1()' and actually even uses
* it, but the pivot is calculated from the pivot given as 'l_fp' in NTP
* time scale. This is in turn expanded around the current system time,
* and the resulting absolute pivot is then used to calculate the full
* NTP time stamp.
*/
TNtpDatum
gpsntp_from_daytime1_ex(
TcCivilDate * jd,
l_fp fofs,
l_fp pivot,
int/*BOOL*/ warp
)
{
vint64 pvi64;
TNtpDatum dpiv;
ntpcal_split split;
pvi64 = ntpcal_ntp_to_ntp(pivot.l_ui, NULL);
split = ntpcal_daysplit(&pvi64);
dpiv.days = split.hi;
dpiv.secs = split.lo;
dpiv.frac = pivot.l_uf;
return _gpsntp_from_daytime(jd, fofs, &dpiv, warp);
}
/* -----------------------------------------------------------------
* Given a calendar date, zap it into a GPS time format and then convert
* that one into the NTP time scale.
*/
TNtpDatum
gpsntp_from_calendar_ex(
TcCivilDate * jd,
l_fp fofs,
int/*BOOL*/ warp
)
{
TGpsDatum gps;
gps = gpscal_from_calendar_ex(jd, fofs, warp);
return gpsntp_from_gpscal_ex(&gps, FALSE);
}
/* -----------------------------------------------------------------
* create a civil calendar datum from a NTP date representation
*/
void
gpsntp_to_calendar(
TCivilDate * cd,
TcNtpDatum * nd
)
{
memset(cd, 0, sizeof(*cd));
ntpcal_rd_to_date(
cd,
nd->days + DAY_NTP_STARTS + ntpcal_daysec_to_date(
cd, nd->secs));
}
/* -----------------------------------------------------------------
* get day/tod representation from week/tow datum
*/
TNtpDatum
gpsntp_from_gpscal_ex(
TcGpsDatum * gd,
int/*BOOL*/ warp
)
{
TNtpDatum retv;
vint64 ts64;
ntpcal_split split;
TGpsDatum date = *gd;
if (warp) {
uint32_t base = basedate_get_gpsweek() + GPSNTP_WSHIFT;
_norm_gps_datum(&date);
date.weeks = ((date.weeks - base) & 1023u) + base;
}
ts64 = ntpcal_weekjoin(date.weeks, date.wsecs);
ts64 = subv64u32(&ts64, (GPSNTP_DSHIFT * SECSPERDAY));
split = ntpcal_daysplit(&ts64);
retv.frac = gd->frac;
retv.secs = split.lo;
retv.days = split.hi;
return retv;
}
/* -----------------------------------------------------------------
* get LFP from ntp datum
*/
l_fp
ntpfp_from_ntpdatum(
TcNtpDatum * nd
)
{
l_fp retv;
retv.l_uf = nd->frac;
retv.l_ui = nd->days * (uint32_t)SECSPERDAY
+ nd->secs;
return retv;
}
/* -------------------------------------------------------------------
* API functions GPS week calendar
*
* Here we use a calendar base of 1899-12-31, so the NTP epoch has
* { 0, 86400.0 } in this representation.
* -------------------------------------------------------------------
*/
static TGpsDatum
_gpscal_fix_gps_era(
TcGpsDatum * in
)
{
/* force result in basedate era
*
* This is based on calculating the modulus to a power of two,
* so signed integer overflow does not affect the result. Which
* in turn makes for a very compact calculation...
*/
uint32_t base, week;
TGpsDatum out = *in;
week = out.weeks;
base = basedate_get_gpsweek() + GPSNTP_WSHIFT;
week = base + ((week - base) & (GPSWEEKS - 1));
out.weeks = week;
return out;
}
TGpsDatum
gpscal_fix_gps_era(
TcGpsDatum * in
)
{
TGpsDatum out = *in;
_norm_gps_datum(&out);
return _gpscal_fix_gps_era(&out);
}
/* -----------------------------------------------------------------
* Given a calendar date, zap it into a GPS time format and the do a
* proper era mapping in the GPS time scale, based on the GPS base date,
* if so requested.
*
* This function also augments the century if just a 2-digit year
* (0..99) is provided on input.
*
* This is a fail-safe against GPS receivers with an unknown starting
* point for their internal calendar calculation and therefore
* unpredictable (but reproducible!) rollover behavior. While there
* *are* receivers that create a full date in the proper way, many
* others just don't. The overall damage is minimized by simply not
* trusting the era mapping of the receiver and doing the era assignment
* with a configurable base date *inside* ntpd.
*/
TGpsDatum
gpscal_from_calendar_ex(
TcCivilDate * jd,
l_fp fofs,
int/*BOOL*/ warp
)
{
/* (-DAY_GPS_STARTS) (mod 7*1024) -- complement of cycle shift */
static const uint32_t s_compl_shift =
(7 * 1024) - DAY_GPS_STARTS % (7 * 1024);
TGpsDatum gps;
TCivilDate cal;
int32_t days, week;
/* if needed, convert from 2-digit year to full year
* !!NOTE!! works only between 1980 and 2079!
*/
cal = *jd;
if (cal.year < 80)
cal.year += 2000;
else if (cal.year < 100)
cal.year += 1900;
/* get RDN from date, possibly adjusting the century */
again: if (cal.month && cal.monthday) { /* use Y/M/D civil date */
days = ntpcal_date_to_rd(&cal);
} else { /* using Y/DoY date */
days = ntpcal_year_to_ystart(cal.year)
+ (int32_t)cal.yearday
- 1; /* both RDN and yearday start with '1'. */
}
/* Rebase to days after the GPS epoch. 'days' is positive here,
* but it might be less than the GPS epoch start. Depending on
* the input, we have to do different things to get the desired
* result. (Since we want to remap the era anyway, we only have
* to retain congruential identities....)
*/
if (days >= DAY_GPS_STARTS) {
/* simply shift to days since GPS epoch */
days -= DAY_GPS_STARTS;
} else if (jd->year < 100) {
/* Two-digit year on input: add another century and
* retry. This can happen only if the century expansion
* yielded a date between 1980-01-01 and 1980-01-05,
* both inclusive. We have at most one retry here.
*/
cal.year += 100;
goto again;
} else {
/* A very bad date before the GPS epoch. There's not
* much we can do, except to add the complement of
* DAY_GPS_STARTS % (7 * 1024) here, that is, use a
* congruential identity: Add the complement instead of
* subtracting the value gives a value with the same
* modulus. But of course, now we MUST to go through a
* cycle fix... because the date was obviously wrong!
*/
warp = TRUE;
days += s_compl_shift;
}
/* Splitting to weeks is simple now: */
week = days / 7;
days -= week * 7;
/* re-base on start of NTP with weeks mapped to 1024 weeks
* starting with the GPS base day set in the calendar.
*/
gps.weeks = week + GPSNTP_WSHIFT;
gps.wsecs = days * SECSPERDAY + ntpcal_date_to_daysec(&cal);
gps.frac = 0;
gpscal_add_offset(&gps, fofs);
return warp ? _gpscal_fix_gps_era(&gps) : gps;
}
/* -----------------------------------------------------------------
* get civil date from week/tow representation
*/
void
gpscal_to_calendar(
TCivilDate * cd,
TcGpsDatum * wd
)
{
TNtpDatum nd;
memset(cd, 0, sizeof(*cd));
nd = gpsntp_from_gpscal_ex(wd, FALSE);
gpsntp_to_calendar(cd, &nd);
}
/* -----------------------------------------------------------------
* Given the week and seconds in week, as well as the fraction/offset
* (which should/could include the leap seconds offset), unfold the
* weeks (which are assumed to have just 10 bits) into expanded weeks
* based on the GPS base date derived from the build date (default) or
* set by the configuration.
*
* !NOTE! This function takes RAW GPS weeks, aligned to the GPS start
* (1980-01-06) on input. The output weeks will be aligned to NTPD's
* week calendar start (1899-12-31)!
*/
TGpsDatum
gpscal_from_gpsweek(
uint16_t week,
int32_t secs,
l_fp fofs
)
{
TGpsDatum retv;
retv.frac = 0;
retv.wsecs = secs;
retv.weeks = week + GPSNTP_WSHIFT;
gpscal_add_offset(&retv, fofs);
return _gpscal_fix_gps_era(&retv);
}
/* -----------------------------------------------------------------
* internal work horse for time-of-week expansion
*/
static TGpsDatum
_gpscal_from_weektime(
int32_t wsecs,
l_fp fofs,
TcGpsDatum * pivot
)
{
static const int32_t shift = SECSPERWEEK / 2;
TGpsDatum retv;
/* set result based on pivot -- ops order is important here */
ZERO(retv);
retv.wsecs = wsecs;
gpscal_add_offset(&retv, fofs); /* result is normalized */
retv.weeks = pivot->weeks;
/* Manual periodic extension without division: */
if (pivot->wsecs < shift) {
int32_t lim = pivot->wsecs + shift;
retv.weeks -= (retv.wsecs > lim ||
(retv.wsecs == lim && retv.frac >= pivot->frac));
} else {
int32_t lim = pivot->wsecs - shift;
retv.weeks += (retv.wsecs < lim ||
(retv.wsecs == lim && retv.frac < pivot->frac));
}
return _gpscal_fix_gps_era(&retv);
}
/* -----------------------------------------------------------------
* expand a time-of-week around a pivot given as week datum
*/
TGpsDatum
gpscal_from_weektime2(
int32_t wsecs,
l_fp fofs,
TcGpsDatum * pivot
)
{
TGpsDatum wpiv = * pivot;
_norm_gps_datum(&wpiv);
return _gpscal_from_weektime(wsecs, fofs, &wpiv);
}
/* -----------------------------------------------------------------
* epand a time-of-week around an pivot given as LFP, which in turn
* is expanded around the current system time and then converted
* into a week datum.
*/
TGpsDatum
gpscal_from_weektime1(
int32_t wsecs,
l_fp fofs,
l_fp pivot
)
{
vint64 pvi64;
TGpsDatum wpiv;
ntpcal_split split;
/* get 64-bit pivot in NTP epoch */
pvi64 = ntpcal_ntp_to_ntp(pivot.l_ui, NULL);
/* convert to weeks since 1899-12-31 and seconds in week */
pvi64 = addv64u32(&pvi64, (GPSNTP_DSHIFT * SECSPERDAY));
split = ntpcal_weeksplit(&pvi64);
wpiv.weeks = split.hi;
wpiv.wsecs = split.lo;
wpiv.frac = pivot.l_uf;
return _gpscal_from_weektime(wsecs, fofs, &wpiv);
}
/* -----------------------------------------------------------------
* get week/tow representation from day/tod datum
*/
TGpsDatum
gpscal_from_gpsntp(
TcNtpDatum * gd
)
{
TGpsDatum retv;
vint64 ts64;
ntpcal_split split;
ts64 = ntpcal_dayjoin(gd->days, gd->secs);
ts64 = addv64u32(&ts64, (GPSNTP_DSHIFT * SECSPERDAY));
split = ntpcal_weeksplit(&ts64);
retv.frac = gd->frac;
retv.wsecs = split.lo;
retv.weeks = split.hi;
return retv;
}
/* -----------------------------------------------------------------
* convert week/tow to LFP stamp
*/
l_fp
ntpfp_from_gpsdatum(
TcGpsDatum * gd
)
{
l_fp retv;
retv.l_uf = gd->frac;
retv.l_ui = gd->weeks * (uint32_t)SECSPERWEEK
+ (uint32_t)gd->wsecs
- (uint32_t)SECSPERDAY * GPSNTP_DSHIFT;
return retv;
}
/* -*-EOF-*- */
@@ -0,0 +1,119 @@
/*
* Crypto-quality random number functions
*
* Author: Harlan Stenn, 2014
*
* This file is Copyright (c) 2014 by Network Time Foundation.
* BSD terms apply: see the file COPYRIGHT in the distribution root for details.
*/
#include "ipntp_config.h"
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdio.h>
#include <l_stdlib.h>
#include <ntp_random.h>
#include "safecast.h"
#ifdef USE_OPENSSL_CRYPTO_RAND
#include <openssl/err.h>
#include <openssl/rand.h>
int crypto_rand_init = 0;
#else
# ifndef HAVE_ARC4RANDOM_BUF
void
evutil_secure_rng_get_bytes(void *buf, size_t nbytes);
#ifndef SYS_VXWORKS
static void
arc4random_buf(void *buf, size_t nbytes);
static void
arc4random_buf(void *buf, size_t nbytes)
{
evutil_secure_rng_get_bytes(buf, nbytes);
return;
}
# endif
#endif
#endif
/*
* As of late 2014, here's how we plan to provide cryptographic-quality
* random numbers:
*
* - If we are building with OpenSSL, use RAND_poll() and RAND_bytes().
* - Otherwise, use arc4random().
*
* Use of arc4random() can be forced using configure --disable-openssl-random
*
* We can count on arc4random existing, thru the OS or thru libevent.
* The quality of arc4random depends on the implementor.
*
* RAND_poll() doesn't show up until XXX. If it's not present, we
* need to either provide our own or use arc4random().
*/
/*
* ntp_crypto_srandom:
*
* Initialize the random number generator, if needed by the underlying
* crypto random number generation mechanism.
*/
void
ntp_crypto_srandom(
void
)
{
#ifdef USE_OPENSSL_CRYPTO_RAND
if (!crypto_rand_init) {
RAND_poll();
crypto_rand_init = 1;
}
#else
/* No initialization needed for arc4random() */
#endif
}
/*
* ntp_crypto_random_buf:
*
* Returns 0 on success, -1 on error.
*/
int
ntp_crypto_random_buf(
void *buf,
size_t nbytes
)
{
#ifdef USE_OPENSSL_CRYPTO_RAND
int rc;
rc = RAND_bytes(buf, size2int_chk(nbytes));
if (1 != rc) {
unsigned long err;
char *err_str;
err = ERR_get_error();
err_str = ERR_error_string(err, NULL);
/* XXX: Log the error */
(void)&err_str;
return -1;
}
return 0;
#else
#ifndef SYS_VXWORKS
arc4random_buf(buf, nbytes);
#endif
return 0;
#endif
}
@@ -0,0 +1,119 @@
/*
* getopt - get option letter from argv
*
* This is a version of the public domain getopt() implementation by
* Henry Spencer, changed for 4.3BSD compatibility (in addition to System V).
* It allows rescanning of an option list by setting optind to 0 before
* calling, which is why we use it even if the system has its own (in fact,
* this one has a unique name so as not to conflict with the system's).
* Thanks to Dennis Ferguson for the appropriate modifications.
*
* This file is in the Public Domain.
*/
/*LINTLIBRARY*/
#include <ipntp_config.h>
#include <stdio.h>
#include "ntp_stdlib.h"
#ifdef lint
#undef putc
#define putc fputc
#endif /* lint */
char *ntp_optarg; /* Global argument pointer. */
int ntp_optind = 0; /* Global argv index. */
int ntp_opterr = 1; /* for compatibility, should error be printed? */
int ntp_optopt; /* for compatibility, option character checked */
static char *scan = NULL; /* Private scan pointer. */
static const char *prog = "amnesia";
void clear_opt(void)
{
ntp_optarg = NULL;
ntp_optind = 0;
ntp_opterr = 1;
ntp_optopt = 0;
scan = NULL;
}
/*
* Print message about a bad option.
*/
static int
badopt(
const char *mess,
int ch
)
{
if (ntp_opterr) {
fputs(prog, stderr);
fputs(mess, stderr);
(void) putc(ch, stderr);
(void) putc('\n', stderr);
}
return ('?');
}
int
ntp_getopt(
int argc,
char *argv[],
const char *optstring
)
{
register char c;
register const char *place;
prog = argv[0];
ntp_optarg = NULL;
if (ntp_optind == 0) {
scan = NULL;
ntp_optind++;
}
if (scan == NULL || *scan == '\0') {
if (ntp_optind >= argc
|| argv[ntp_optind][0] != '-'
|| argv[ntp_optind][1] == '\0') {
return (EOF);
}
if (argv[ntp_optind][1] == '-'
&& argv[ntp_optind][2] == '\0') {
ntp_optind++;
return (EOF);
}
scan = argv[ntp_optind++]+1;
}
c = *scan++;
ntp_optopt = c & 0377;
for (place = optstring; place != NULL && *place != '\0'; ++place)
if (*place == c)
break;
if (place == NULL || *place == '\0' || c == ':' || c == '?') {
return (badopt(": unknown option -", c));
}
place++;
if (*place == ':') {
if (*scan != '\0') {
ntp_optarg = scan;
scan = NULL;
} else if (ntp_optind >= argc) {
return (badopt(": option requires argument -", c));
} else {
ntp_optarg = argv[ntp_optind++];
}
}
return (c & 0377);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,58 @@
/*
* ntp_libopts.c
*
* Common code interfacing with Autogen's libopts command-line option
* processing.
*/
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#include <stdio.h>
#include <stddef.h>
#include "ntp_libopts.h"
#include "ntp_stdlib.h"
extern const char *Version; /* version.c for each program */
/*
* ntpOptionProcess() was a clone of libopts' optionProcess which
* overrode the --version output, appending detail from version.c
* which was not available at Autogen time. This is now done via
* AutoOpts' version-proc = override in copyright.def, so this
* routine is a straightforward wrapper of optionProcess().
*/
int
ntpOptionProcess(
tOptions * pOpts,
int argc,
char ** argv
)
{
return optionProcess(pOpts, argc, argv);
}
/*
* ntpOptionPrintVersion() replaces the stock optionPrintVersion() via
* version-proc = ntpOptionPrintVersion; in copyright.def. It differs
* from the stock function by displaying the complete version string,
* including compile time which was unknown when Autogen ran.
*
* Like optionPrintVersion() this function must exit(0) rather than
* return.
*/
void
ntpOptionPrintVersion(
tOptions * pOpts,
tOptDesc * pOD
)
{
UNUSED_ARG(pOpts);
UNUSED_ARG(pOD);
printf("%s\n", Version);
fflush(stdout);
ipntp_exit_callback(ipcom_getpid());
}
@@ -0,0 +1,248 @@
/*
* ntp_lineedit.c - generic interface to various line editing libs
*/
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "ntp_mem.h"
#if defined(HAVE_READLINE_HISTORY) && \
(!defined(HAVE_READLINE_HISTORY_H) || \
!defined(HAVE_READLINE_READLINE_H))
# undef HAVE_READLINE_HISTORY
#endif
#if defined(HAVE_READLINE_HISTORY)
# include <readline/readline.h>
# include <readline/history.h>
# define LE_READLINE
#elif defined(HAVE_HISTEDIT_H)
# include <histedit.h>
# define LE_EDITLINE
#else
# define LE_NONE
#endif
#include "ntp.h"
#include "ntp_stdlib.h"
#include "ntp_lineedit.h"
#include "safecast.h"
#define MAXEDITLINE 512
/*
* external references
*/
extern char const * progname;
/*
* globals, private prototypes
*/
static int ntp_readline_initted;
static char * lineedit_prompt;
#ifdef LE_EDITLINE
# ifndef H_SETSIZE
# define H_SETSIZE H_EVENT
# endif
static EditLine * ntp_el;
static History * ntp_hist;
static HistEvent hev;
char * ntp_prompt_callback(EditLine *);
#endif /* LE_EDITLINE */
/*
* ntp_readline_init - setup, set or reset prompt string
*/
int
ntp_readline_init(
const char * prompt
)
{
int success;
success = 1;
if (prompt) {
if (lineedit_prompt)
efree((void *)lineedit_prompt);
lineedit_prompt = estrdup(prompt);
}
#ifdef LE_EDITLINE
if (NULL == ntp_el) {
# if 4 == EL_INIT_ARGS
ntp_el = el_init(progname, stdin, stdout, stderr);
# else
ntp_el = el_init(progname, stdin, stdout);
# endif
if (ntp_el) {
el_set(ntp_el, EL_PROMPT, ntp_prompt_callback);
el_set(ntp_el, EL_EDITOR, "emacs");
ntp_hist = history_init();
if (NULL == ntp_hist) {
mfprintf(stderr, "history_init(): %m\n");
fflush(stderr);
el_end(ntp_el);
ntp_el = NULL;
success = 0;
} else {
ZERO(hev);
#ifdef H_SETSIZE
history(ntp_hist, &hev, H_SETSIZE, 128);
#endif
el_set(ntp_el, EL_HIST, history,
ntp_hist);
/* use any .editrc */
el_source(ntp_el, NULL);
}
} else
success = 0;
}
#endif /* LE_EDITLINE */
ntp_readline_initted = success;
return success;
}
/*
* ntp_readline_uninit - release resources
*/
void
ntp_readline_uninit(
void
)
{
#ifdef LE_EDITLINE
if (ntp_el) {
el_end(ntp_el);
ntp_el = NULL;
history_end(ntp_hist);
ntp_hist = NULL;
}
#endif /* LE_EDITLINE */
if (lineedit_prompt) {
efree(lineedit_prompt);
lineedit_prompt = NULL;
}
ntp_readline_initted = 0;
}
/*
* ntp_readline - read a line with the line editor available
*
* The string returned must be released with free()
*/
char *
ntp_readline(
int * pcount
)
{
char * line;
#ifdef LE_NONE
char line_buf[MAXEDITLINE];
#endif
#ifdef LE_EDITLINE
const char * cline;
#endif
if (!ntp_readline_initted)
return NULL;
*pcount = 0;
#ifdef LE_READLINE
line = readline(lineedit_prompt ? lineedit_prompt : "");
if (NULL != line) {
if (*line) {
add_history(line);
}
*pcount = strlen(line);
}
#endif /* LE_READLINE */
#ifdef LE_EDITLINE
cline = el_gets(ntp_el, pcount);
if (NULL != cline && *cline) {
history(ntp_hist, &hev, H_ENTER, cline);
*pcount = strlen(cline);
line = estrdup(cline);
} else if (*pcount == -1) {
line = NULL;
} else {
line = estrdup("");
}
#endif /* LE_EDITLINE */
#ifdef LE_NONE
/* stone hammers */
if (lineedit_prompt) {
# ifdef VMS
/*
* work around problem mixing
* stdout & stderr
*/
fputs("", stdout);
# endif /* VMS */
fputs(lineedit_prompt, stderr);
fflush(stderr);
}
line = fgets(line_buf, sizeof(line_buf), stdin);
if (NULL != line && *line) {
*pcount = (int)strlen(line); /* cannot overflow here */
line = estrdup(line);
} else
line = NULL;
#endif /* LE_NONE */
if (!line) /* EOF */
fputs("\n", stderr);
return line;
}
#ifdef LE_EDITLINE
/*
* ntp_prompt_callback - return prompt string to el_gets()
*/
char *
ntp_prompt_callback(
EditLine *el
)
{
UNUSED_ARG(el);
return lineedit_prompt;
}
#endif /* LE_EDITLINE */
@@ -0,0 +1,310 @@
/*
* Copyright (c) 1987, 1989 Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Arthur David Olson of the National Cancer Institute.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. */
/*static char *sccsid = "from: @(#)ctime.c 5.26 (Berkeley) 2/23/91";*/
/*
* This implementation of mktime is lifted straight from the NetBSD (BSD 4.4)
* version. I modified it slightly to divorce it from the internals of the
* ctime library. Thus this version can't use details of the internal
* timezone state file to figure out strange unnormalized struct tm values,
* as might result from someone doing date math on the tm struct then passing
* it to mktime.
*
* It just does as well as it can at normalizing the tm input, then does a
* binary search of the time space using the system's localtime() function.
*
* The original binary search was defective in that it didn't consider the
* setting of tm_isdst when comparing tm values, causing the search to be
* flubbed for times near the dst/standard time changeover. The original
* code seems to make up for this by grubbing through the timezone info
* whenever the binary search barfed. Since I don't have that luxury in
* portable code, I have to take care of tm_isdst in the comparison routine.
* This requires knowing how many minutes offset dst is from standard time.
*
* So, if you live somewhere in the world where dst is not 60 minutes offset,
* and your vendor doesn't supply mktime(), you'll have to edit this variable
* by hand. Sorry about that.
*/
#include <ipntp_config.h>
#include "ntp_machine.h"
#if !defined(HAVE_MKTIME) || ( !defined(HAVE_TIMEGM) && defined(WANT_TIMEGM) )
#if SIZEOF_TIME_T >= 8
#error libntp supplied mktime()/timegm() do not support 64-bit time_t
#endif
#ifndef DSTMINUTES
#define DSTMINUTES 60
#endif
#define FALSE 0
#define TRUE 1
/* some constants from tzfile.h */
#define SECSPERMIN 60
#define MINSPERHOUR 60
#define HOURSPERDAY 24
#define DAYSPERWEEK 7
#define DAYSPERNYEAR 365
#define DAYSPERLYEAR 366
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
#define MONSPERYEAR 12
#define TM_YEAR_BASE 1900
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
static int mon_lengths[2][MONSPERYEAR] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
static int year_lengths[2] = {
DAYSPERNYEAR, DAYSPERLYEAR
};
/*
** Adapted from code provided by Robert Elz, who writes:
** The "best" way to do mktime I think is based on an idea of Bob
** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
** It does a binary search of the time_t space. Since time_t's are
** just 32 bits, its a max of 32 iterations (even at 64 bits it
** would still be very reasonable).
*/
#ifndef WRONG
#define WRONG (-1)
#endif /* !defined WRONG */
static void
normalize(
int * tensptr,
int * unitsptr,
int base
)
{
if (*unitsptr >= base) {
*tensptr += *unitsptr / base;
*unitsptr %= base;
} else if (*unitsptr < 0) {
--*tensptr;
*unitsptr += base;
if (*unitsptr < 0) {
*tensptr -= 1 + (-*unitsptr) / base;
*unitsptr = base - (-*unitsptr) % base;
}
}
}
static struct tm *
mkdst(
struct tm * tmp
)
{
/* jds */
static struct tm tmbuf;
tmbuf = *tmp;
tmbuf.tm_isdst = 1;
tmbuf.tm_min += DSTMINUTES;
normalize(&tmbuf.tm_hour, &tmbuf.tm_min, MINSPERHOUR);
return &tmbuf;
}
static int
tmcomp(
register struct tm * atmp,
register struct tm * btmp
)
{
register int result;
/* compare down to the same day */
if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
(result = (atmp->tm_mon - btmp->tm_mon)) == 0)
result = (atmp->tm_mday - btmp->tm_mday);
if(result != 0)
return result;
/* get rid of one-sided dst bias */
if(atmp->tm_isdst == 1 && !btmp->tm_isdst)
btmp = mkdst(btmp);
else if(btmp->tm_isdst == 1 && !atmp->tm_isdst)
atmp = mkdst(atmp);
/* compare the rest of the way */
if ((result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
(result = (atmp->tm_min - btmp->tm_min)) == 0)
result = atmp->tm_sec - btmp->tm_sec;
return result;
}
static time_t
time2(
struct tm * tmp,
int * okayp,
int usezn
)
{
register int dir;
register int bits;
register int i;
register int saved_seconds;
time_t t;
struct tm yourtm, mytm;
*okayp = FALSE;
yourtm = *tmp;
if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
while (yourtm.tm_mday <= 0) {
--yourtm.tm_year;
yourtm.tm_mday +=
year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
}
for ( ; ; ) {
i = mon_lengths[isleap(yourtm.tm_year +
TM_YEAR_BASE)][yourtm.tm_mon];
if (yourtm.tm_mday <= i)
break;
yourtm.tm_mday -= i;
if (++yourtm.tm_mon >= MONSPERYEAR) {
yourtm.tm_mon = 0;
++yourtm.tm_year;
}
}
saved_seconds = yourtm.tm_sec;
yourtm.tm_sec = 0;
/*
** Calculate the number of magnitude bits in a time_t
** (this works regardless of whether time_t is
** signed or unsigned, though lint complains if unsigned).
*/
for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
;
/*
** If time_t is signed, then 0 is the median value,
** if time_t is unsigned, then 1 << bits is median.
*/
t = (t < 0) ? 0 : ((time_t) 1 << bits);
for ( ; ; ) {
if (usezn)
mytm = *localtime(&t);
else
mytm = *gmtime(&t);
dir = tmcomp(&mytm, &yourtm);
if (dir != 0) {
if (bits-- < 0)
return WRONG;
if (bits < 0)
--t;
else if (dir > 0)
t -= (time_t) 1 << bits;
else t += (time_t) 1 << bits;
continue;
}
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
break;
return WRONG;
}
t += saved_seconds;
if (usezn)
*tmp = *localtime(&t);
else
*tmp = *gmtime(&t);
*okayp = TRUE;
return t;
}
#else
int mktime_bs;
#endif /* !HAVE_MKTIME || !HAVE_TIMEGM */
#ifndef HAVE_MKTIME
static time_t
time1(
struct tm * tmp
)
{
register time_t t;
int okay;
if (tmp->tm_isdst > 1)
tmp->tm_isdst = 1;
t = time2(tmp, &okay, 1);
if (okay || tmp->tm_isdst < 0)
return t;
return WRONG;
}
time_t
mktime(
struct tm * tmp
)
{
return time1(tmp);
}
#endif /* !HAVE_MKTIME */
#ifdef WANT_TIMEGM
#ifndef HAVE_TIMEGM
time_t
timegm(
struct tm * tmp
)
{
register time_t t;
int okay;
tmp->tm_isdst = 0;
t = time2(tmp, &okay, 0);
if (okay || tmp->tm_isdst < 0)
return t;
return WRONG;
}
#endif /* !HAVE_TIMEGM */
#endif /* WANT_TIMEGM */
@@ -0,0 +1,517 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/lib/libc/stdlib/random.c,v 1.4.2.2 1999/09/05 11:16:45 peter Exp $
*
*/
#include "ipntp_config.h"
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <l_stdlib.h>
#include <ntp_random.h>
#include <ntp_unixtime.h>
/*
* random.c:
*
* An improved random number generation package. In addition to the standard
* rand()/srand() like interface, this package also has a special state info
* interface. The initstate() routine is called with a seed, an array of
* bytes, and a count of how many bytes are being passed in; this array is
* then initialized to contain information for random number generation with
* that much state information. Good sizes for the amount of state
* information are 32, 64, 128, and 256 bytes. The state can be switched by
* calling the setstate() routine with the same array as was initiallized
* with initstate(). By default, the package runs with 128 bytes of state
* information and generates far better random numbers than a linear
* congruential generator. If the amount of state information is less than
* 32 bytes, a simple linear congruential R.N.G. is used.
*
* Internally, the state information is treated as an array of longs; the
* zeroeth element of the array is the type of R.N.G. being used (small
* integer); the remainder of the array is the state information for the
* R.N.G. Thus, 32 bytes of state information will give 7 longs worth of
* state information, which will allow a degree seven polynomial. (Note:
* the zeroeth word of state information also has some other information
* stored in it -- see setstate() for details).
*
* The random number generation technique is a linear feedback shift register
* approach, employing trinomials (since there are fewer terms to sum up that
* way). In this approach, the least significant bit of all the numbers in
* the state table will act as a linear feedback shift register, and will
* have period 2^deg - 1 (where deg is the degree of the polynomial being
* used, assuming that the polynomial is irreducible and primitive). The
* higher order bits will have longer periods, since their values are also
* influenced by pseudo-random carries out of the lower bits. The total
* period of the generator is approximately deg*(2**deg - 1); thus doubling
* the amount of state information has a vast influence on the period of the
* generator. Note: the deg*(2**deg - 1) is an approximation only good for
* large deg, when the period of the shift register is the dominant factor.
* With deg equal to seven, the period is actually much longer than the
* 7*(2**7 - 1) predicted by this formula.
*
* Modified 28 December 1994 by Jacob S. Rosenberg.
* The following changes have been made:
* All references to the type u_int have been changed to unsigned long.
* All references to type int have been changed to type long. Other
* cleanups have been made as well. A warning for both initstate and
* setstate has been inserted to the effect that on Sparc platforms
* the 'arg_state' variable must be forced to begin on word boundaries.
* This can be easily done by casting a long integer array to char *.
* The overall logic has been left STRICTLY alone. This software was
* tested on both a VAX and Sun SpacsStation with exactly the same
* results. The new version and the original give IDENTICAL results.
* The new version is somewhat faster than the original. As the
* documentation says: "By default, the package runs with 128 bytes of
* state information and generates far better random numbers than a linear
* congruential generator. If the amount of state information is less than
* 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of
* 128 bytes, this new version runs about 19 percent faster and for a 16
* byte buffer it is about 5 percent faster.
*/
/*
* For each of the currently supported random number generators, we have a
* break value on the amount of state information (you need at least this
* many bytes of state info to support this random number generator), a degree
* for the polynomial (actually a trinomial) that the R.N.G. is based on, and
* the separation between the two lower order coefficients of the trinomial.
*/
#define TYPE_0 0 /* linear congruential */
#define BREAK_0 8
#define DEG_0 0
#define SEP_0 0
#define TYPE_1 1 /* x**7 + x**3 + 1 */
#define BREAK_1 32
#define DEG_1 7
#define SEP_1 3
#define TYPE_2 2 /* x**15 + x + 1 */
#define BREAK_2 64
#define DEG_2 15
#define SEP_2 1
#define TYPE_3 3 /* x**31 + x**3 + 1 */
#define BREAK_3 128
#define DEG_3 31
#define SEP_3 3
#define TYPE_4 4 /* x**63 + x + 1 */
#define BREAK_4 256
#define DEG_4 63
#define SEP_4 1
#define MAX_TYPES 5 /* max number of types above */
/*
* Initially, everything is set up as if from:
*
* initstate(1, randtbl, 128);
*
* Note that this initialization takes advantage of the fact that srandom()
* advances the front and rear pointers 10*rand_deg times, and hence the
* rear pointer which starts at 0 will also end up at zero; thus the zeroeth
* element of the state information, which contains info about the current
* position of the rear pointer is just
*
* MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3.
*/
static unsigned long randtbl[DEG_3 + 1] = {
TYPE_3,
#ifdef USE_WEAK_SEEDING
/* Historic implementation compatibility */
/* The random sequences do not vary much with the seed */
0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5,
0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd,
0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88,
0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b,
0x27fb47b9,
#else /* !USE_WEAK_SEEDING */
0x991539b1, 0x16a5bce3, 0x6774a4cd, 0x3e01511e, 0x4e508aaa, 0x61048c05,
0xf5500617, 0x846b7115, 0x6a19892c, 0x896a97af, 0xdb48f936, 0x14898454,
0x37ffd106, 0xb58bff9c, 0x59e17104, 0xcf918a49, 0x09378c83, 0x52c7a471,
0x8d293ea9, 0x1f4fc301, 0xc3db71be, 0x39b44e1c, 0xf8a44ef9, 0x4c8b80b1,
0x19edc328, 0x87bf4bdd, 0xc9b240e5, 0xe9ee4b1b, 0x4382aee7, 0x535b6b41,
0xf3bec5da
#endif /* !USE_WEAK_SEEDING */
};
/*
* fptr and rptr are two pointers into the state info, a front and a rear
* pointer. These two pointers are always rand_sep places aparts, as they
* cycle cyclically through the state information. (Yes, this does mean we
* could get away with just one pointer, but the code for random() is more
* efficient this way). The pointers are left positioned as they would be
* from the call
*
* initstate(1, randtbl, 128);
*
* (The position of the rear pointer, rptr, is really 0 (as explained above
* in the initialization of randtbl) because the state table pointer is set
* to point to randtbl[1] (as explained below).
*/
static unsigned long *fptr = &randtbl[SEP_3 + 1];
static unsigned long *rptr = &randtbl[1];
/*
* The following things are the pointer to the state information table, the
* type of the current generator, the degree of the current polynomial being
* used, and the separation between the two pointers. Note that for efficiency
* of random(), we remember the first location of the state information, not
* the zeroeth. Hence it is valid to access state[-1], which is used to
* store the type of the R.N.G. Also, we remember the last location, since
* this is more efficient than indexing every time to find the address of
* the last element to see if the front and rear pointers have wrapped.
*/
static unsigned long *state = &randtbl[1];
static long rand_type = TYPE_3;
static long rand_deg = DEG_3;
static long rand_sep = SEP_3;
static unsigned long *end_ptr = &randtbl[DEG_3 + 1];
void clear_ramdom(void)
{
fptr = &randtbl[SEP_3 + 1];
rptr = &randtbl[1];
state = &randtbl[1];
rand_type = TYPE_3;
rand_deg = DEG_3;
rand_sep = SEP_3;
end_ptr = &randtbl[DEG_3 + 1];
}
static inline long good_rand (long);
static inline long
good_rand (
register long x
)
{
#ifdef USE_WEAK_SEEDING
/*
* Historic implementation compatibility.
* The random sequences do not vary much with the seed,
* even with overflowing.
*/
return (1103515245 * x + 12345);
#else /* !USE_WEAK_SEEDING */
/*
* Compute x = (7^5 * x) mod (2^31 - 1)
* wihout overflowing 31 bits:
* (2^31 - 1) = 127773 * (7^5) + 2836
* From "Random number generators: good ones are hard to find",
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
* October 1988, p. 1195.
*/
register long hi, lo;
hi = x / 127773;
lo = x % 127773;
x = 16807 * lo - 2836 * hi;
if (x <= 0)
x += 0x7fffffff;
return (x);
#endif /* !USE_WEAK_SEEDING */
}
/*
* srandom:
*
* Initialize the random number generator based on the given seed. If the
* type is the trivial no-state-information type, just remember the seed.
* Otherwise, initializes state[] based on the given "seed" via a linear
* congruential generator. Then, the pointers are set to known locations
* that are exactly rand_sep places apart. Lastly, it cycles the state
* information a given number of times to get rid of any initial dependencies
* introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
* for default usage relies on values produced by this routine.
*/
void
ntp_srandom(
unsigned long x
)
{
long i;
if (rand_type == TYPE_0) {
state[0] = x;
} else {
state[0] = x;
for (i = 1; i < rand_deg; i++)
state[i] = good_rand(state[i - 1]);
fptr = &state[rand_sep];
rptr = &state[0];
for (i = 0; i < 10 * rand_deg; i++)
x = ntp_random();
}
/* seed the likely faster (and poorer) rand() as well */
srand((u_int)x);
}
/*
* srandomdev:
*
* Many programs choose the seed value in a totally predictable manner.
* This often causes problems. We seed the generator using the much more
* secure urandom(4) interface. Note that this particular seeding
* procedure can generate states which are impossible to reproduce by
* calling srandom() with any value, since the succeeding terms in the
* state buffer are no longer derived from the LC algorithm applied to
* a fixed seed.
*/
#ifdef NEED_SRANDOMDEV
void
ntp_srandomdev( void )
{
struct timeval tv;
unsigned long junk; /* Purposely used uninitialized */
#ifndef SYS_VXWORKS
GETTIMEOFDAY(&tv, NULL);
#else
(void)ipcom_gettimeofday(&tv, IP_NULL);
#endif
ntp_srandom(getpid() ^ tv.tv_sec ^ tv.tv_usec ^ junk);
return;
}
#endif
/*
* ntp_initstate() and ntp_setstate() are unused in our codebase and
* trigger warnings due to casting to a more-strictly-aligned pointer
* on alignment-sensitive platforms. #ifdef them away to save noise,
* build time, and binary space, but retain the code in case we find a
* use.
*/
#ifdef COMPILE_UNUSED_FUNCTIONS
/*
* Array versions of the above information to make code run faster --
* relies on fact that TYPE_i == i.
*/
#define MAX_TYPES 5 /* max number of types above */
static long degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
static long seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
/*
* initstate:
*
* Initialize the state information in the given array of n bytes for future
* random number generation. Based on the number of bytes we are given, and
* the break values for the different R.N.G.'s, we choose the best (largest)
* one we can and set things up for it. srandom() is then called to
* initialize the state information.
*
* Note that on return from srandom(), we set state[-1] to be the type
* multiplexed with the current value of the rear pointer; this is so
* successive calls to initstate() won't lose this information and will be
* able to restart with setstate().
*
* Note: the first thing we do is save the current state, if any, just like
* setstate() so that it doesn't matter when initstate is called.
*
* Returns a pointer to the old state.
*
* Note: The Sparc platform requires that arg_state begin on a long
* word boundary; otherwise a bus error will occur. Even so, lint will
* complain about mis-alignment, but you should disregard these messages.
*/
char *
ntp_initstate(
unsigned long seed, /* seed for R.N.G. */
char *arg_state, /* pointer to state array */
long n /* # bytes of state info */
)
{
register char *ostate = (char *)(&state[-1]);
register long *long_arg_state = (long *) arg_state;
if (rand_type == TYPE_0)
state[-1] = rand_type;
else
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
if (n < BREAK_0) {
(void)fprintf(stderr,
"random: not enough state (%ld bytes); ignored.\n", n);
return(0);
}
if (n < BREAK_1) {
rand_type = TYPE_0;
rand_deg = DEG_0;
rand_sep = SEP_0;
} else if (n < BREAK_2) {
rand_type = TYPE_1;
rand_deg = DEG_1;
rand_sep = SEP_1;
} else if (n < BREAK_3) {
rand_type = TYPE_2;
rand_deg = DEG_2;
rand_sep = SEP_2;
} else if (n < BREAK_4) {
rand_type = TYPE_3;
rand_deg = DEG_3;
rand_sep = SEP_3;
} else {
rand_type = TYPE_4;
rand_deg = DEG_4;
rand_sep = SEP_4;
}
state = (unsigned long *) (long_arg_state + 1); /* first location */
end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */
ntp_srandom(seed);
if (rand_type == TYPE_0)
long_arg_state[0] = rand_type;
else
long_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type;
return(ostate);
}
/*
* setstate:
*
* Restore the state from the given state array.
*
* Note: it is important that we also remember the locations of the pointers
* in the current state information, and restore the locations of the pointers
* from the old state information. This is done by multiplexing the pointer
* location into the zeroeth word of the state information.
*
* Note that due to the order in which things are done, it is OK to call
* setstate() with the same state as the current state.
*
* Returns a pointer to the old state information.
*
* Note: The Sparc platform requires that arg_state begin on a long
* word boundary; otherwise a bus error will occur. Even so, lint will
* complain about mis-alignment, but you should disregard these messages.
*/
char *
ntp_setstate(
char *arg_state /* pointer to state array */
)
{
register unsigned long *new_state = (unsigned long *) arg_state;
register long type = new_state[0] % MAX_TYPES;
register long rear = new_state[0] / MAX_TYPES;
char *ostate = (char *)(&state[-1]);
if (rand_type == TYPE_0)
state[-1] = rand_type;
else
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
switch(type) {
case TYPE_0:
case TYPE_1:
case TYPE_2:
case TYPE_3:
case TYPE_4:
rand_type = type;
rand_deg = degrees[type];
rand_sep = seps[type];
break;
default:
(void)fprintf(stderr,
"random: state info corrupted; not changed.\n");
}
state = (new_state + 1);
if (rand_type != TYPE_0) {
rptr = &state[rear];
fptr = &state[(rear + rand_sep) % rand_deg];
}
end_ptr = &state[rand_deg]; /* set end_ptr too */
return(ostate);
}
#endif /* COMPILE_UNUSED_FUNCTIONS */
/*
* random:
*
* If we are using the trivial TYPE_0 R.N.G., just do the old linear
* congruential bit. Otherwise, we do our fancy trinomial stuff, which is
* the same in all the other cases due to all the global variables that have
* been set up. The basic operation is to add the number at the rear pointer
* into the one at the front pointer. Then both pointers are advanced to
* the next location cyclically in the table. The value returned is the sum
* generated, reduced to 31 bits by throwing away the "least random" low bit.
*
* Note: the code takes advantage of the fact that both the front and
* rear pointers can't wrap on the same call by not testing the rear
* pointer if the front one has wrapped.
*
* Returns a 31-bit random number.
*/
long
ntp_random( void )
{
register long i;
register unsigned long *f, *r;
if (rand_type == TYPE_0) {
i = state[0];
state[0] = i = (good_rand(i)) & 0x7fffffff;
} else {
/*
* Use local variables rather than static variables for speed.
*/
f = fptr; r = rptr;
*f += *r;
i = (*f >> 1) & 0x7fffffff; /* chucking least random bit */
if (++f >= end_ptr) {
f = state;
++r;
}
else if (++r >= end_ptr) {
r = state;
}
fptr = f; rptr = r;
}
return(i);
}
@@ -0,0 +1,589 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Copyright (c) 1982, 1986, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
* Compatability shims with the rfc2553 API to simplify ntp.
*/
#include <ipntp_config.h>
#include <sys/types.h>
#include <ctype.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <isc/net.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include "ntp_rfc2553.h"
#include "ntpd.h"
#include "ntp_malloc.h"
#include "ntp_string.h"
#include "ntp_debug.h"
/*
* copy_addrinfo() - copy a single addrinfo to malloc()'d block.
* copy_addrinfo_list() - copy an addrinfo list to malloc()'d block.
*
* Copies an addrinfo list and its associated data to a contiguous block
* of storage from emalloc(). Callback routines invoked via
* getaddrinfo_sometime() have access to the resulting addrinfo list
* only until they return. This routine provides an easy way to make a
* persistent copy. Although the list provided to gai_sometime_callback
* routines is similarly contiguous, to keep this code usable in any
* context where we might want to duplicate an addrinfo list, it does
* not require the input list be contiguous.
*
* The returned list head pointer is passed to free() to release the
* entire list.
*
* In keeping with the rest of the NTP distribution, sockaddr_u is used
* in preference to struct sockaddr_storage, which is a member of the
* former union and so compatible.
*
* The rest of ntp_rfc2553.c is conditioned on ISC_PLATFORM_HAVEIPV6
* not being defined, copy_addrinfo_*() are exceptions.
*/
struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int
#ifdef EREALLOC_CALLSITE
,
const char *, int
#endif
);
struct addrinfo *
copy_addrinfo_impl(
const struct addrinfo * src
#ifdef EREALLOC_CALLSITE
,
const char * caller_file,
int caller_line
#endif
)
{
return copy_addrinfo_common(src, TRUE
#ifdef EREALLOC_CALLSITE
,
caller_file, caller_line
#endif
);
}
struct addrinfo *
copy_addrinfo_list_impl(
const struct addrinfo * src
#ifdef EREALLOC_CALLSITE
,
const char * caller_file,
int caller_line
#endif
)
{
return copy_addrinfo_common(src, FALSE
#ifdef EREALLOC_CALLSITE
,
caller_file, caller_line
#endif
);
}
struct addrinfo *
copy_addrinfo_common(
const struct addrinfo * src,
int just_one
#ifdef EREALLOC_CALLSITE
,
const char * caller_file,
int caller_line
#endif
)
{
const struct addrinfo * ai_src;
const struct addrinfo * ai_nxt;
struct addrinfo * ai_cpy;
struct addrinfo * dst;
sockaddr_u * psau;
char * pcanon;
u_int elements;
size_t octets;
size_t canons_octets;
size_t str_octets;
elements = 0;
canons_octets = 0;
for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
if (just_one)
ai_nxt = NULL;
else
ai_nxt = ai_src->ai_next;
++elements;
if (NULL != ai_src->ai_canonname)
canons_octets += 1 + strlen(ai_src->ai_canonname);
}
octets = elements * (sizeof(*ai_cpy) + sizeof(*psau));
octets += canons_octets;
dst = erealloczsite(NULL, octets, 0, TRUE, caller_file,
caller_line);
ai_cpy = dst;
psau = (void *)(ai_cpy + elements);
pcanon = (void *)(psau + elements);
for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
if (just_one)
ai_nxt = NULL;
else
ai_nxt = ai_src->ai_next;
*ai_cpy = *ai_src;
DEBUG_INSIST(ai_cpy->ai_canonname == ai_src->ai_canonname);
INSIST(ai_src->ai_addrlen <= sizeof(sockaddr_u));
memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
ai_cpy->ai_addr = &psau->sa;
++psau;
if (NULL != ai_src->ai_canonname) {
ai_cpy->ai_canonname = pcanon;
str_octets = 1 + strlen(ai_src->ai_canonname);
memcpy(pcanon, ai_src->ai_canonname, str_octets);
pcanon += str_octets;
}
if (NULL != ai_cpy->ai_next) {
if (just_one)
ai_cpy->ai_next = NULL;
else
ai_cpy->ai_next = ai_cpy + 1;
}
++ai_cpy;
}
ENSURE(pcanon == ((char *)dst + octets));
return dst;
}
#ifndef ISC_PLATFORM_HAVEIPV6
static char *ai_errlist[] = {
"Success",
"Address family for hostname not supported", /* EAI_ADDRFAMILY */
"Temporary failure in name resolution", /* EAI_AGAIN */
"Invalid value for ai_flags", /* EAI_BADFLAGS */
"Non-recoverable failure in name resolution", /* EAI_FAIL */
"ai_family not supported", /* EAI_FAMILY */
"Memory allocation failure", /* EAI_MEMORY */
"No address associated with hostname", /* EAI_NODATA */
"hostname nor servname provided, or not known", /* EAI_NONAME */
"servname not supported for ai_socktype", /* EAI_SERVICE */
"ai_socktype not supported", /* EAI_SOCKTYPE */
"System error returned in errno", /* EAI_SYSTEM */
"Invalid value for hints", /* EAI_BADHINTS */
"Resolved protocol is unknown", /* EAI_PROTOCOL */
"Unknown error", /* EAI_MAX */
};
/*
* Local declaration
*/
int
DNSlookup_name(
const char *name,
int ai_family,
struct hostent **Addresses
);
#ifndef SYS_WINNT
/*
* Encapsulate gethostbyname to control the error code
*/
int
DNSlookup_name(
const char *name,
int ai_family,
struct hostent **Addresses
)
{
*Addresses = gethostbyname(name);
return 0;
}
#endif
#ifndef HAVE_ADDRINFO
static int do_nodename (const char *nodename, struct addrinfo *ai,
const struct addrinfo *hints);
int
getaddrinfo (const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
int rval;
struct servent *sp;
struct addrinfo *ai = NULL;
int port;
const char *proto = NULL;
int family, socktype, flags, protocol;
/*
* If no name is provide just return an error
*/
if (nodename == NULL && servname == NULL)
return (EAI_NONAME);
ai = emalloc(sizeof(struct addrinfo));
if (ai == NULL)
return (EAI_MEMORY);
/*
* Copy default values from hints, if available
*/
if (hints != NULL) {
ai->ai_flags = hints->ai_flags;
ai->ai_family = hints->ai_family;
ai->ai_socktype = hints->ai_socktype;
ai->ai_protocol = hints->ai_protocol;
family = hints->ai_family;
socktype = hints->ai_socktype;
protocol = hints->ai_protocol;
flags = hints->ai_flags;
switch (family) {
case AF_UNSPEC:
switch (hints->ai_socktype) {
case SOCK_STREAM:
proto = "tcp";
break;
case SOCK_DGRAM:
proto = "udp";
break;
}
break;
case AF_INET:
case AF_INET6:
switch (hints->ai_socktype) {
case 0:
break;
case SOCK_STREAM:
proto = "tcp";
break;
case SOCK_DGRAM:
proto = "udp";
break;
case SOCK_RAW:
break;
default:
return (EAI_SOCKTYPE);
}
break;
#ifdef AF_LOCAL
case AF_LOCAL:
switch (hints->ai_socktype) {
case 0:
break;
case SOCK_STREAM:
break;
case SOCK_DGRAM:
break;
default:
return (EAI_SOCKTYPE);
}
break;
#endif
default:
return (EAI_FAMILY);
}
} else {
protocol = 0;
family = 0;
socktype = 0;
flags = 0;
}
rval = do_nodename(nodename, ai, hints);
if (rval != 0) {
freeaddrinfo(ai);
return (rval);
}
/*
* First, look up the service name (port) if it was
* requested. If the socket type wasn't specified, then
* try and figure it out.
*/
if (servname != NULL) {
char *e;
port = strtol(servname, &e, 10);
if (*e == '\0') {
if (socktype == 0)
return (EAI_SOCKTYPE);
if (port < 0 || port > 65535)
return (EAI_SERVICE);
port = htons((unsigned short) port);
} else {
sp = getservbyname(servname, proto);
if (sp == NULL)
return (EAI_SERVICE);
port = sp->s_port;
if (socktype == 0) {
if (strcmp(sp->s_proto, "tcp") == 0)
socktype = SOCK_STREAM;
else if (strcmp(sp->s_proto, "udp") == 0)
socktype = SOCK_DGRAM;
}
}
} else
port = 0;
/*
*
* Set up the port number
*/
if (ai->ai_family == AF_INET)
((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
else if (ai->ai_family == AF_INET6)
((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
*res = ai;
return (0);
}
void
freeaddrinfo(struct addrinfo *ai)
{
if (ai->ai_canonname != NULL)
{
efree(ai->ai_canonname);
ai->ai_canonname = NULL;
}
if (ai->ai_addr != NULL)
{
efree(ai->ai_addr);
ai->ai_addr = NULL;
}
efree(ai);
ai = NULL;
}
int
getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags)
{
struct hostent *hp;
if (sa->sa_family != AF_INET)
return (EAI_FAMILY);
hp = gethostbyaddr(
(const char *)&((const struct sockaddr_in *)sa)->sin_addr,
4, AF_INET);
if (hp == NULL) {
if (h_errno == TRY_AGAIN)
return (EAI_AGAIN);
else
return (EAI_FAIL);
}
if (host != NULL && hostlen > 0)
strlcpy(host, hp->h_name, hostlen);
return (0);
}
char *
gai_strerror(int ecode)
{
if (ecode < 0 || ecode > EAI_MAX)
ecode = EAI_MAX;
return ai_errlist[ecode];
}
static int
do_nodename(
const char *nodename,
struct addrinfo *ai,
const struct addrinfo *hints)
{
struct hostent *hp = NULL;
struct sockaddr_in *sockin;
struct sockaddr_in6 *sockin6;
int errval;
ai->ai_addr = emalloc(sizeof(struct sockaddr_storage));
if (ai->ai_addr == NULL)
return (IP_EAI_MEMORY);
/*
* For an empty node name just use the wildcard.
* NOTE: We need to assume that the address family is
* set elsewhere so that we can set the appropriate wildcard
*/
if (nodename == NULL) {
if (ai->ai_family == AF_INET)
{
ai->ai_addrlen = sizeof(struct sockaddr_in);
sockin = (struct sockaddr_in *)ai->ai_addr;
sockin->sin_family = (short) ai->ai_family;
sockin->sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
ai->ai_addrlen = sizeof(struct sockaddr_in6);
sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
sockin6->sin6_family = (short) ai->ai_family;
/*
* we have already zeroed out the address
* so we don't actually need to do this
* This assignment is causing problems so
* we don't do what this would do.
sockin6->sin6_addr = in6addr_any;
*/
}
#ifdef ISC_PLATFORM_HAVESALEN
ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
#endif
return (0);
}
/*
* See if we have an IPv6 address
*/
if(strchr(nodename, ':') != NULL) {
if (inet_pton(AF_INET6, nodename,
&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
ai->ai_family = AF_INET6;
ai->ai_addrlen = sizeof(struct sockaddr_in6);
return (0);
}
}
/*
* See if we have an IPv4 address
*/
if (inet_pton(AF_INET, nodename,
&((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
ai->ai_family = AF_INET;
ai->ai_addrlen = sizeof(struct sockaddr_in);
return (0);
}
/*
* If the numeric host flag is set, don't attempt resolution
*/
if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
return (IP_EAI_NONAME);
/*
* Look for a name
*/
errval = DNSlookup_name(nodename, AF_INET, &hp);
if (hp == NULL) {
if (errval == IP_TRY_AGAIN || errval == IP_TRY_AGAIN)
return (IP_TRY_AGAIN);
else if (errval == IP_EAI_NONAME) {
if (inet_pton(AF_INET, nodename,
&((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
ai->ai_family = AF_INET;
ai->ai_addrlen = sizeof(struct sockaddr_in);
return (0);
}
return (errval);
}
else
{
return (errval);
}
}
ai->ai_family = hp->h_addrtype;
ai->ai_addrlen = sizeof(struct sockaddr);
sockin = (struct sockaddr_in *)ai->ai_addr;
memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
ai->ai_addr->sa_family = hp->h_addrtype;
#ifdef ISC_PLATFORM_HAVESALEN
ai->ai_addr->sa_len = sizeof(struct sockaddr);
#endif
if (hints != NULL && (hints->ai_flags & AI_CANONNAME))
ai->ai_canonname = estrdup(hp->h_name);
return (0);
}
#endif /* HAVE_ADDRINFO */
char *
ntp_gai_strerror(int ecode)
{
if (ecode < 0 || ecode > EAI_MAX)
ecode = EAI_MAX;
return ai_errlist[ecode];
}
#endif /* !ISC_PLATFORM_HAVEIPV6 */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,55 @@
#include <ipntp_config.h>
#include <ntp_assert.h>
#include <string.h>
#include "ntp_malloc.h"
#include "l_stdlib.h"
#define STRDUP_EMPTY_UNIT
#ifndef HAVE_STRDUP
# undef STRDUP_EMPTY_UNIT
char *strdup(const char *s);
char *
strdup(
const char *s
)
{
size_t octets;
char * cp;
REQUIRE(s);
octets = strlen(s) + 1;
if ((cp = emalloc(octets)) == NULL)
return NULL;
memcpy(cp, s, octets);
return cp;
}
#endif
#ifndef HAVE_MEMCHR
# undef STRDUP_EMPTY_UNIT
void *memchr(const void *s, int c, size_t n)
{
const unsigned char *p = s;
while (n && *p != c) {
--n;
++p;
}
return n ? (char*)p : NULL;
}
#endif
#ifndef HAVE_STRNLEN
# undef STRDUP_EMPTY_UNIT
size_t strnlen(const char *s, size_t n)
{
const char *e = memchr(s, 0, n);
return e ? (size_t)(e - s) : n;
}
#endif
#ifdef STRDUP_EMPTY_UNIT
int strdup_c_nonempty_compilation_unit;
#endif
@@ -0,0 +1,376 @@
/*
* ntp_worker.c
*/
#include <ipntp_config.h>
#include "ntp_workimpl.h"
#ifdef WORKER
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include "iosignal.h"
#include "ntp_stdlib.h"
#include "ntp_malloc.h"
#include "ntp_syslog.h"
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_assert.h"
#include "ntp_unixtime.h"
#include "intreswork.h"
#define CHILD_MAX_IDLE (3 * 60) /* seconds, idle worker limit */
blocking_child ** blocking_children;
size_t blocking_children_alloc;
int worker_per_query; /* boolean */
int intres_req_pending;
volatile u_int blocking_child_ready_seen;
volatile u_int blocking_child_ready_done;
void clear_worker(void)
{
blocking_children = NULL;
blocking_children_alloc = 0;
worker_per_query = 0;
intres_req_pending = 0;
}
#ifndef HAVE_IO_COMPLETION_PORT
/*
* pipe_socketpair()
*
* Provides an AF_UNIX socketpair on systems which have them, otherwise
* pair of unidirectional pipes.
*/
int
pipe_socketpair(
int caller_fds[2],
int * is_pipe
)
{
int rc;
int fds[2];
int called_pipe;
#ifdef HAVE_SOCKETPAIR
rc = socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]);
#else
rc = -1;
#endif
if (-1 == rc) {
rc = pipe(&fds[0]);
called_pipe = TRUE;
} else {
called_pipe = FALSE;
}
if (-1 == rc)
return rc;
caller_fds[0] = fds[0];
caller_fds[1] = fds[1];
if (is_pipe != NULL)
*is_pipe = called_pipe;
return 0;
}
/*
* close_all_except()
*
* Close all file descriptors except the given keep_fd.
*/
void
close_all_except(
int keep_fd
)
{
int fd;
for (fd = 0; fd < keep_fd; fd++)
close(fd);
close_all_beyond(keep_fd);
}
/*
* close_all_beyond()
*
* Close all file descriptors after the given keep_fd, which is the
* highest fd to keep open.
*/
void
close_all_beyond(
int keep_fd
)
{
# ifdef HAVE_CLOSEFROM
closefrom(keep_fd + 1);
# elif defined(F_CLOSEM)
/*
* From 'Writing Reliable AIX Daemons,' SG24-4946-00,
* by Eric Agar (saves us from doing 32767 system
* calls)
*/
if (fcntl(keep_fd + 1, F_CLOSEM, 0) == -1)
msyslog(LOG_ERR, "F_CLOSEM(%d): %m", keep_fd + 1);
# else /* !HAVE_CLOSEFROM && !F_CLOSEM follows */
int fd;
int max_fd;
max_fd = GETDTABLESIZE();
for (fd = keep_fd + 1; fd < max_fd; fd++)
close(fd);
# endif /* !HAVE_CLOSEFROM && !F_CLOSEM */
}
#endif /* HAVE_IO_COMPLETION_PORT */
u_int
available_blocking_child_slot(void)
{
const size_t each = sizeof(blocking_children[0]);
u_int slot;
size_t prev_alloc;
size_t new_alloc;
size_t prev_octets;
size_t octets;
for (slot = 0; slot < blocking_children_alloc; slot++) {
if (NULL == blocking_children[slot])
return slot;
if (blocking_children[slot]->reusable) {
blocking_children[slot]->reusable = FALSE;
return slot;
}
}
prev_alloc = blocking_children_alloc;
prev_octets = prev_alloc * each;
new_alloc = blocking_children_alloc + 4;
octets = new_alloc * each;
blocking_children = erealloc_zero(blocking_children, octets,
prev_octets);
blocking_children_alloc = new_alloc;
/* assume we'll never have enough workers to overflow u_int */
return (u_int)prev_alloc;
}
int
queue_blocking_request(
blocking_work_req rtype,
void * req,
size_t reqsize,
blocking_work_callback done_func,
void * context
)
{
static u_int intres_slot = UINT_MAX;
u_int child_slot;
blocking_child * c;
blocking_pipe_header req_hdr;
req_hdr.octets = sizeof(req_hdr) + reqsize;
req_hdr.magic_sig = BLOCKING_REQ_MAGIC;
req_hdr.rtype = rtype;
req_hdr.done_func = done_func;
req_hdr.context = context;
child_slot = UINT_MAX;
if (worker_per_query || UINT_MAX == intres_slot ||
blocking_children[intres_slot]->reusable)
child_slot = available_blocking_child_slot();
if (!worker_per_query) {
if (UINT_MAX == intres_slot)
intres_slot = child_slot;
else
child_slot = intres_slot;
if (0 == intres_req_pending)
intres_timeout_req(0);
}
intres_req_pending++;
INSIST(UINT_MAX != child_slot);
c = blocking_children[child_slot];
if (NULL == c) {
c = emalloc_zero(sizeof(*c));
#ifdef WORK_FORK
c->req_read_pipe = -1;
c->req_write_pipe = -1;
#endif
#ifdef WORK_PIPE
c->resp_read_pipe = -1;
c->resp_write_pipe = -1;
#endif
blocking_children[child_slot] = c;
}
req_hdr.child_idx = child_slot;
return send_blocking_req_internal(c, &req_hdr, req);
}
int queue_blocking_response(
blocking_child * c,
blocking_pipe_header * resp,
size_t respsize,
const blocking_pipe_header * req
)
{
resp->octets = respsize;
resp->magic_sig = BLOCKING_RESP_MAGIC;
resp->rtype = req->rtype;
resp->context = req->context;
resp->done_func = req->done_func;
return send_blocking_resp_internal(c, resp);
}
void
process_blocking_resp(
blocking_child * c
)
{
blocking_pipe_header * resp;
void * data;
/*
* On Windows send_blocking_resp_internal() may signal the
* blocking_response_ready event multiple times while we're
* processing a response, so always consume all available
* responses before returning to test the event again.
*/
#ifdef WORK_THREAD
do {
#endif
resp = receive_blocking_resp_internal(c);
if (NULL != resp) {
DEBUG_REQUIRE(BLOCKING_RESP_MAGIC ==
resp->magic_sig);
data = (char *)resp + sizeof(*resp);
intres_req_pending--;
(*resp->done_func)(resp->rtype, resp->context,
resp->octets - sizeof(*resp),
data);
efree(resp);
}
#ifdef WORK_THREAD
} while (NULL != resp);
#endif
if (!worker_per_query && 0 == intres_req_pending)
intres_timeout_req(CHILD_MAX_IDLE);
else if (worker_per_query)
req_child_exit(c);
}
void
harvest_blocking_responses(void)
{
size_t idx;
blocking_child* cp;
u_int scseen, scdone;
scseen = blocking_child_ready_seen;
scdone = blocking_child_ready_done;
if (scdone != scseen) {
blocking_child_ready_done = scseen;
for (idx = 0; idx < blocking_children_alloc; idx++) {
cp = blocking_children[idx];
if (NULL == cp)
continue;
scseen = cp->resp_ready_seen;
scdone = cp->resp_ready_done;
if (scdone != scseen) {
cp->resp_ready_done = scseen;
process_blocking_resp(cp);
}
}
}
}
/*
* blocking_child_common runs as a forked child or a thread
*/
int
blocking_child_common(
blocking_child *c
)
{
int say_bye;
blocking_pipe_header *req;
say_bye = FALSE;
while (!say_bye) {
req = receive_blocking_req_internal(c);
if (NULL == req) {
say_bye = TRUE;
continue;
}
DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == req->magic_sig);
switch (req->rtype) {
case BLOCKING_GETADDRINFO:
if (blocking_getaddrinfo(c, req))
say_bye = TRUE;
break;
case BLOCKING_GETNAMEINFO:
if (blocking_getnameinfo(c, req))
say_bye = TRUE;
break;
default:
msyslog(LOG_ERR, "unknown req %d to blocking worker", req->rtype);
say_bye = TRUE;
}
efree(req);
}
return 0;
}
/*
* worker_idle_timer_fired()
*
* The parent starts this timer when the last pending response has been
* received from the child, making it idle, and clears the timer when a
* request is dispatched to the child. Once the timer expires, the
* child is sent packing.
*
* This is called when worker_idle_timer is nonzero and less than or
* equal to current_time.
*/
void
worker_idle_timer_fired(void)
{
u_int idx;
blocking_child * c;
DEBUG_REQUIRE(0 == intres_req_pending);
intres_timeout_req(0);
for (idx = 0; idx < blocking_children_alloc; idx++) {
c = blocking_children[idx];
if (NULL == c)
continue;
req_child_exit(c);
}
}
#else /* !WORKER follows */
int ntp_worker_nonempty_compilation_unit;
#endif
@@ -0,0 +1,59 @@
/*
* numtoa - return asciized network numbers store in local array space
*/
#include <ipntp_config.h>
#include <sys/types.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> /* ntohl */
#endif
#include <stdio.h>
#include "ntp_fp.h"
#include "lib_strbuf.h"
#include "ntp_stdlib.h"
char *
numtoa(
u_int32 num
)
{
register u_int32 netnum;
register char *buf;
netnum = ntohl(num);
LIB_GETBUF(buf);
snprintf(buf, LIB_BUFLENGTH, "%lu.%lu.%lu.%lu",
((u_long)netnum >> 24) & 0xff,
((u_long)netnum >> 16) & 0xff,
((u_long)netnum >> 8) & 0xff,
(u_long)netnum & 0xff);
return buf;
}
/* Convert a refid & stratum to a string */
const char *
refid_str(
u_int32 refid,
int stratum
)
{
char * text;
size_t tlen;
if (stratum > 1)
return numtoa(refid);
LIB_GETBUF(text);
text[0] = '.';
memcpy(&text[1], &refid, sizeof(refid));
text[1 + sizeof(refid)] = '\0';
tlen = strlen(text);
text[tlen] = '.';
text[tlen + 1] = '\0';
return text;
}
@@ -0,0 +1,43 @@
/*
* numtohost - convert network number to host name.
*/
#include <ipntp_config.h>
#include <sys/types.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> /* ntohl */
#endif
#include "ntp_fp.h"
#include "ntp_stdlib.h"
#include "lib_strbuf.h"
#define LOOPBACKNET 0x7f000000
#define LOOPBACKHOST 0x7f000001
#define LOOPBACKNETMASK 0xff000000
char *
numtohost(
u_int32 netnum
)
{
char *bp;
struct hostent *hp;
/*
* This is really gross, but saves lots of hanging looking for
* hostnames for the radio clocks. Don't bother looking up
* addresses on the loopback network except for the loopback
* host itself.
*/
if ((((ntohl(netnum) & LOOPBACKNETMASK) == LOOPBACKNET)
&& (ntohl(netnum) != LOOPBACKHOST))
|| ((hp = gethostbyaddr((char *)&netnum, sizeof netnum, AF_INET))
== 0))
return numtoa(netnum);
LIB_GETBUF(bp);
strlcpy(bp, hp->h_name, LIB_BUFLENGTH);
return bp;
}
@@ -0,0 +1,36 @@
/*
* octtoint - convert an ascii string in octal to an unsigned
* long, with error checking
*/
#include <ipntp_config.h>
#include <stdio.h>
#include <ctype.h>
#include "ntp_stdlib.h"
int
octtoint(
const char *str,
u_long *ival
)
{
register u_long u;
register const char *cp;
cp = str;
if (*cp == '\0')
return 0;
u = 0;
while (*cp != '\0') {
if (!isdigit((unsigned char)*cp) || *cp == '8' || *cp == '9')
return 0;
if (u >= 0x20000000)
return 0; /* overflow */
u <<= 3;
u += *cp++ - '0'; /* ascii dependent */
}
*ival = u;
return 1;
}
@@ -0,0 +1,238 @@
/*
* prettydate - convert a time stamp to something readable
*/
#include <ipntp_config.h>
#include <stdio.h>
#include "ntp_fp.h"
#include "ntp_unixtime.h" /* includes <sys/time.h> */
#include "lib_strbuf.h"
#include "ntp_stdlib.h"
#include "ntp_assert.h"
#include "ntp_calendar.h"
#if SIZEOF_TIME_T < 4
# error sizeof(time_t) < 4 -- this will not work!
#endif
static char *common_prettydate(l_fp *, int);
const char * const months[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
const char * const daynames[7] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
/* Helper function to handle possible wraparound of the ntp epoch.
*
* Works by periodic extension of the ntp time stamp in the UN*X epoch.
* If the 'time_t' is 32 bit, use solar cycle warping to get the value
* in a suitable range. Also uses solar cycle warping to work around
* really buggy implementations of 'gmtime()' / 'localtime()' that
* cannot work with a negative time value, that is, times before
* 1970-01-01. (MSVCRT...)
*
* Apart from that we're assuming that the localtime/gmtime library
* functions have been updated so that they work...
*
* An explanation: The julian calendar repeats ever 28 years, because
* it's the LCM of 7 and 1461, the week and leap year cycles. This is
* called a 'solar cycle'. The gregorian calendar does the same as
* long as no centennial year (divisible by 100, but not 400) goes in
* the way. So between 1901 and 2099 (inclusive) we can warp time
* stamps by 28 years to make them suitable for localtime() and
* gmtime() if we have trouble. Of course this will play hubbubb with
* the DST zone switches, so we should do it only if necessary; but as
* we NEED a proper conversion to dates via gmtime() we should try to
* cope with as many idiosyncrasies as possible.
*
*/
/*
* solar cycle in unsigned secs and years, and the cycle limits.
*/
#define SOLAR_CYCLE_SECS 0x34AADC80UL /* 7*1461*86400*/
#define SOLAR_CYCLE_YEARS 28
#define MINFOLD -3
#define MAXFOLD 3
static struct tm *
get_struct_tm(
const vint64 *stamp,
int local)
{
struct tm *tm = NULL;
int32 folds = 0;
time_t ts;
#ifdef HAVE_INT64
int64 tl;
tl = stamp->q_s;
ts = (time_t)tl;
/*
* If there is chance of truncation, try to fix it. Let the
* compiler find out if this can happen at all.
*/
while (ts != tl) { /* truncation? */
if (tl < 0) {
if (--folds < MINFOLD)
return NULL;
tl += SOLAR_CYCLE_SECS;
} else {
if (++folds > MAXFOLD)
return NULL;
tl -= SOLAR_CYCLE_SECS;
}
ts = (time_t)tl; /* next try... */
}
#else
/*
* since we do not have 64-bit scalars, it's not likely we have
* 64-bit time_t. Assume 32 bits and properly reduce the value.
*/
u_int32 hi, lo;
hi = stamp->D_s.hi;
lo = stamp->D_s.lo;
while ((hi && ~hi) || ((hi ^ lo) & 0x80000000u)) {
if ((((hi) & 0x80000000) != 0)) {
if (--folds < MINFOLD)
return NULL;
M_ADD(hi, lo, 0, SOLAR_CYCLE_SECS);
} else {
if (++folds > MAXFOLD)
return NULL;
M_SUB(hi, lo, 0, SOLAR_CYCLE_SECS);
}
}
ts = (int32)lo;
#endif
/*
* 'ts' should be a suitable value by now. Just go ahead, but
* with care:
*
* There are some pathological implementations of 'gmtime()'
* and 'localtime()' out there. No matter if we have 32-bit or
* 64-bit 'time_t', try to fix this by solar cycle warping
* again...
*
* At least the MSDN says that the (Microsoft) Windoze
* versions of 'gmtime()' and 'localtime()' will bark on time
* stamps < 0.
*/
while ((tm = (*(local ? localtime : gmtime))(&ts)) == NULL)
if (ts < 0) {
if (--folds < MINFOLD)
return NULL;
ts += SOLAR_CYCLE_SECS;
} else if (ts >= (time_t)SOLAR_CYCLE_SECS) {
if (++folds > MAXFOLD)
return NULL;
ts -= SOLAR_CYCLE_SECS;
} else
return NULL; /* That's truly pathological! */
/* 'tm' surely not NULL here! */
INSIST(tm != NULL);
if (folds != 0) {
tm->tm_year += folds * SOLAR_CYCLE_YEARS;
if (tm->tm_year <= 0 || tm->tm_year >= 200)
return NULL; /* left warp range... can't help here! */
}
return tm;
}
static char *
common_prettydate(
l_fp *ts,
int local
)
{
static const char pfmt0[] =
"%08lx.%08lx %s, %s %2d %4d %2d:%02d:%02d.%03u";
static const char pfmt1[] =
"%08lx.%08lx [%s, %s %2d %4d %2d:%02d:%02d.%03u UTC]";
char *bp;
struct tm *tm;
u_int msec;
u_int32 ntps;
vint64 sec;
LIB_GETBUF(bp);
if (ts->l_ui == 0 && ts->l_uf == 0) {
strlcpy (bp, "(no time)", LIB_BUFLENGTH);
return (bp);
}
/* get & fix milliseconds */
ntps = ts->l_ui;
msec = ts->l_uf / 4294967; /* fract / (2 ** 32 / 1000) */
if (msec >= 1000u) {
msec -= 1000u;
ntps++;
}
sec = ntpcal_ntp_to_time(ntps, NULL);
tm = get_struct_tm(&sec, local);
if (!tm) {
/*
* get a replacement, but always in UTC, using
* ntpcal_time_to_date()
*/
struct calendar jd;
ntpcal_time_to_date(&jd, &sec);
snprintf(bp, LIB_BUFLENGTH, local ? pfmt1 : pfmt0,
(u_long)ts->l_ui, (u_long)ts->l_uf,
daynames[jd.weekday], months[jd.month-1],
jd.monthday, jd.year, jd.hour,
jd.minute, jd.second, msec);
} else
snprintf(bp, LIB_BUFLENGTH, pfmt0,
(u_long)ts->l_ui, (u_long)ts->l_uf,
daynames[tm->tm_wday], months[tm->tm_mon],
tm->tm_mday, 1900 + tm->tm_year, tm->tm_hour,
tm->tm_min, tm->tm_sec, msec);
return bp;
}
char *
prettydate(
l_fp *ts
)
{
return common_prettydate(ts, 1);
}
char *
gmprettydate(
l_fp *ts
)
{
return common_prettydate(ts, 0);
}
struct tm *
ntp2unix_tm(
u_int32 ntp, int local
)
{
vint64 vl;
vl = ntpcal_ntp_to_time(ntp, NULL);
return get_struct_tm(&vl, local);
}
@@ -0,0 +1,419 @@
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#include <stdio.h>
#include "ntp_assert.h"
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
#include "ntp_lists.h"
#include "recvbuff.h"
#include "iosignal.h"
#include <isc/isc_list.h>
#include "ntp_mem.h"
#if (RECV_INC & (RECV_INC-1))
# error RECV_INC not a power of 2!
#endif
#if (RECV_BATCH & (RECV_BATCH - 1))
#error RECV_BATCH not a power of 2!
#endif
#if (RECV_BATCH < RECV_INC)
#error RECV_BATCH must be >= RECV_INC!
#endif
/*
* Memory allocation
*/
static u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */
static u_long volatile free_recvbufs; /* recvbufs on free_recv_list */
static u_long volatile total_recvbufs; /* total recvbufs currently in use */
static u_long volatile lowater_adds; /* number of times we have added memory */
static u_long volatile buffer_shortfall;/* number of missed free receive buffers
between replenishments */
static u_long limit_recvbufs; /* maximum total of receive buffers */
static u_long emerg_recvbufs; /* emergency/urgent buffers to keep */
static void *total_recv_bufp = NULL;
static DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo;
static recvbuf_t * free_recv_list;
#if defined(SYS_WINNT)
/*
* For Windows we need to set up a lock to manipulate the
* recv buffers to prevent corruption. We keep it lock for as
* short a time as possible
*/
static CRITICAL_SECTION RecvLock;
static CRITICAL_SECTION FreeLock;
# define LOCK_R() EnterCriticalSection(&RecvLock)
# define UNLOCK_R() LeaveCriticalSection(&RecvLock)
# define LOCK_F() EnterCriticalSection(&FreeLock)
# define UNLOCK_F() LeaveCriticalSection(&FreeLock)
#else
# define LOCK_R() do {} while (FALSE)
# define UNLOCK_R() do {} while (FALSE)
# define LOCK_F() do {} while (FALSE)
# define UNLOCK_F() do {} while (FALSE)
#endif
#ifdef NTP_DEBUG
static void uninit_recvbuff(void);
#endif
u_long
free_recvbuffs (void)
{
return free_recvbufs;
}
u_long
full_recvbuffs (void)
{
return full_recvbufs;
}
u_long
total_recvbuffs (void)
{
return total_recvbufs;
}
u_long
lowater_additions(void)
{
return lowater_adds;
}
static inline void
initialise_buffer(recvbuf_t *buff)
{
ZERO(*buff);
}
static void
create_buffers(
size_t nbufs)
{
# ifndef NTP_DEBUG
static const u_int chunk = RECV_INC;
# else
/* Allocate each buffer individually so they can be free()d
* during ntpd shutdown on DEBUG builds to keep them out of heap
* leak reports.
*/
static const u_int chunk = 1;
# endif
register recvbuf_t *bufp;
recvbuf_t *head;
u_int i;
size_t abuf;
if (limit_recvbufs <= total_recvbufs)
return;
abuf = nbufs + buffer_shortfall;
buffer_shortfall = 0;
if (abuf < nbufs || abuf > RECV_BATCH)
abuf = RECV_BATCH; /* clamp on overflow */
else
abuf += (~abuf + 1) & (RECV_INC - 1); /* round up */
if (abuf > (limit_recvbufs - total_recvbufs))
abuf = limit_recvbufs - total_recvbufs;
abuf += (~abuf + 1) & (chunk - 1); /* round up */
while (abuf) {
bufp = emalloc(chunk*sizeof(*bufp));
if (!bufp) {
limit_recvbufs = total_recvbufs;
break;
}
head = bufp;
for (i = chunk; i; --i,++bufp) {
bufp->mem_head = FALSE;
LINK_SLIST(free_recv_list, bufp, link);
}
head->mem_head = TRUE;
free_recvbufs += chunk;
total_recvbufs += chunk;
abuf -= chunk;
}
++lowater_adds;
}
void
init_recvbuff(int nbufs)
{
buffer_shortfall = 0;
total_recv_bufp = NULL;
free_recv_list = NULL;
memset(&full_recv_fifo, 0, sizeof(full_recv_fifo));
/*
* Init buffer free list and stat counters
*/
free_recvbufs = total_recvbufs = 0;
full_recvbufs = lowater_adds = 0;
limit_recvbufs = RECV_TOOMANY;
emerg_recvbufs = RECV_CLOCK;
create_buffers(nbufs);
# if defined(SYS_WINNT)
InitializeCriticalSection(&RecvLock);
InitializeCriticalSection(&FreeLock);
# endif
# ifdef NTP_DEBUG
atexit(&uninit_recvbuff);
# endif
}
void
clean_all_recvbuff()
{
recvbuf_t *rbunlinked;
LOCK_R();
efree(total_recv_bufp);
UNLOCK_R();
for (;;) {
UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link);
if (rbunlinked == NULL)
break;
if (rbunlinked->mem_head)
efree(rbunlinked);
}
free_recv_list = NULL;
free_recvbufs = total_recvbufs = 0;
full_recvbufs = lowater_adds = 0;
}
#ifdef NTP_DEBUG
static void
uninit_recvbuff(void)
{
recvbuf_t *rbunlinked;
for (;;) {
UNLINK_FIFO(rbunlinked, full_recv_fifo, link);
if (rbunlinked == NULL)
break;
efree(rbunlinked);
}
for (;;) {
UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link);
if (rbunlinked == NULL)
break;
efree(rbunlinked);
}
# if defined(SYS_WINNT)
DeleteCriticalSection(&FreeLock);
DeleteCriticalSection(&RecvLock);
# endif
}
#endif /* NTP_DEBUG */
/*
* freerecvbuf - make a single recvbuf available for reuse
*/
void
freerecvbuf(recvbuf_t *rb)
{
if (rb) {
if (--rb->used != 0) {
msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used);
rb->used = 0;
}
LOCK_F();
LINK_SLIST(free_recv_list, rb, link);
++free_recvbufs;
UNLOCK_F();
}
}
void
add_full_recv_buffer(recvbuf_t *rb)
{
if (rb == NULL) {
msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer");
return;
}
LOCK_R();
LINK_FIFO(full_recv_fifo, rb, link);
++full_recvbufs;
UNLOCK_R();
}
recvbuf_t *
get_free_recv_buffer(
int /*BOOL*/ urgent
)
{
recvbuf_t *buffer = NULL;
LOCK_F();
if (free_recvbufs > (urgent ? emerg_recvbufs : 0)) {
UNLINK_HEAD_SLIST(buffer, free_recv_list, link);
}
if (buffer != NULL) {
if (free_recvbufs)
--free_recvbufs;
initialise_buffer(buffer);
++buffer->used;
} else {
++buffer_shortfall;
}
UNLOCK_F();
return buffer;
}
#ifdef HAVE_IO_COMPLETION_PORT
recvbuf_t *
get_free_recv_buffer_alloc(
int /*BOOL*/ urgent
)
{
LOCK_F();
if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0)
create_buffers(RECV_INC);
UNLOCK_F();
return get_free_recv_buffer(urgent);
}
#endif
recvbuf_t *
get_full_recv_buffer(void)
{
recvbuf_t * rbuf;
/*
* make sure there are free buffers when we wander off to do
* lengthy packet processing with any buffer we grab from the
* full list.
*
* fixes malloc() interrupted by SIGIO risk (Bug 889)
*/
LOCK_F();
if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0)
create_buffers(RECV_INC);
UNLOCK_F();
/*
* try to grab a full buffer
*/
LOCK_R();
UNLINK_FIFO(rbuf, full_recv_fifo, link);
if (rbuf != NULL && full_recvbufs)
--full_recvbufs;
UNLOCK_R();
return rbuf;
}
/*
* purge_recv_buffers_for_fd() - purges any previously-received input
* from a given file descriptor.
*/
void
purge_recv_buffers_for_fd(
int fd
)
{
recvbuf_t *rbufp;
recvbuf_t *next;
recvbuf_t *punlinked;
recvbuf_t *freelist = NULL;
/* We want to hold only one lock at a time. So we do a scan on
* the full buffer queue, collecting items as we go, and when
* done we spool the the collected items to 'freerecvbuf()'.
*/
LOCK_R();
for (rbufp = HEAD_FIFO(full_recv_fifo);
rbufp != NULL;
rbufp = next)
{
next = rbufp->link;
# ifdef HAVE_IO_COMPLETION_PORT
if (rbufp->dstadr == NULL && rbufp->fd == fd)
# else
if (rbufp->fd == fd)
# endif
{
UNLINK_MID_FIFO(punlinked, full_recv_fifo,
rbufp, link, recvbuf_t);
INSIST(punlinked == rbufp);
if (full_recvbufs)
--full_recvbufs;
rbufp->link = freelist;
freelist = rbufp;
}
}
UNLOCK_R();
while (freelist) {
next = freelist->link;
freerecvbuf(freelist);
freelist = next;
}
}
/*
* Checks to see if there are buffers to process
*/
isc_boolean_t has_full_recv_buffer(void)
{
if (HEAD_FIFO(full_recv_fifo) != NULL)
return (ISC_TRUE);
else
return (ISC_FALSE);
}
#ifdef NTP_DEBUG_LISTS_H
void
check_gen_fifo_consistency(void *fifo)
{
gen_fifo *pf;
gen_node *pthis;
gen_node **pptail;
pf = fifo;
REQUIRE((NULL == pf->phead && NULL == pf->pptail) ||
(NULL != pf->phead && NULL != pf->pptail));
pptail = &pf->phead;
for (pthis = pf->phead;
pthis != NULL;
pthis = pthis->link)
if (NULL != pthis->link)
pptail = &pthis->link;
REQUIRE(NULL == pf->pptail || pptail == pf->pptail);
}
#endif /* NTP_DEBUG_LISTS_H */
@@ -0,0 +1,36 @@
/*
* refnumtoa - return asciized refclock addresses stored in local array space
*/
#include <ipntp_config.h>
#include <stdio.h>
#include "ntp_net.h"
#include "lib_strbuf.h"
#include "ntp_stdlib.h"
const char *
refnumtoa(
sockaddr_u *num
)
{
u_int32 netnum;
char *buf;
const char *rclock;
if (!ISREFCLOCKADR(num))
return socktoa(num);
LIB_GETBUF(buf);
netnum = SRCADR(num);
rclock = clockname((int)((u_long)netnum >> 8) & 0xff);
if (rclock != NULL)
snprintf(buf, LIB_BUFLENGTH, "%s(%lu)",
rclock, (u_long)netnum & 0xff);
else
snprintf(buf, LIB_BUFLENGTH, "REFCLK(%lu,%lu)",
((u_long)netnum >> 8) & 0xff,
(u_long)netnum & 0xff);
return buf;
}
@@ -0,0 +1,231 @@
/*
* socket.c - low-level socket operations
*/
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#include <stdio.h>
#include "ntp.h"
#include "ntp_io.h"
#include "ntp_net.h"
#include "ntp_debug.h"
#include "ipcom_sock.h"
#include "ipntp.h"
/*
* Windows C runtime ioctl() can't deal properly with sockets,
* map to ioctlsocket for this source file.
*/
#ifdef SYS_WINNT
#define ioctl(fd, opt, val) ioctlsocket(fd, opt, (u_long *)(val))
#endif
/*
* on Unix systems the stdio library typically
* makes use of file descriptors in the lower
* integer range. stdio usually will make use
* of the file descriptors in the range of
* [0..FOPEN_MAX)
* in order to keep this range clean, for socket
* file descriptors we attempt to move them above
* FOPEN_MAX. This is not as easy as it sounds as
* FOPEN_MAX changes from implementation to implementation
* and may exceed to current file decriptor limits.
* We are using following strategy:
* - keep a current socket fd boundary initialized with
* max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX))
* - attempt to move the descriptor to the boundary or
* above.
* - if that fails and boundary > 0 set boundary
* to min(0, socket_fd_boundary - FD_CHUNK)
* -> retry
* if failure and boundary == 0 return old fd
* - on success close old fd return new fd
*
* effects:
* - fds will be moved above the socket fd boundary
* if at all possible.
* - the socket boundary will be reduced until
* allocation is possible or 0 is reached - at this
* point the algrithm will be disabled
*/
SOCKET
move_fd(
SOCKET fd
)
{
#if !defined(SYS_WINNT) && defined(F_DUPFD)
#ifndef FD_CHUNK
#define FD_CHUNK 10
#endif
#ifndef FOPEN_MAX
#define FOPEN_MAX 20
#endif
/*
* number of fds we would like to have for
* stdio FILE* available.
* we can pick a "low" number as our use of
* FILE* is limited to log files and temporarily
* to data and config files. Except for log files
* we don't keep the other FILE* open beyond the
* scope of the function that opened it.
*/
#ifndef FD_PREFERRED_SOCKBOUNDARY
#define FD_PREFERRED_SOCKBOUNDARY 48
#endif
static SOCKET socket_boundary = -1;
SOCKET newfd;
REQUIRE((int)fd >= 0);
/*
* check whether boundary has be set up
* already
*/
if (socket_boundary == -1) {
socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK,
min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY)));
TRACE(1, ("move_fd: estimated max descriptors: %d, "
"initial socket boundary: %d\n",
GETDTABLESIZE(), socket_boundary));
}
/*
* Leave a space for stdio to work in. potentially moving the
* socket_boundary lower until allocation succeeds.
*/
do {
if (fd >= 0 && fd < socket_boundary) {
/* inside reserved range: attempt to move fd */
newfd = fcntl(fd, F_DUPFD, socket_boundary);
if (newfd != -1) {
/* success: drop the old one - return the new one */
close(fd);
return newfd;
}
} else {
/* outside reserved range: no work - return the original one */
return fd;
}
socket_boundary = max(0, socket_boundary - FD_CHUNK);
TRACE(1, ("move_fd: selecting new socket boundary: %d\n",
socket_boundary));
} while (socket_boundary > 0);
#else
REQUIRE((int)fd >= 0);
#endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */
return fd;
}
/*
* make_socket_nonblocking() - set up descriptor to be non blocking
*/
void
make_socket_nonblocking(
SOCKET fd
)
{
/*
* set non-blocking,
*/
#ifdef USE_FIONBIO
/* in vxWorks we use FIONBIO, but the others are defined for old
* systems, so all hell breaks loose if we leave them defined
*/
#undef O_NONBLOCK
#undef FNDELAY
#undef O_NDELAY
#endif
#ifndef NTP_VXWORKS_7
#if defined(O_NONBLOCK) /* POSIX */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
msyslog(LOG_ERR,
"fcntl(O_NONBLOCK) fails on fd #%d: %m", fd);
ipntp_exit_callback(ipcom_getpid());
}
#elif defined(FNDELAY)
if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
msyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m",
fd);
ipntp_exit_callback(ipcom_getpid());
}
#elif defined(O_NDELAY) /* generally the same as FNDELAY */
if (fcntl(fd, F_SETFL, O_NDELAY) < 0) {
msyslog(LOG_ERR, "fcntl(O_NDELAY) fails on fd #%d: %m",
fd);
ipntp_exit_callback(ipcom_getpid());
}
#elif defined(FIONBIO)
{
int on = 1;
if (ioctl(fd, FIONBIO, &on) < 0) {
msyslog(LOG_ERR,
"ioctl(FIONBIO) fails on fd #%d: %m",
fd);
ipntp_exit_callback(ipcom_getpid());
}
}
#elif defined(FIOSNBIO)
if (ioctl(fd, FIOSNBIO, &on) < 0) {
msyslog(LOG_ERR,
"ioctl(FIOSNBIO) fails on fd #%d: %m", fd);
ipntp_exit_callback(ipcom_getpid());
}
#else
# include "Bletch: Need non-blocking I/O!"
#endif
#endif
int on = 1;
if (ipcom_socketioctl(fd, IP_FIONBIO, &on) < 0) {
msyslog(LOG_ERR,
"ioctl(FIONBIO) fails on fd #%d: %m",
fd);
ipntp_exit_callback(ipcom_getpid());
}
}
#if 0
/* The following subroutines should probably be moved here */
static SOCKET
open_socket(
sockaddr_u * addr,
int bcast,
int turn_off_reuse,
endpt * interf
)
void
sendpkt(
sockaddr_u * dest,
struct interface * ep,
int ttl,
struct pkt * pkt,
int len
)
static inline int
read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
static inline int
read_network_packet(
SOCKET fd,
struct interface * itf,
l_fp ts
)
void
kill_asyncio(int startfd)
#endif /* 0 */
@@ -0,0 +1,172 @@
/*
* socktoa.c socktoa(), sockporttoa(), and sock_hash()
*/
#ifdef HAVE_CONFIG_H
#include <ipntp_config.h>
#endif
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include <stdio.h>
#include <arpa/inet.h>
#include <isc/result.h>
#include <isc/netaddr.h>
#include <isc/sockaddr.h>
#include <limits.h>
#include "ntp_fp.h"
#include "lib_strbuf.h"
#include "ntp_stdlib.h"
#include "ntp.h"
/*
* socktoa - return a numeric host name from a sockaddr_storage structure
*/
const char *
socktoa(
const sockaddr_u *sock
)
{
int saved_errno;
char * res;
char * addr;
u_long scope;
saved_errno = socket_errno();
LIB_GETBUF(res);
if (NULL == sock) {
strlcpy(res, "(null)", LIB_BUFLENGTH);
} else {
switch(AF(sock)) {
case AF_INET:
case AF_UNSPEC:
inet_ntop(AF_INET, PSOCK_ADDR4(sock), res,
LIB_BUFLENGTH);
break;
case AF_INET6:
inet_ntop(AF_INET6, PSOCK_ADDR6(sock), res,
LIB_BUFLENGTH);
scope = SCOPE_VAR(sock);
if (0 != scope && !strchr(res, '%')) {
addr = res;
LIB_GETBUF(res);
snprintf(res, LIB_BUFLENGTH, "%s%%%lu",
addr, scope);
res[LIB_BUFLENGTH - 1] = '\0';
}
break;
default:
snprintf(res, LIB_BUFLENGTH,
"(socktoa unknown family %d)",
AF(sock));
}
}
errno = saved_errno;
return res;
}
const char *
sockporttoa(
const sockaddr_u *sock
)
{
int saved_errno;
const char * atext;
char * buf;
saved_errno = socket_errno();
atext = socktoa(sock);
LIB_GETBUF(buf);
snprintf(buf, LIB_BUFLENGTH,
(IS_IPV6(sock))
? "[%s]:%hu"
: "%s:%hu",
atext, SRCPORT(sock));
errno = saved_errno;
return buf;
}
/*
* sock_hash - hash a sockaddr_u structure
*/
u_short
sock_hash(
const sockaddr_u *addr
)
{
u_int hashVal;
u_int j;
size_t len;
const u_char *pch;
hashVal = 0;
len = 0;
/*
* We can't just hash the whole thing because there are hidden
* fields in sockaddr_in6 that might be filled in by recvfrom(),
* so just use the family, port and address.
*/
pch = (const void *)&AF(addr);
hashVal = 37 * hashVal + *pch;
if (sizeof(AF(addr)) > 1) {
pch++;
hashVal = 37 * hashVal + *pch;
}
switch(AF(addr)) {
case AF_INET:
pch = (const void *)&SOCK_ADDR4(addr);
len = sizeof(SOCK_ADDR4(addr));
break;
case AF_INET6:
pch = (const void *)&SOCK_ADDR6(addr);
len = sizeof(SOCK_ADDR6(addr));
break;
}
for (j = 0; j < len ; j++)
hashVal = 37 * hashVal + pch[j];
return (u_short)(hashVal & USHRT_MAX);
}
int
sockaddr_masktoprefixlen(
const sockaddr_u * psa
)
{
isc_netaddr_t isc_na;
isc_sockaddr_t isc_sa;
u_int pfxlen;
isc_result_t result;
int rc;
ZERO(isc_sa);
memcpy(&isc_sa.type, psa,
min(sizeof(isc_sa.type), sizeof(*psa)));
isc_netaddr_fromsockaddr(&isc_na, &isc_sa);
result = isc_netaddr_masktoprefixlen(&isc_na, &pfxlen);
rc = (ISC_R_SUCCESS == result)
? (int)pfxlen
: -1;
return rc;
}
@@ -0,0 +1,120 @@
/*
* socktoa - return a numeric host name from a sockaddr_storage structure
*/
#include <ipntp_config.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include <arpa/inet.h>
#include <stdio.h>
#include "ntp_fp.h"
#include "lib_strbuf.h"
#include "ntp_stdlib.h"
#include "ntp.h"
#include "ntp_debug.h"
#include "ntp_rfc2553.h"
extern char *gai_strerror(int ecode);
const char *
socktohost(
const sockaddr_u *sock
)
{
const char svc[] = "ntp";
char * pbuf;
char * pliar;
int gni_flags;
struct addrinfo hints;
struct addrinfo * alist;
struct addrinfo * ai;
sockaddr_u addr;
size_t octets;
int a_info;
int saved_errno;
saved_errno = socket_errno();
/* reverse the address to purported DNS name */
LIB_GETBUF(pbuf);
gni_flags = IP_NI_DGRAM | IP_NI_NAMEREQD;
if (getnameinfo(&sock->sa, (Ip_socklen_t)SOCKLEN(sock), pbuf, LIB_BUFLENGTH,
NULL, 0, gni_flags)) {
errno = saved_errno;
return stoa(sock); /* use address */
}
TRACE(1, ("%s reversed to %s\n", stoa(sock), pbuf));
/*
* Resolve the reversed name and make sure the reversed address
* is among the results.
*/
ZERO(hints);
hints.ai_family = AF(sock);
hints.ai_protocol = IPPROTO_UDP;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = 0;
alist = NULL;
a_info = getaddrinfo(pbuf, svc, &hints, &alist);
if (a_info == EAI_NONAME
#ifdef EAI_NODATA
|| a_info == EAI_NODATA
#endif
) {
hints.ai_flags = AI_CANONNAME;
#ifdef AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG;
#endif
a_info = getaddrinfo(pbuf, svc, &hints, &alist);
}
#ifdef AI_ADDRCONFIG
/* Some older implementations don't like AI_ADDRCONFIG. */
if (a_info == EAI_BADFLAGS) {
hints.ai_flags &= ~AI_ADDRCONFIG;
a_info = getaddrinfo(pbuf, svc, &hints, &alist);
}
#endif
if (a_info)
goto forward_fail;
INSIST(alist != NULL);
for (ai = alist; ai != NULL; ai = ai->ai_next) {
/*
* Make a convenience sockaddr_u copy from ai->ai_addr
* because casting from sockaddr * to sockaddr_u * is
* risking alignment problems on platforms where
* sockaddr_u has stricter alignment than sockaddr,
* such as sparc.
*/
ZERO_SOCK(&addr);
octets = min(sizeof(addr), ai->ai_addrlen);
memcpy(&addr, ai->ai_addr, octets);
if (SOCK_EQ(sock, &addr))
break;
}
freeaddrinfo(alist);
if (ai != NULL) {
errno = saved_errno;
return pbuf; /* forward check passed */
}
forward_fail:
TRACE(1, ("%s forward check lookup fail: %s\n", pbuf,
(char *)gai_strerror(a_info)));
LIB_GETBUF(pliar);
snprintf(pliar, LIB_BUFLENGTH, "%s (%s)", stoa(sock), pbuf);
errno = saved_errno;
return pliar;
}
@@ -0,0 +1,266 @@
/*
* ssl_init.c Common OpenSSL initialization code for the various
* programs which use it.
*
* Moved from ntpd/ntp_crypto.c crypto_setup()
*/
#ifdef HAVE_CONFIG_H
#include <ipntp_config.h>
#endif
#include <ctype.h>
#include <ntp.h>
#include <ntp_debug.h>
#include <lib_strbuf.h>
#ifdef OPENSSL
# include <openssl/crypto.h>
# include <openssl/err.h>
# include <openssl/evp.h>
#include "stdlib.h"
# include <openssl/opensslv.h>
# include "libssl_compat.h"
# ifdef HAVE_OPENSSL_CMAC_H
# include <openssl/cmac.h>
# define CMAC_LENGTH 16
# define CMAC "AES128CMAC"
# endif /*HAVE_OPENSSL_CMAC_H*/
extern int atexit (void (*__func)(void));
int ssl_init_done;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static void
atexit_ssl_cleanup(void)
{
if (!ssl_init_done) {
return;
}
ssl_init_done = FALSE;
EVP_cleanup();
ERR_free_strings();
}
void
ssl_init(void)
{
init_lib();
if ( ! ssl_init_done) {
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
atexit(&atexit_ssl_cleanup);
ssl_init_done = TRUE;
}
}
#else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
void
ssl_init(void)
{
init_lib();
ssl_init_done = TRUE;
}
#endif /* OPENSSL_VERSION_NUMBER */
void
ssl_check_version(void)
{
u_long v;
v = OpenSSL_version_num();
if ((v ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
msyslog(LOG_WARNING,
"OpenSSL version mismatch. Built against %lx, you have %lx",
(u_long)OPENSSL_VERSION_NUMBER, v);
fprintf(stderr,
"OpenSSL version mismatch. Built against %lx, you have %lx\n",
(u_long)OPENSSL_VERSION_NUMBER, v);
}
INIT_SSL();
}
#else /* !OPENSSL */
# define MD5_LENGTH 16
#endif /* OPENSSL */
/*
* keytype_from_text returns OpenSSL NID for digest by name, and
* optionally the associated digest length.
*
* Used by ntpd authreadkeys(), ntpq and ntpdc keytype()
*/
int
keytype_from_text(
const char * text,
size_t * pdigest_len
)
{
int key_type;
u_int digest_len;
#ifdef OPENSSL /* --*-- OpenSSL code --*-- */
const u_long max_digest_len = MAX_MAC_LEN - sizeof(keyid_t);
char * upcased;
char * pch;
EVP_MD const * md;
/*
* OpenSSL digest short names are capitalized, so uppercase the
* digest name before passing to OBJ_sn2nid(). If it is not
* recognized but matches our CMAC string use NID_cmac, or if
* it begins with 'M' or 'm' use NID_md5 to be consistent with
* past behavior.
*/
INIT_SSL();
/* get name in uppercase */
LIB_GETBUF(upcased);
strlcpy(upcased, text, LIB_BUFLENGTH);
for (pch = upcased; '\0' != *pch; pch++) {
*pch = (char)toupper((unsigned char)*pch);
}
key_type = OBJ_sn2nid(upcased);
# ifdef ENABLE_CMAC
if (!key_type && !strncmp(CMAC, upcased, strlen(CMAC) + 1)) {
key_type = NID_cmac;
if (debug) {
fprintf(stderr, "%s:%d:%s():%s:key\n",
__FILE__, __LINE__, __func__, CMAC);
}
}
# endif /*ENABLE_CMAC*/
#else
key_type = 0;
#endif
if (!key_type && 'm' == tolower((unsigned char)text[0])) {
key_type = NID_md5;
}
if (!key_type) {
return 0;
}
if (NULL != pdigest_len) {
#ifdef OPENSSL
md = EVP_get_digestbynid(key_type);
digest_len = (md) ? EVP_MD_size(md) : 0;
if (!md || digest_len <= 0) {
# ifdef ENABLE_CMAC
if (key_type == NID_cmac) {
digest_len = CMAC_LENGTH;
if (debug) {
fprintf(stderr, "%s:%d:%s():%s:len\n",
__FILE__, __LINE__, __func__, CMAC);
}
} else
# endif /*ENABLE_CMAC*/
{
fprintf(stderr,
"key type %s is not supported by OpenSSL\n",
keytype_name(key_type));
msyslog(LOG_ERR,
"key type %s is not supported by OpenSSL\n",
keytype_name(key_type));
return 0;
}
}
if (digest_len > max_digest_len) {
fprintf(stderr,
"key type %s %u octet digests are too big, max %lu\n",
keytype_name(key_type), digest_len,
max_digest_len);
msyslog(LOG_ERR,
"key type %s %u octet digests are too big, max %lu",
keytype_name(key_type), digest_len,
max_digest_len);
return 0;
}
#else
digest_len = MD5_LENGTH;
#endif
*pdigest_len = digest_len;
}
return key_type;
}
/*
* keytype_name returns OpenSSL short name for digest by NID.
*
* Used by ntpq and ntpdc keytype()
*/
const char *
keytype_name(
int nid
)
{
static const char unknown_type[] = "(unknown key type)";
const char *name;
#ifdef OPENSSL
INIT_SSL();
name = OBJ_nid2sn(nid);
# ifdef ENABLE_CMAC
if (NID_cmac == nid) {
name = CMAC;
if (debug) {
fprintf(stderr, "%s:%d:%s():%s:nid\n",
__FILE__, __LINE__, __func__, CMAC);
}
} else
# endif /*ENABLE_CMAC*/
if (NULL == name) {
name = unknown_type;
}
#else /* !OPENSSL follows */
if (NID_md5 == nid)
name = "MD5";
else
name = unknown_type;
#endif
return name;
}
/*
* Use getpassphrase() if configure.ac detected it, as Suns that
* have it truncate the password in getpass() to 8 characters.
*/
#ifdef HAVE_GETPASSPHRASE
# define getpass(str) getpassphrase(str)
#endif
/*
* getpass_keytype() -- shared between ntpq and ntpdc, only vaguely
* related to the rest of ssl_init.c.
*/
char *
getpass_keytype(
int keytype
)
{
char pass_prompt[64 + 11 + 1]; /* 11 for " Password: " */
snprintf(pass_prompt, sizeof(pass_prompt),
"%.64s Password: ", keytype_name(keytype));
return getpass(pass_prompt);
}
@@ -0,0 +1,517 @@
/*
* pretty printing of status information
*/
#ifdef HAVE_CONFIG_H
#include <ipntp_config.h>
#endif
#include <stdio.h>
#include "ntp_stdlib.h"
#include "ntp_fp.h"
#include "ntp.h"
#include "lib_strbuf.h"
#include "ntp_refclock.h"
#include "ntp_control.h"
#include "ntp_string.h"
#ifdef KERNEL_PLL
# include "ntp_syscall.h"
#endif
/*
* Structure for turning various constants into a readable string.
*/
struct codestring {
int code;
const char * const string1;
const char * const string0;
};
/*
* Leap status (leap)
*/
static const struct codestring leap_codes[] = {
{ LEAP_NOWARNING, "leap_none", 0 },
{ LEAP_ADDSECOND, "leap_add_sec", 0 },
{ LEAP_DELSECOND, "leap_del_sec", 0 },
{ LEAP_NOTINSYNC, "leap_alarm", 0 },
{ -1, "leap", 0 }
};
/*
* Clock source status (sync)
*/
static const struct codestring sync_codes[] = {
{ CTL_SST_TS_UNSPEC, "sync_unspec", 0 },
{ CTL_SST_TS_ATOM, "sync_pps", 0 },
{ CTL_SST_TS_LF, "sync_lf_radio", 0 },
{ CTL_SST_TS_HF, "sync_hf_radio", 0 },
{ CTL_SST_TS_UHF, "sync_uhf_radio", 0 },
{ CTL_SST_TS_LOCAL, "sync_local", 0 },
{ CTL_SST_TS_NTP, "sync_ntp", 0 },
{ CTL_SST_TS_UDPTIME, "sync_other", 0 },
{ CTL_SST_TS_WRSTWTCH, "sync_wristwatch", 0 },
{ CTL_SST_TS_TELEPHONE, "sync_telephone", 0 },
{ -1, "sync", 0 }
};
/*
* Peer selection status (sel)
*/
static const struct codestring select_codes[] = {
{ CTL_PST_SEL_REJECT, "sel_reject", 0 },
{ CTL_PST_SEL_SANE, "sel_falsetick", 0 },
{ CTL_PST_SEL_CORRECT, "sel_excess", 0 },
{ CTL_PST_SEL_SELCAND, "sel_outlyer", 0 },
{ CTL_PST_SEL_SYNCCAND, "sel_candidate", 0 },
{ CTL_PST_SEL_EXCESS, "sel_backup", 0 },
{ CTL_PST_SEL_SYSPEER, "sel_sys.peer", 0 },
{ CTL_PST_SEL_PPS, "sel_pps.peer", 0 },
{ -1, "sel", 0 }
};
/*
* Clock status (clk)
*/
static const struct codestring clock_codes[] = {
{ CTL_CLK_OKAY, "clk_unspec", 0 },
{ CTL_CLK_NOREPLY, "clk_no_reply", 0 },
{ CTL_CLK_BADFORMAT, "clk_bad_format", 0 },
{ CTL_CLK_FAULT, "clk_fault", 0 },
{ CTL_CLK_PROPAGATION, "clk_bad_signal", 0 },
{ CTL_CLK_BADDATE, "clk_bad_date", 0 },
{ CTL_CLK_BADTIME, "clk_bad_time", 0 },
{ -1, "clk", 0 }
};
#ifdef FLASH_CODES_UNUSED
/*
* Flash bits -- see ntpq.c tstflags & tstflagnames
*/
static const struct codestring flash_codes[] = {
{ TEST1, "pkt_dup", 0 },
{ TEST2, "pkt_bogus", 0 },
{ TEST3, "pkt_unsync", 0 },
{ TEST4, "pkt_denied", 0 },
{ TEST5, "pkt_auth", 0 },
{ TEST6, "pkt_stratum", 0 },
{ TEST7, "pkt_header", 0 },
{ TEST8, "pkt_autokey", 0 },
{ TEST9, "pkt_crypto", 0 },
{ TEST10, "peer_stratum", 0 },
{ TEST11, "peer_dist", 0 },
{ TEST12, "peer_loop", 0 },
{ TEST13, "peer_unreach", 0 },
{ -1, "flash", 0 }
};
#endif
/*
* System events (sys)
*/
static const struct codestring sys_codes[] = {
{ EVNT_UNSPEC, "unspecified", 0 },
{ EVNT_NSET, "freq_not_set", 0 },
{ EVNT_FSET, "freq_set", 0 },
{ EVNT_SPIK, "spike_detect", 0 },
{ EVNT_FREQ, "freq_mode", 0 },
{ EVNT_SYNC, "clock_sync", 0 },
{ EVNT_SYSRESTART, "restart", 0 },
{ EVNT_SYSFAULT, "panic_stop", 0 },
{ EVNT_NOPEER, "no_sys_peer", 0 },
{ EVNT_ARMED, "leap_armed", 0 },
{ EVNT_DISARMED, "leap_disarmed", 0 },
{ EVNT_LEAP, "leap_event", 0 },
{ EVNT_CLOCKRESET, "clock_step", 0 },
{ EVNT_KERN, "kern", 0 },
{ EVNT_TAI, "TAI", 0 },
{ EVNT_LEAPVAL, "stale_leapsecond_values", 0 },
{ -1, "", 0 }
};
/*
* Peer events (peer)
*/
static const struct codestring peer_codes[] = {
{ PEVNT_MOBIL & ~PEER_EVENT, "mobilize", 0 },
{ PEVNT_DEMOBIL & ~PEER_EVENT, "demobilize", 0 },
{ PEVNT_UNREACH & ~PEER_EVENT, "unreachable", 0 },
{ PEVNT_REACH & ~PEER_EVENT, "reachable", 0 },
{ PEVNT_RESTART & ~PEER_EVENT, "restart", 0 },
{ PEVNT_REPLY & ~PEER_EVENT, "no_reply", 0 },
{ PEVNT_RATE & ~PEER_EVENT, "rate_exceeded", 0 },
{ PEVNT_DENY & ~PEER_EVENT, "access_denied", 0 },
{ PEVNT_ARMED & ~PEER_EVENT, "leap_armed", 0 },
{ PEVNT_NEWPEER & ~PEER_EVENT, "sys_peer", 0 },
{ PEVNT_CLOCK & ~PEER_EVENT, "clock_event", 0 },
{ PEVNT_AUTH & ~PEER_EVENT, "bad_auth", 0 },
{ PEVNT_POPCORN & ~PEER_EVENT, "popcorn", 0 },
{ PEVNT_XLEAVE & ~PEER_EVENT, "interleave_mode", 0 },
{ PEVNT_XERR & ~PEER_EVENT, "interleave_error", 0 },
{ -1, "", 0 }
};
/*
* Peer status bits
*/
static const struct codestring peer_st_bits[] = {
{ CTL_PST_CONFIG, "conf", 0 },
{ CTL_PST_AUTHENABLE, "authenb", 0 },
{ CTL_PST_AUTHENTIC, "auth", 0 },
{ CTL_PST_REACH, "reach", 0 },
{ CTL_PST_BCAST, "bcast", 0 },
/* not used with getcode(), no terminating entry needed */
};
/*
* Restriction match bits
*/
static const struct codestring res_match_bits[] = {
{ RESM_NTPONLY, "ntpport", 0 },
{ RESM_INTERFACE, "interface", 0 },
{ RESM_SOURCE, "source", 0 },
/* not used with getcode(), no terminating entry needed */
};
/*
* Restriction access bits
*/
static const struct codestring res_access_bits[] = {
{ RES_IGNORE, "ignore", 0 },
{ RES_DONTSERVE, "noserve", "serve" },
{ RES_DONTTRUST, "notrust", "trust" },
{ RES_VERSION, "version", 0 },
{ RES_NOPEER, "nopeer", "peer" },
{ RES_NOEPEER, "noepeer", "epeer" },
{ RES_LIMITED, "limited", 0 },
{ RES_NOQUERY, "noquery", "query" },
{ RES_NOMODIFY, "nomodify", 0 },
{ RES_NOTRAP, "notrap", "trap" },
{ RES_LPTRAP, "lptrap", 0 },
{ RES_KOD, "kod", 0 },
{ RES_MSSNTP, "mssntp", 0 },
{ RES_FLAKE, "flake", 0 },
{ RES_NOMRULIST, "nomrulist", 0 },
{ RES_SRVRSPFUZ, "serverresponse fuzz", 0 },
/* not used with getcode(), no terminating entry needed */
};
#ifdef AUTOKEY
/*
* Crypto events (cryp)
*/
static const struct codestring crypto_codes[] = {
{ XEVNT_OK & ~CRPT_EVENT, "success", 0 },
{ XEVNT_LEN & ~CRPT_EVENT, "bad_field_format_or_length", 0 },
{ XEVNT_TSP & ~CRPT_EVENT, "bad_timestamp", 0 },
{ XEVNT_FSP & ~CRPT_EVENT, "bad_filestamp", 0 },
{ XEVNT_PUB & ~CRPT_EVENT, "bad_or_missing_public_key", 0 },
{ XEVNT_MD & ~CRPT_EVENT, "unsupported_digest_type", 0 },
{ XEVNT_KEY & ~CRPT_EVENT, "unsupported_identity_type", 0 },
{ XEVNT_SGL & ~CRPT_EVENT, "bad_signature_length", 0 },
{ XEVNT_SIG & ~CRPT_EVENT, "signature_not_verified", 0 },
{ XEVNT_VFY & ~CRPT_EVENT, "certificate_not_verified", 0 },
{ XEVNT_PER & ~CRPT_EVENT, "host_certificate_expired", 0 },
{ XEVNT_CKY & ~CRPT_EVENT, "bad_or_missing_cookie", 0 },
{ XEVNT_DAT & ~CRPT_EVENT, "bad_or_missing_leapseconds", 0 },
{ XEVNT_CRT & ~CRPT_EVENT, "bad_or_missing_certificate", 0 },
{ XEVNT_ID & ~CRPT_EVENT, "bad_or_missing_group key", 0 },
{ XEVNT_ERR & ~CRPT_EVENT, "protocol_error", 0 },
{ -1, "", 0 }
};
#endif /* AUTOKEY */
#ifdef KERNEL_PLL
/*
* kernel discipline status bits
*/
static const struct codestring k_st_bits[] = {
# ifdef STA_PLL
{ STA_PLL, "pll", 0 },
# endif
# ifdef STA_PPSFREQ
{ STA_PPSFREQ, "ppsfreq", 0 },
# endif
# ifdef STA_PPSTIME
{ STA_PPSTIME, "ppstime", 0 },
# endif
# ifdef STA_FLL
{ STA_FLL, "fll", 0 },
# endif
# ifdef STA_INS
{ STA_INS, "ins", 0 },
# endif
# ifdef STA_DEL
{ STA_DEL, "del", 0 },
# endif
# ifdef STA_UNSYNC
{ STA_UNSYNC, "unsync", 0 },
# endif
# ifdef STA_FREQHOLD
{ STA_FREQHOLD, "freqhold", 0 },
# endif
# ifdef STA_PPSSIGNAL
{ STA_PPSSIGNAL, "ppssignal", 0 },
# endif
# ifdef STA_PPSJITTER
{ STA_PPSJITTER, "ppsjitter", 0 },
# endif
# ifdef STA_PPSWANDER
{ STA_PPSWANDER, "ppswander", 0 },
# endif
# ifdef STA_PPSERROR
{ STA_PPSERROR, "ppserror", 0 },
# endif
# ifdef STA_CLOCKERR
{ STA_CLOCKERR, "clockerr", 0 },
# endif
# ifdef STA_NANO
{ STA_NANO, "nano", 0 },
# endif
# ifdef STA_MODE
{ STA_MODE, "mode=fll", 0 },
# endif
# ifdef STA_CLK
{ STA_CLK, "src=B", 0 },
# endif
/* not used with getcode(), no terminating entry needed */
};
#endif /* KERNEL_PLL */
/* Forwards */
static const char * getcode(int, const struct codestring *);
static const char * getevents(int);
static const char * peer_st_flags(u_char pst);
/*
* getcode - return string corresponding to code
*/
static const char *
getcode(
int code,
const struct codestring * codetab
)
{
char * buf;
while (codetab->code != -1) {
if (codetab->code == code)
return codetab->string1;
codetab++;
}
LIB_GETBUF(buf);
snprintf(buf, LIB_BUFLENGTH, "%s_%d", codetab->string1, code);
return buf;
}
/*
* getevents - return a descriptive string for the event count
*/
static const char *
getevents(
int cnt
)
{
char * buf;
if (cnt == 0)
return "no events";
LIB_GETBUF(buf);
snprintf(buf, LIB_BUFLENGTH, "%d event%s", cnt,
(1 == cnt)
? ""
: "s");
return buf;
}
/*
* decode_bitflags()
*
* returns a human-readable string with a keyword from tab for each bit
* set in bits, separating multiple entries with text of sep2.
*/
static const char *
decode_bitflags(
int bits,
const char * sep2,
const struct codestring * tab,
size_t tab_ct
)
{
const char * sep;
char * buf;
char * pch;
char * lim;
size_t b;
int rc;
int saved_errno; /* for use in DPRINTF with %m */
saved_errno = errno;
LIB_GETBUF(buf);
pch = buf;
lim = buf + LIB_BUFLENGTH;
sep = "";
for (b = 0; b < tab_ct; b++) {
const char * flagstr;
if (tab[b].code & bits) {
flagstr = tab[b].string1;
} else {
flagstr = tab[b].string0;
}
if (flagstr) {
size_t avail = lim - pch;
rc = snprintf(pch, avail, "%s%s", sep,
flagstr);
if ((size_t)rc >= avail)
goto toosmall;
pch += rc;
sep = sep2;
}
}
return buf;
toosmall:
snprintf(buf, LIB_BUFLENGTH,
"decode_bitflags(%s) can't decode 0x%x in %d bytes",
(tab == peer_st_bits)
? "peer_st"
:
#ifdef KERNEL_PLL
(tab == k_st_bits)
? "kern_st"
:
#endif
"",
bits, (int)LIB_BUFLENGTH);
errno = saved_errno;
return buf;
}
static const char *
peer_st_flags(
u_char pst
)
{
return decode_bitflags(pst, ", ", peer_st_bits,
COUNTOF(peer_st_bits));
}
const char *
res_match_flags(
u_short mf
)
{
return decode_bitflags(mf, " ", res_match_bits,
COUNTOF(res_match_bits));
}
const char *
res_access_flags(
u_int32 af
)
{
return decode_bitflags(af, " ", res_access_bits,
COUNTOF(res_access_bits));
}
#ifdef KERNEL_PLL
const char *
k_st_flags(
unsigned int st
)
{
return decode_bitflags(st, " ", k_st_bits, COUNTOF(k_st_bits));
}
#endif /* KERNEL_PLL */
/*
* statustoa - return a descriptive string for a peer status
*/
char *
statustoa(
int type,
int st
)
{
char * cb;
char * cc;
u_char pst;
LIB_GETBUF(cb);
switch (type) {
case TYPE_SYS:
snprintf(cb, LIB_BUFLENGTH, "%s, %s, %s, %s",
getcode(CTL_SYS_LI(st), leap_codes),
getcode(CTL_SYS_SOURCE(st), sync_codes),
getevents(CTL_SYS_NEVNT(st)),
getcode(CTL_SYS_EVENT(st), sys_codes));
break;
case TYPE_PEER:
pst = (u_char)CTL_PEER_STATVAL(st);
snprintf(cb, LIB_BUFLENGTH, "%s, %s, %s",
peer_st_flags(pst),
getcode(pst & 0x7, select_codes),
getevents(CTL_PEER_NEVNT(st)));
if (CTL_PEER_EVENT(st) != EVNT_UNSPEC) {
cc = cb + strlen(cb);
snprintf(cc, LIB_BUFLENGTH - (cc - cb), ", %s",
getcode(CTL_PEER_EVENT(st),
peer_codes));
}
break;
case TYPE_CLOCK:
snprintf(cb, LIB_BUFLENGTH, "%s, %s",
getevents(CTL_SYS_NEVNT(st)),
getcode((st) & 0xf, clock_codes));
break;
}
return cb;
}
const char *
eventstr(
int num
)
{
if (num & PEER_EVENT)
return (getcode(num & ~PEER_EVENT, peer_codes));
#ifdef AUTOKEY
else if (num & CRPT_EVENT)
return (getcode(num & ~CRPT_EVENT, crypto_codes));
#endif /* AUTOKEY */
else
return (getcode(num, sys_codes));
}
const char *
ceventstr(
int num
)
{
return getcode(num, clock_codes);
}
@@ -0,0 +1,192 @@
#ifdef HAVE_CONFIG_H
# include <ipntp_config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <ipcom_type.h>
#include <ipcom_os.h>
#include <ipntp.h>
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
static ctrl_c_fn ctrl_c_hook;
#ifndef SYS_WINNT
RETSIGTYPE sigint_handler(int);
#else
BOOL WINAPI console_event_handler(DWORD);
#endif
#ifdef HAVE_SIGACTION
# ifdef SA_RESTART
# define Z_SA_RESTART SA_RESTART
# else
# define Z_SA_RESTART 0
# endif
void
signal_no_reset(
int sig,
void (*func)(int)
)
{
int n;
struct sigaction vec;
struct sigaction ovec;
ZERO(vec);
sigemptyset(&vec.sa_mask);
vec.sa_handler = func;
/* Added for PPS clocks on Solaris 7 which get EINTR errors */
# ifdef SIGPOLL
if (SIGPOLL == sig)
vec.sa_flags = Z_SA_RESTART;
# endif
# ifdef SIGIO
if (SIGIO == sig)
vec.sa_flags = Z_SA_RESTART;
# endif
do
n = sigaction(sig, &vec, &ovec);
while (-1 == n && EINTR == errno);
if (-1 == n) {
perror("sigaction");
ipntp_exit_callback(ipcom_getpid());
}
}
#elif HAVE_SIGVEC
void
signal_no_reset(
int sig,
RETSIGTYPE (*func)(int)
)
{
struct sigvec sv;
int n;
ZERO(sv);
sv.sv_handler = func;
n = sigvec(sig, &sv, (struct sigvec *)NULL);
if (-1 == n) {
perror("sigvec");
ipntp_exit_callback(ipcom_getpid());
}
}
#elif HAVE_SIGSET
void
signal_no_reset(
int sig,
RETSIGTYPE (*func)(int)
)
{
int n;
n = sigset(sig, func);
if (-1 == n) {
perror("sigset");
ipntp_exit_callback(ipcom_getpid());
}
}
#else
/* Beware! This implementation resets the signal to SIG_DFL */
void
signal_no_reset(
int sig,
RETSIGTYPE (*func)(int)
)
{
#ifndef SIG_ERR
# define SIG_ERR (-1)
#endif
if (SIG_ERR == signal(sig, func)) {
perror("signal");
ipntp_exit_callback(ipcom_getpid());
}
}
#endif
#ifndef SYS_WINNT
/*
* POSIX implementation of set_ctrl_c_hook()
*/
RETSIGTYPE
sigint_handler(
int signum
)
{
UNUSED_ARG(signum);
if (ctrl_c_hook != NULL)
(*ctrl_c_hook)();
}
void
set_ctrl_c_hook(
ctrl_c_fn c_hook
)
{
RETSIGTYPE (*handler)(int);
if (NULL == c_hook) {
handler = SIG_DFL;
signal_no_reset(SIGINT, handler);
ctrl_c_hook = c_hook;
} else {
ctrl_c_hook = c_hook;
handler = &sigint_handler;
signal_no_reset(SIGINT, handler);
}
}
#else /* SYS_WINNT follows */
/*
* Windows implementation of set_ctrl_c_hook()
*/
BOOL WINAPI
console_event_handler(
DWORD dwCtrlType
)
{
BOOL handled;
if (CTRL_C_EVENT == dwCtrlType && ctrl_c_hook != NULL) {
(*ctrl_c_hook)();
handled = TRUE;
} else {
handled = FALSE;
}
return handled;
}
void
set_ctrl_c_hook(
ctrl_c_fn c_hook
)
{
BOOL install;
if (NULL == c_hook) {
ctrl_c_hook = NULL;
install = FALSE;
} else {
ctrl_c_hook = c_hook;
install = TRUE;
}
if (!SetConsoleCtrlHandler(&console_event_handler, install))
msyslog(LOG_ERR, "Can't %s console control handler: %m",
(install)
? "add"
: "remove");
}
#endif /* SYS_WINNT */
@@ -0,0 +1,711 @@
/*
* systime -- routines to fiddle a UNIX clock.
*
* ATTENTION: Get approval from Dave Mills on all changes to this file!
*
*/
#include <ipntp_config.h>
#include <ipcom_clib.h>
#include <ipcom_time.h>
#include <math.h>
#include "ntp.h"
#include "ntpd.h"
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
#include "ntp_random.h"
#include "iosignal.h"
#include "timevalops.h"
#include "timespecops.h"
#include "ntp_calendar.h"
#include "lib_strbuf.h"
#include "ipntp.h"
extern Ip_u32 ipsntp_server_nsec_to_fraction(Ip_u32 nsecs);
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif /* HAVE_UTMP_H */
#ifdef HAVE_UTMPX_H
# include <utmpx.h>
#endif /* HAVE_UTMPX_H */
int allow_panic = FALSE; /* allow panic correction (-g) */
int enable_panic_check = TRUE; /* Can we check allow_panic's state? */
u_long sys_lamport; /* Lamport violation */
u_long sys_tsrounding; /* timestamp rounding errors */
#ifndef USE_COMPILETIME_PIVOT
# define USE_COMPILETIME_PIVOT 1
#endif
/*
* These routines (get_systime, step_systime, adj_systime) implement an
* interface between the system independent NTP clock and the Unix
* system clock in various architectures and operating systems. Time is
* a precious quantity in these routines and every effort is made to
* minimize errors by unbiased rounding and amortizing adjustment
* residues.
*
* In order to improve the apparent resolution, provide unbiased
* rounding and most importantly ensure that the readings cannot be
* predicted, the low-order unused portion of the time below the minimum
* time to read the clock is filled with an unbiased random fuzz.
*
* The sys_tick variable specifies the system clock tick interval in
* seconds, for stepping clocks, defined as those which return times
* less than MINSTEP greater than the previous reading. For systems that
* use a high-resolution counter such that each clock reading is always
* at least MINSTEP greater than the prior, sys_tick is the time to read
* the system clock.
*
* The sys_fuzz variable measures the minimum time to read the system
* clock, regardless of its precision. When reading the system clock
* using get_systime() after sys_tick and sys_fuzz have been determined,
* ntpd ensures each unprocessed clock reading is no less than sys_fuzz
* later than the prior unprocessed reading, and then fuzzes the bits
* below sys_fuzz in the timestamp returned, ensuring each of its
* resulting readings is strictly later than the previous.
*
* When slewing the system clock using adj_systime() (with the kernel
* loop discipline unavailable or disabled), adjtime() offsets are
* quantized to sys_tick, if sys_tick is greater than sys_fuzz, which
* is to say if the OS presents a stepping clock. Otherwise, offsets
* are quantized to the microsecond resolution of adjtime()'s timeval
* input. The remaining correction sys_residual is carried into the
* next adjtime() and meanwhile is also factored into get_systime()
* readings.
*/
double sys_tick = 1e-6; /* 1 us tickadj() , tick size or time to read (s) */
double sys_fuzz = 0; /* min. time to read the clock (s) */
long sys_fuzz_nsec = 0; /* min. time to read the clock (ns) */
double measured_tick; /* non-overridable sys_tick (s) */
double sys_residual = 0; /* adjustment residue (s) */
int trunc_os_clock; /* sys_tick > measured_tick */
time_stepped_callback step_callback;
#ifndef SIM
/* perlinger@ntp.org: As 'get_sysime()' does it's own check for clock
* backstepping, this could probably become a local variable in
* 'get_systime()' and the cruft associated with communicating via a
* static value could be removed after the v4.2.8 release.
*/
static int lamport_violated = FALSE; /* clock was stepped back */
#endif /* !SIM */
#ifdef NTP_DEBUG
static int systime_init_done;
# define DONE_SYSTIME_INIT() systime_init_done = TRUE
#else
# define DONE_SYSTIME_INIT() do {} while (FALSE)
#endif
#ifdef HAVE_SIGNALED_IO
int using_sigio;
#endif
#ifdef SYS_WINNT
CRITICAL_SECTION get_systime_cs;
#endif
void
set_sys_fuzz(
double fuzz_val
)
{
sys_fuzz = fuzz_val;
INSIST(sys_fuzz >= 0);
INSIST(sys_fuzz <= 1.0);
#ifdef NTP_VXWORKS_6
sys_fuzz_nsec = (long)(sys_fuzz * 1e9 + 0.5);
#else
/* [Bug 3450] ensure nsec fuzz >= sys_fuzz to reduce chance of
* short-falling fuzz advance
*/
sys_fuzz_nsec = (long)ceil(sys_fuzz * 1e9);
#endif
}
void
init_systime(void)
{
sys_tick = 1e-6;
sys_fuzz = 0;
sys_fuzz_nsec = 0;
measured_tick = 0;
sys_residual = 0;
trunc_os_clock = 0;
INIT_GET_SYSTIME_CRITSEC();
INIT_WIN_PRECISE_TIME();
DONE_SYSTIME_INIT();
}
#ifndef SIM /* ntpsim.c has get_systime() and friends for sim */
static inline void
get_ostime(
struct timespec * tsp
)
{
int rc;
long ticks;
struct timeval tv;
rc = ipcom_gettimeofday(&tv, IP_NULL);
tsp->tv_sec = tv.tv_sec;
tsp->tv_nsec = tv.tv_usec * 1000;
if (rc < 0) {
msyslog(LOG_ERR, "read system clock failed: %m (%d)",
errno);
ipntp_exit_callback(ipcom_getpid());
}
if (trunc_os_clock) {
ticks = (long)((tsp->tv_nsec * 1e-9) / sys_tick);
tsp->tv_nsec = (long)(ticks * 1e9 * sys_tick);
}
}
/*
* get_systime - return system time in NTP timestamp format.
*/
void
get_systime(
l_fp *now /* system time */
)
{
static struct timespec ts_last; /* last sampled os time */
static struct timespec ts_prev; /* prior os time */
static l_fp lfp_prev; /* prior result */
struct timespec ts; /* seconds and nanoseconds */
struct timespec ts_min; /* earliest permissible */
struct timespec ts_lam; /* lamport fictional increment */
double dfuzz;
l_fp result;
l_fp lfpfuzz;
l_fp lfpdelta;
get_ostime(&ts);
DEBUG_REQUIRE(systime_init_done);
ENTER_GET_SYSTIME_CRITSEC();
/* First check if here was a Lamport violation, that is, two
* successive calls to 'get_ostime()' resulted in negative
* time difference. Use a few milliseconds of permissible
* tolerance -- being too sharp can hurt here. (This is intented
* for the Win32 target, where the HPC interpolation might
* introduce small steps backward. It should not be an issue on
* systems where get_ostime() results in a true syscall.)
*/
if (cmp_tspec(add_tspec_ns(ts, 50000000), ts_last) < 0) {
lamport_violated = 1;
sys_lamport++;
}
ts_last = ts;
/*
* After default_get_precision() has set a nonzero sys_fuzz,
* ensure every reading of the OS clock advances by at least
* sys_fuzz over the prior reading, thereby assuring each
* fuzzed result is strictly later than the prior. Limit the
* necessary fiction to 1 second.
*/
if (!USING_SIGIO()) {
ts_min = add_tspec_ns(ts_prev, sys_fuzz_nsec);
if (cmp_tspec(ts, ts_min) < 0) {
ts_lam = sub_tspec(ts_min, ts);
if (ts_lam.tv_sec > 0 && !lamport_violated) {
msyslog(LOG_ERR,
"get_systime Lamport advance exceeds one second (%.9f)",
ts_lam.tv_sec +
1e-9 * ts_lam.tv_nsec);
ipntp_exit_callback(ipcom_getpid());
}
if (!lamport_violated)
ts = ts_min;
}
ts_prev = ts;
}
/* convert from timespec to l_fp fixed-point */
result = tspec_stamp_to_lfp(ts);
/*
* Add in the fuzz. 'ntp_random()' returns [0..2**31-1] so we
* must scale up the result by 2.0 to cover the full fractional
* range.
*/
dfuzz = ntp_random() * 2. / FRAC * sys_fuzz;
DTOLFP(dfuzz, &lfpfuzz);
L_ADD(&result, &lfpfuzz);
/*
* Ensure result is strictly greater than prior result (ignoring
* sys_residual's effect for now) once sys_fuzz has been
* determined.
*
* [Bug 3450] Rounding errors and time slew can lead to a
* violation of the expected postcondition. This is bound to
* happen from time to time (depending on state of the random
* generator, the current slew and the closeness of system time
* stamps drawn) and does not warrant a syslog entry. Instead it
* makes much more sense to ensure the postcondition and hop
* along silently.
*/
if (!USING_SIGIO()) {
if ( !L_ISZERO(&lfp_prev)
&& !lamport_violated
&& (sys_fuzz > 0.0)
) {
lfpdelta = result;
L_SUB(&lfpdelta, &lfp_prev);
L_SUBUF(&lfpdelta, 1);
if (lfpdelta.l_i < 0)
{
L_NEG(&lfpdelta);
DPRINTF(1, ("get_systime: postcond failed by %s secs, fixed\n",
lfptoa(&lfpdelta, 9)));
result = lfp_prev;
L_ADDUF(&result, 1);
sys_tsrounding++;
}
}
lfp_prev = result;
if (lamport_violated)
lamport_violated = FALSE;
}
LEAVE_GET_SYSTIME_CRITSEC();
*now = result;
}
/*
* adj_systime - adjust system time by the argument.
*/
#if !defined SYS_WINNT
int /* 0 okay, 1 error */
adj_systime(
double now /* adjustment (s) */
)
{
struct timeval adjtv; /* new adjustment */
struct timeval oadjtv; /* residual adjustment */
double quant; /* quantize to multiples of */
double dtemp;
long ticks;
int isneg = 0;
/*
* The Windows port adj_systime() depends on being called each
* second even when there's no additional correction, to allow
* emulation of adjtime() behavior on top of an API that simply
* sets the current rate. This POSIX implementation needs to
* ignore invocations with zero correction, otherwise ongoing
* EVNT_NSET adjtime() can be aborted by a tiny adjtime()
* triggered by sys_residual.
*/
if (0. == now) {
if (enable_panic_check && allow_panic) {
msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!");
INSIST(!allow_panic);
}
return TRUE;
}
/*
* Most Unix adjtime() implementations adjust the system clock
* in microsecond quanta, but some adjust in 10-ms quanta. We
* carefully round the adjustment to the nearest quantum, then
* adjust in quanta and keep the residue for later.
*/
dtemp = now + sys_residual;
if (dtemp < 0) {
isneg = 1;
dtemp = -dtemp;
}
adjtv.tv_sec = (time_t)dtemp;
dtemp -= (double)adjtv.tv_sec;
if (sys_tick > sys_fuzz)
quant = sys_tick;
else
quant = 1e-6;
ticks = (long)(dtemp / quant + .5);
adjtv.tv_usec = (long)(ticks * quant * 1.e6 + .5);
/* The rounding in the conversions could us push over the
* limits: make sure the result is properly normalised!
* note: sign comes later, all numbers non-negative here.
*/
if (adjtv.tv_usec >= 1000000) {
adjtv.tv_sec += 1;
adjtv.tv_usec -= 1000000;
dtemp -= 1.;
}
/* set the new residual with leftover from correction */
sys_residual = dtemp - adjtv.tv_usec * 1.e-6;
/*
* Convert to signed seconds and microseconds for the Unix
* adjtime() system call. Note we purposely lose the adjtime()
* leftover.
*/
if (isneg) {
adjtv.tv_sec = -adjtv.tv_sec;
adjtv.tv_usec = -adjtv.tv_usec;
sys_residual = -sys_residual;
}
if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {
if (adjtime(&adjtv, &oadjtv) < 0) {
msyslog(LOG_ERR, "adj_systime: %m");
if (enable_panic_check && allow_panic) {
msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!");
}
return FALSE;
}
}
if (enable_panic_check && allow_panic) {
msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!");
}
return TRUE;
}
#endif
/*
* helper to keep utmp/wtmp up to date
*/
static void
update_uwtmp(
struct timeval timetv,
struct timeval tvlast
)
{
struct timeval tvdiff;
#ifdef NTP_VXWORKS_7
struct timeval tmpval, tmpvallast;
#endif
/*
* FreeBSD, for example, has:
* struct utmp {
* char ut_line[UT_LINESIZE];
* char ut_name[UT_NAMESIZE];
* char ut_host[UT_HOSTSIZE];
* long ut_time;
* };
* and appends line="|", name="date", host="", time for the OLD
* and appends line="{", name="date", host="", time for the NEW
* to _PATH_WTMP .
*
* Some OSes have utmp, some have utmpx.
*/
/*
* Write old and new time entries in utmp and wtmp if step
* adjustment is greater than one second.
*
* This might become even Uglier...
*/
#ifdef NTP_VXWORKS_7
tmpval.tv_sec = timetv.tv_sec;
tmpval.tv_usec = timetv.tv_usec;
tmpvallast.tv_sec = tvlast.tv_sec;
tmpvallast.tv_usec = tvlast.tv_usec;
tmpval = abs_tval(sub_tval(tmpval, tmpvallast));
tvdiff.tv_sec = tmpval.tv_sec;
tvdiff.tv_usec = tmpval.tv_usec;
#else
tvdiff = abs_tval(sub_tval(timetv, tvlast));
#endif
if (tvdiff.tv_sec > 0) {
#ifdef HAVE_UTMP_H
struct utmp ut;
#endif
#ifdef HAVE_UTMPX_H
struct utmpx utx;
#endif
#ifdef HAVE_UTMP_H
ZERO(ut);
#endif
#ifdef HAVE_UTMPX_H
ZERO(utx);
#endif
/* UTMP */
#ifdef UPDATE_UTMP
# ifdef HAVE_PUTUTLINE
# ifndef _PATH_UTMP
# define _PATH_UTMP UTMP_FILE
# endif
utmpname(_PATH_UTMP);
ut.ut_type = OLD_TIME;
strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
ut.ut_time = tvlast.tv_sec;
setutent();
pututline(&ut);
ut.ut_type = NEW_TIME;
strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line));
ut.ut_time = timetv.tv_sec;
setutent();
pututline(&ut);
endutent();
# else /* not HAVE_PUTUTLINE */
# endif /* not HAVE_PUTUTLINE */
#endif /* UPDATE_UTMP */
/* UTMPX */
#ifdef UPDATE_UTMPX
# ifdef HAVE_PUTUTXLINE
utx.ut_type = OLD_TIME;
strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
utx.ut_tv = tvlast;
setutxent();
pututxline(&utx);
utx.ut_type = NEW_TIME;
strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line));
utx.ut_tv = timetv;
setutxent();
pututxline(&utx);
endutxent();
# else /* not HAVE_PUTUTXLINE */
# endif /* not HAVE_PUTUTXLINE */
#endif /* UPDATE_UTMPX */
/* WTMP */
#ifdef UPDATE_WTMP
# ifdef HAVE_PUTUTLINE
# ifndef _PATH_WTMP
# define _PATH_WTMP WTMP_FILE
# endif
utmpname(_PATH_WTMP);
ut.ut_type = OLD_TIME;
strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
ut.ut_time = tvlast.tv_sec;
setutent();
pututline(&ut);
ut.ut_type = NEW_TIME;
strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line));
ut.ut_time = timetv.tv_sec;
setutent();
pututline(&ut);
endutent();
# else /* not HAVE_PUTUTLINE */
# endif /* not HAVE_PUTUTLINE */
#endif /* UPDATE_WTMP */
/* WTMPX */
#ifdef UPDATE_WTMPX
# ifdef HAVE_PUTUTXLINE
utx.ut_type = OLD_TIME;
utx.ut_tv = tvlast;
strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
# ifdef HAVE_UPDWTMPX
updwtmpx(WTMPX_FILE, &utx);
# else /* not HAVE_UPDWTMPX */
# endif /* not HAVE_UPDWTMPX */
# else /* not HAVE_PUTUTXLINE */
# endif /* not HAVE_PUTUTXLINE */
# ifdef HAVE_PUTUTXLINE
utx.ut_type = NEW_TIME;
utx.ut_tv = timetv;
strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line));
# ifdef HAVE_UPDWTMPX
updwtmpx(WTMPX_FILE, &utx);
# else /* not HAVE_UPDWTMPX */
# endif /* not HAVE_UPDWTMPX */
# else /* not HAVE_PUTUTXLINE */
# endif /* not HAVE_PUTUTXLINE */
#endif /* UPDATE_WTMPX */
}
}
/*
* step_systime - step the system clock.
*/
int
step_systime(
double step
)
{
time_t pivot; /* for ntp era unfolding */
struct timeval timetv, tvlast;
#ifdef NTP_VXWORKS_7
struct timeval tmpval;
#endif
l_fp fp_ofs, fp_sys; /* offset and target system time in FP */
/*
* Get pivot time for NTP era unfolding. Since we don't step
* very often, we can afford to do the whole calculation from
* scratch. And we're not in the time-critical path yet.
*/
#if SIZEOF_TIME_T > 4
pivot = basedate_get_eracenter();
#else
/* This makes sure the resulting time stamp is on or after
* 1969-12-31/23:59:59 UTC and gives us additional two years,
* from the change of NTP era in 2036 to the UNIX rollover in
* 2038. (Minus one second, but that won't hurt.) We *really*
* need a longer 'time_t' after that! Or a different baseline,
* but that would cause other serious trouble, too.
*/
pivot = 0x7FFFFFFF;
#endif
/* get the complete jump distance as l_fp */
DTOLFP(sys_residual, &fp_sys);
DTOLFP(step, &fp_ofs);
L_ADD(&fp_ofs, &fp_sys);
/* ---> time-critical path starts ---> */
(void)ipcom_gettimeofday(&tvlast, IP_NULL);
fp_sys.l_i = (int)tvlast.tv_sec + JAN_1970;
fp_sys.l_uf = (unsigned int)ipsntp_server_nsec_to_fraction(tvlast.tv_usec * 1000);
/* get the target time as l_fp */
L_ADD(&fp_sys, &fp_ofs);
/* unfold the new system time */
#ifdef NTP_VXWORKS_7
tmpval = lfp_stamp_to_tval(fp_sys, &pivot);
timetv.tv_sec = tmpval.tv_sec;
timetv.tv_usec = tmpval.tv_usec;
#else
timetv = lfp_stamp_to_tval(fp_sys, &pivot);
#endif
/* now set new system time */
if (ntp_set_tod(&timetv, NULL) != 0) {
msyslog(LOG_ERR, "step-systime: %m");
if (enable_panic_check && allow_panic) {
msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!");
}
return FALSE;
}
/* <--- time-critical path ended with 'ntp_set_tod()' <--- */
sys_residual = 0;
lamport_violated = (step < 0);
if (step_callback)
(*step_callback)();
#ifdef NEED_HPUX_ADJTIME
/*
* CHECKME: is this correct when called by ntpdate?????
*/
_clear_adjtime();
#endif
update_uwtmp(timetv, tvlast);
if (enable_panic_check && allow_panic) {
msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!");
INSIST(!allow_panic);
}
return TRUE;
}
static const char *
tv_fmt_libbuf(
const struct timeval * ptv
)
{
char * retv;
vint64 secs;
ntpcal_split dds;
struct calendar jd;
secs = time_to_vint64(&ptv->tv_sec);
dds = ntpcal_daysplit(&secs);
ntpcal_daysplit_to_date(&jd, &dds, DAY_UNIX_STARTS);
LIB_GETBUF(retv);
snprintf(retv, LIB_BUFLENGTH,
"%04hu-%02hu-%02hu/%02hu:%02hu:%02hu.%06u",
jd.year, (u_short)jd.month, (u_short)jd.monthday,
(u_short)jd.hour, (u_short)jd.minute, (u_short)jd.second,
(u_int)ptv->tv_usec);
return retv;
}
int /*BOOL*/
clamp_systime(void)
{
#if SIZEOF_TIME_T > 4
struct timeval tvbase, tvlast;
struct timespec timets;
tvbase.tv_sec = basedate_get_erabase();
tvbase.tv_usec = 0;
/* ---> time-critical path starts ---> */
/* get the current time as l_fp (without fuzz) and as struct timeval */
get_ostime(&timets);
tvlast.tv_sec = timets.tv_sec;
tvlast.tv_usec = (timets.tv_nsec + 500) / 1000;
if (tvlast.tv_usec >= 1000000) {
tvlast.tv_usec -= 1000000;
tvlast.tv_sec += 1;
}
if (tvbase.tv_sec > tvlast.tv_sec) {
/* now set new system time */
if (ntp_set_tod(&tvbase, NULL) != 0) {
msyslog(LOG_ERR, "clamp-systime: %m");
return FALSE;
}
} else {
msyslog(LOG_INFO,
"clamp-systime: clock (%s) in allowed range",
tv_fmt_libbuf(&tvlast));
return FALSE;
}
/* <--- time-critical path ended with 'ntp_set_tod()' <--- */
sys_residual = 0;
lamport_violated = (tvbase.tv_sec < tvlast.tv_sec);
if (step_callback)
(*step_callback)();
# ifdef NEED_HPUX_ADJTIME
/*
* CHECKME: is this correct when called by ntpdate?????
*/
_clear_adjtime();
# endif
update_uwtmp(tvbase, tvlast);
msyslog(LOG_WARNING,
"clamp-systime: clock stepped from %s to %s!",
tv_fmt_libbuf(&tvlast), tv_fmt_libbuf(&tvbase));
return TRUE;
#else
return FALSE;
#endif
}
#endif /* !SIM */
@@ -0,0 +1,2 @@
#define SIM
#include "systime.c"
@@ -0,0 +1,233 @@
/*
* timespecops.c -- calculations on 'struct timespec' values
*
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
* The contents of 'html/copyright.html' apply.
*
*/
#include "ipntp_config.h"
#include <sys/types.h>
#include <stdio.h>
#include <math.h>
#include "ntp.h"
#include "timetoa.h"
#include "timespecops.h"
/* nanoseconds per second */
#define NANOSECONDS 1000000000
/* conversion between l_fp fractions and nanoseconds */
#ifdef HAVE_U_INT64
# define FTOTVN(tsf) \
((int32) \
(((u_int64)(tsf) * NANOSECONDS + 0x80000000) >> 32))
# define TVNTOF(tvu) \
((u_int32) \
((((u_int64)(tvu) << 32) + NANOSECONDS / 2) / \
NANOSECONDS))
#else
# define NSECFRAC (FRAC / NANOSECONDS)
# define FTOTVN(tsf) \
((int32)((tsf) / NSECFRAC + 0.5))
# define TVNTOF(tvu) \
((u_int32)((tvu) * NSECFRAC + 0.5))
#endif
/* make sure nanoseconds are in nominal range */
struct timespec
normalize_tspec(
struct timespec x
)
{
#if SIZEOF_LONG > 4
long z;
/*
* tv_nsec is of type 'long', and on a 64-bit machine using only
* loops becomes prohibitive once the upper 32 bits get
* involved. On the other hand, division by constant should be
* fast enough; so we do a division of the nanoseconds in that
* case. The floor adjustment step follows with the standard
* normalisation loops. And labs() is intentionally not used
* here: it has implementation-defined behaviour when applied
* to LONG_MIN.
*/
if (x.tv_nsec < -3l * NANOSECONDS ||
x.tv_nsec > 3l * NANOSECONDS) {
z = x.tv_nsec / NANOSECONDS;
x.tv_nsec -= z * NANOSECONDS;
x.tv_sec += z;
}
#endif
/* since 10**9 is close to 2**32, we don't divide but do a
* normalisation in a loop; this takes 3 steps max, and should
* outperform a division even if the mul-by-inverse trick is
* employed. */
if (x.tv_nsec < 0)
do {
x.tv_nsec += NANOSECONDS;
x.tv_sec--;
} while (x.tv_nsec < 0);
else if (x.tv_nsec >= NANOSECONDS)
do {
x.tv_nsec -= NANOSECONDS;
x.tv_sec++;
} while (x.tv_nsec >= NANOSECONDS);
return x;
}
/* x = abs(a) */
struct timespec
abs_tspec(
struct timespec a
)
{
struct timespec c;
c = normalize_tspec(a);
if (c.tv_sec < 0) {
if (c.tv_nsec != 0) {
c.tv_sec = -c.tv_sec - 1;
c.tv_nsec = NANOSECONDS - c.tv_nsec;
} else {
c.tv_sec = -c.tv_sec;
}
}
return c;
}
/*
* compare previously-normalised a and b
* return 1 / 0 / -1 if a < / == / > b
*/
int
cmp_tspec(
struct timespec a,
struct timespec b
)
{
int r;
r = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec);
if (0 == r)
r = (a.tv_nsec > b.tv_nsec) -
(a.tv_nsec < b.tv_nsec);
return r;
}
/*
* test previously-normalised a
* return 1 / 0 / -1 if a < / == / > 0
*/
int
test_tspec(
struct timespec a
)
{
int r;
r = (a.tv_sec > 0) - (a.tv_sec < 0);
if (r == 0)
r = (a.tv_nsec > 0);
return r;
}
/*
* convert to l_fp type, relative and absolute
*/
/* convert from timespec duration to l_fp duration */
l_fp
tspec_intv_to_lfp(
struct timespec x
)
{
struct timespec v;
l_fp y;
v = normalize_tspec(x);
y.l_uf = TVNTOF(v.tv_nsec);
y.l_i = (int32)v.tv_sec;
return y;
}
/* convert from l_fp type, relative signed/unsigned and absolute */
struct timespec
lfp_intv_to_tspec(
l_fp x
)
{
struct timespec out;
l_fp absx;
int neg;
neg = L_ISNEG(&x);
absx = x;
if (neg) {
L_NEG(&absx);
}
out.tv_nsec = FTOTVN(absx.l_uf);
out.tv_sec = absx.l_i;
if (neg) {
out.tv_sec = -out.tv_sec;
out.tv_nsec = -out.tv_nsec;
out = normalize_tspec(out);
}
return out;
}
struct timespec
lfp_uintv_to_tspec(
l_fp x
)
{
struct timespec out;
out.tv_nsec = FTOTVN(x.l_uf);
out.tv_sec = x.l_ui;
return out;
}
/*
* absolute (timestamp) conversion. Input is time in NTP epoch, output
* is in UN*X epoch. The NTP time stamp will be expanded around the
* pivot time *p or the current time, if p is NULL.
*/
struct timespec
lfp_stamp_to_tspec(
l_fp x,
const time_t * p
)
{
struct timespec out;
vint64 sec;
sec = ntpcal_ntp_to_time(x.l_ui, p);
out.tv_nsec = FTOTVN(x.l_uf);
/* copying a vint64 to a time_t needs some care... */
#if SIZEOF_TIME_T <= 4
out.tv_sec = (time_t)sec.d_s.lo;
#elif defined(HAVE_INT64)
out.tv_sec = (time_t)sec.q_s;
#else
out.tv_sec = ((time_t)sec.d_s.hi << 32) | sec.d_s.lo;
#endif
return out;
}
/* -*-EOF-*- */
@@ -0,0 +1,119 @@
/*
* timetoa.c -- time_t related string formatting
*
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
* The contents of 'html/copyright.html' apply.
*
* Printing a 'time_t' has a lot of portability pitfalls, due to it's
* opaque base type. The only requirement imposed by the standard is
* that it must be a numeric type. For all practical purposes it's a
* signed int, and 32 bits are common.
*
* Since the UN*X time epoch will cause a signed integer overflow for
* 32-bit signed int in the year 2038, implementations slowly move to
* 64bit base types for time_t, even in 32-bit environments.
*
* As the printf() family has no standardised type specifier for time_t,
* guessing the right output format specifier is a bit troublesome and
* best done with the help of the preprocessor and "config.h".
*/
#include "ipntp_config.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "timetoa.h"
#include "ntp_assert.h"
#include "lib_strbuf.h"
/*
* Formatting to string needs at max 40 bytes (even with 64 bit time_t),
* so we check LIB_BUFLENGTH is big enough for our purpose.
*/
#if LIB_BUFLENGTH < 40
# include "GRONK: LIB_BUFLENGTH is not sufficient"
#endif
#ifndef NTP_VXWORKS_7
#ifdef SYS_VXWORKS
typedef struct _ldiv_t {
long quot;
long rem;
} ldiv_t;
ldiv_t ldiv(long num, long denom);
#endif
#endif
/*
* general fractional timestamp formatting
*
* Many pieces of ntpd require a machine with two's complement
* representation of signed integers, so we don't go through the whole
* rigamarole of creating fully portable code here. But we have to stay
* away from signed integer overflow, as this might cause trouble even
* with two's complement representation.
*/
const char *
format_time_fraction(
time_t secs,
long frac,
int prec
)
{
char * cp;
u_int prec_u;
u_time secs_u;
u_int u;
long fraclimit;
int notneg; /* flag for non-negative value */
ldiv_t qr;
DEBUG_REQUIRE(prec != 0);
LIB_GETBUF(cp);
secs_u = (u_time)secs;
/* check if we need signed or unsigned mode */
notneg = (prec < 0);
prec_u = ((prec) < 0 ? -(prec) : (prec));
/* fraclimit = (long)pow(10, prec_u); */
for (fraclimit = 10, u = 1; u < prec_u; u++) {
DEBUG_INSIST(fraclimit < fraclimit * 10);
fraclimit *= 10;
}
/*
* Since conversion to string uses lots of divisions anyway,
* there's no big extra penalty for normalisation. We do it for
* consistency.
*/
if (frac < 0 || frac >= fraclimit) {
qr = ldiv(frac, fraclimit);
if (qr.rem < 0) {
qr.quot--;
qr.rem += fraclimit;
}
secs_u += (time_t)qr.quot;
frac = qr.rem;
}
/* Get the absolute value of the split representation time. */
notneg = notneg || ((time_t)secs_u >= 0);
if (!notneg) {
secs_u = ~secs_u;
if (0 == frac)
secs_u++;
else
frac = fraclimit - frac;
}
/* finally format the data and return the result */
snprintf(cp, LIB_BUFLENGTH, "%s%" UTIME_FORMAT ".%0*ld",
notneg? "" : "-", secs_u, prec_u, frac);
return cp;
}
@@ -0,0 +1,297 @@
/*
* timevalops.c -- calculations on 'struct timeval' values
*
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
* The contents of 'html/copyright.html' apply.
*/
#include <ipntp_config.h>
#include "timevalops.h"
#ifdef USE_TSF_USEC_TABLES
/*
* Tables to calculate time stamp fractions from usecs. The entries
* in these tables are offset into using each of the two low order
* bytes plus the next 4 bits in a usec value (from a struct timeval).
* These are summed to produce the time stamp fraction.
*
* Note that these tables are rounded (not truncated) to the nearest
* low order bit in the fraction. The timestamp computed should be
* +- 1.5 low order bits.
*/
const u_int32 ustotslo[256] = {
0x00000000, 0x000010c7, 0x0000218e, 0x00003255,
0x0000431c, 0x000053e3, 0x000064aa, 0x00007571,
0x00008638, 0x000096ff, 0x0000a7c6, 0x0000b88d,
0x0000c954, 0x0000da1b, 0x0000eae2, 0x0000fba9,
0x00010c6f, 0x00011d36, 0x00012dfd, 0x00013ec4,
0x00014f8b, 0x00016052, 0x00017119, 0x000181e0,
0x000192a7, 0x0001a36e, 0x0001b435, 0x0001c4fc,
0x0001d5c3, 0x0001e68a, 0x0001f751, 0x00020818,
0x000218df, 0x000229a6, 0x00023a6d, 0x00024b34,
0x00025bfb, 0x00026cc2, 0x00027d89, 0x00028e50,
0x00029f17, 0x0002afde, 0x0002c0a5, 0x0002d16c,
0x0002e233, 0x0002f2fa, 0x000303c0, 0x00031487,
0x0003254e, 0x00033615, 0x000346dc, 0x000357a3,
0x0003686a, 0x00037931, 0x000389f8, 0x00039abf,
0x0003ab86, 0x0003bc4d, 0x0003cd14, 0x0003dddb,
0x0003eea2, 0x0003ff69, 0x00041030, 0x000420f7,
0x000431be, 0x00044285, 0x0004534c, 0x00046413,
0x000474da, 0x000485a1, 0x00049668, 0x0004a72f,
0x0004b7f6, 0x0004c8bd, 0x0004d984, 0x0004ea4b,
0x0004fb12, 0x00050bd8, 0x00051c9f, 0x00052d66,
0x00053e2d, 0x00054ef4, 0x00055fbb, 0x00057082,
0x00058149, 0x00059210, 0x0005a2d7, 0x0005b39e,
0x0005c465, 0x0005d52c, 0x0005e5f3, 0x0005f6ba,
0x00060781, 0x00061848, 0x0006290f, 0x000639d6,
0x00064a9d, 0x00065b64, 0x00066c2b, 0x00067cf2,
0x00068db9, 0x00069e80, 0x0006af47, 0x0006c00e,
0x0006d0d5, 0x0006e19c, 0x0006f263, 0x0007032a,
0x000713f0, 0x000724b7, 0x0007357e, 0x00074645,
0x0007570c, 0x000767d3, 0x0007789a, 0x00078961,
0x00079a28, 0x0007aaef, 0x0007bbb6, 0x0007cc7d,
0x0007dd44, 0x0007ee0b, 0x0007fed2, 0x00080f99,
0x00082060, 0x00083127, 0x000841ee, 0x000852b5,
0x0008637c, 0x00087443, 0x0008850a, 0x000895d1,
0x0008a698, 0x0008b75f, 0x0008c826, 0x0008d8ed,
0x0008e9b4, 0x0008fa7b, 0x00090b41, 0x00091c08,
0x00092ccf, 0x00093d96, 0x00094e5d, 0x00095f24,
0x00096feb, 0x000980b2, 0x00099179, 0x0009a240,
0x0009b307, 0x0009c3ce, 0x0009d495, 0x0009e55c,
0x0009f623, 0x000a06ea, 0x000a17b1, 0x000a2878,
0x000a393f, 0x000a4a06, 0x000a5acd, 0x000a6b94,
0x000a7c5b, 0x000a8d22, 0x000a9de9, 0x000aaeb0,
0x000abf77, 0x000ad03e, 0x000ae105, 0x000af1cc,
0x000b0293, 0x000b1359, 0x000b2420, 0x000b34e7,
0x000b45ae, 0x000b5675, 0x000b673c, 0x000b7803,
0x000b88ca, 0x000b9991, 0x000baa58, 0x000bbb1f,
0x000bcbe6, 0x000bdcad, 0x000bed74, 0x000bfe3b,
0x000c0f02, 0x000c1fc9, 0x000c3090, 0x000c4157,
0x000c521e, 0x000c62e5, 0x000c73ac, 0x000c8473,
0x000c953a, 0x000ca601, 0x000cb6c8, 0x000cc78f,
0x000cd856, 0x000ce91d, 0x000cf9e4, 0x000d0aaa,
0x000d1b71, 0x000d2c38, 0x000d3cff, 0x000d4dc6,
0x000d5e8d, 0x000d6f54, 0x000d801b, 0x000d90e2,
0x000da1a9, 0x000db270, 0x000dc337, 0x000dd3fe,
0x000de4c5, 0x000df58c, 0x000e0653, 0x000e171a,
0x000e27e1, 0x000e38a8, 0x000e496f, 0x000e5a36,
0x000e6afd, 0x000e7bc4, 0x000e8c8b, 0x000e9d52,
0x000eae19, 0x000ebee0, 0x000ecfa7, 0x000ee06e,
0x000ef135, 0x000f01fc, 0x000f12c2, 0x000f2389,
0x000f3450, 0x000f4517, 0x000f55de, 0x000f66a5,
0x000f776c, 0x000f8833, 0x000f98fa, 0x000fa9c1,
0x000fba88, 0x000fcb4f, 0x000fdc16, 0x000fecdd,
0x000ffda4, 0x00100e6b, 0x00101f32, 0x00102ff9,
0x001040c0, 0x00105187, 0x0010624e, 0x00107315,
0x001083dc, 0x001094a3, 0x0010a56a, 0x0010b631
};
const u_int32 ustotsmid[256] = {
0x00000000, 0x0010c6f8, 0x00218def, 0x003254e7,
0x00431bdf, 0x0053e2d6, 0x0064a9ce, 0x007570c5,
0x008637bd, 0x0096feb5, 0x00a7c5ac, 0x00b88ca4,
0x00c9539c, 0x00da1a93, 0x00eae18b, 0x00fba882,
0x010c6f7a, 0x011d3672, 0x012dfd69, 0x013ec461,
0x014f8b59, 0x01605250, 0x01711948, 0x0181e03f,
0x0192a737, 0x01a36e2f, 0x01b43526, 0x01c4fc1e,
0x01d5c316, 0x01e68a0d, 0x01f75105, 0x020817fc,
0x0218def4, 0x0229a5ec, 0x023a6ce3, 0x024b33db,
0x025bfad3, 0x026cc1ca, 0x027d88c2, 0x028e4fb9,
0x029f16b1, 0x02afdda9, 0x02c0a4a0, 0x02d16b98,
0x02e23290, 0x02f2f987, 0x0303c07f, 0x03148777,
0x03254e6e, 0x03361566, 0x0346dc5d, 0x0357a355,
0x03686a4d, 0x03793144, 0x0389f83c, 0x039abf34,
0x03ab862b, 0x03bc4d23, 0x03cd141a, 0x03dddb12,
0x03eea20a, 0x03ff6901, 0x04102ff9, 0x0420f6f1,
0x0431bde8, 0x044284e0, 0x04534bd7, 0x046412cf,
0x0474d9c7, 0x0485a0be, 0x049667b6, 0x04a72eae,
0x04b7f5a5, 0x04c8bc9d, 0x04d98394, 0x04ea4a8c,
0x04fb1184, 0x050bd87b, 0x051c9f73, 0x052d666b,
0x053e2d62, 0x054ef45a, 0x055fbb51, 0x05708249,
0x05814941, 0x05921038, 0x05a2d730, 0x05b39e28,
0x05c4651f, 0x05d52c17, 0x05e5f30e, 0x05f6ba06,
0x060780fe, 0x061847f5, 0x06290eed, 0x0639d5e5,
0x064a9cdc, 0x065b63d4, 0x066c2acc, 0x067cf1c3,
0x068db8bb, 0x069e7fb2, 0x06af46aa, 0x06c00da2,
0x06d0d499, 0x06e19b91, 0x06f26289, 0x07032980,
0x0713f078, 0x0724b76f, 0x07357e67, 0x0746455f,
0x07570c56, 0x0767d34e, 0x07789a46, 0x0789613d,
0x079a2835, 0x07aaef2c, 0x07bbb624, 0x07cc7d1c,
0x07dd4413, 0x07ee0b0b, 0x07fed203, 0x080f98fa,
0x08205ff2, 0x083126e9, 0x0841ede1, 0x0852b4d9,
0x08637bd0, 0x087442c8, 0x088509c0, 0x0895d0b7,
0x08a697af, 0x08b75ea6, 0x08c8259e, 0x08d8ec96,
0x08e9b38d, 0x08fa7a85, 0x090b417d, 0x091c0874,
0x092ccf6c, 0x093d9664, 0x094e5d5b, 0x095f2453,
0x096feb4a, 0x0980b242, 0x0991793a, 0x09a24031,
0x09b30729, 0x09c3ce21, 0x09d49518, 0x09e55c10,
0x09f62307, 0x0a06e9ff, 0x0a17b0f7, 0x0a2877ee,
0x0a393ee6, 0x0a4a05de, 0x0a5accd5, 0x0a6b93cd,
0x0a7c5ac4, 0x0a8d21bc, 0x0a9de8b4, 0x0aaeafab,
0x0abf76a3, 0x0ad03d9b, 0x0ae10492, 0x0af1cb8a,
0x0b029281, 0x0b135979, 0x0b242071, 0x0b34e768,
0x0b45ae60, 0x0b567558, 0x0b673c4f, 0x0b780347,
0x0b88ca3e, 0x0b999136, 0x0baa582e, 0x0bbb1f25,
0x0bcbe61d, 0x0bdcad15, 0x0bed740c, 0x0bfe3b04,
0x0c0f01fc, 0x0c1fc8f3, 0x0c308feb, 0x0c4156e2,
0x0c521dda, 0x0c62e4d2, 0x0c73abc9, 0x0c8472c1,
0x0c9539b9, 0x0ca600b0, 0x0cb6c7a8, 0x0cc78e9f,
0x0cd85597, 0x0ce91c8f, 0x0cf9e386, 0x0d0aaa7e,
0x0d1b7176, 0x0d2c386d, 0x0d3cff65, 0x0d4dc65c,
0x0d5e8d54, 0x0d6f544c, 0x0d801b43, 0x0d90e23b,
0x0da1a933, 0x0db2702a, 0x0dc33722, 0x0dd3fe19,
0x0de4c511, 0x0df58c09, 0x0e065300, 0x0e1719f8,
0x0e27e0f0, 0x0e38a7e7, 0x0e496edf, 0x0e5a35d6,
0x0e6afcce, 0x0e7bc3c6, 0x0e8c8abd, 0x0e9d51b5,
0x0eae18ad, 0x0ebedfa4, 0x0ecfa69c, 0x0ee06d94,
0x0ef1348b, 0x0f01fb83, 0x0f12c27a, 0x0f238972,
0x0f34506a, 0x0f451761, 0x0f55de59, 0x0f66a551,
0x0f776c48, 0x0f883340, 0x0f98fa37, 0x0fa9c12f,
0x0fba8827, 0x0fcb4f1e, 0x0fdc1616, 0x0fecdd0e,
0x0ffda405, 0x100e6afd, 0x101f31f4, 0x102ff8ec,
0x1040bfe4, 0x105186db, 0x10624dd3, 0x107314cb,
0x1083dbc2, 0x1094a2ba, 0x10a569b1, 0x10b630a9
};
const u_int32 ustotshi[16] = {
0x00000000, 0x10c6f7a1, 0x218def41, 0x3254e6e2,
0x431bde83, 0x53e2d624, 0x64a9cdc4, 0x7570c565,
0x8637bd06, 0x96feb4a6, 0xa7c5ac47, 0xb88ca3e8,
0xc9539b89, 0xda1a9329, 0xeae18aca, 0xfba8826b
};
/*
* Tables to convert from a time stamp fraction to usecs. Note that
* the units of these tables are actually (usec<<3). We carry three
* guard bits so that the result can be properly truncated (or rounded)
* to be correct to the least significant bit.
*
* These tables are rounded.
*/
const u_int32 tstoushi[256] = {
0x000000, 0x007a12, 0x00f424, 0x016e36,
0x01e848, 0x02625a, 0x02dc6c, 0x03567e,
0x03d090, 0x044aa2, 0x04c4b4, 0x053ec6,
0x05b8d8, 0x0632ea, 0x06acfc, 0x07270e,
0x07a120, 0x081b32, 0x089544, 0x090f56,
0x098968, 0x0a037a, 0x0a7d8c, 0x0af79e,
0x0b71b0, 0x0bebc2, 0x0c65d4, 0x0cdfe6,
0x0d59f8, 0x0dd40a, 0x0e4e1c, 0x0ec82e,
0x0f4240, 0x0fbc52, 0x103664, 0x10b076,
0x112a88, 0x11a49a, 0x121eac, 0x1298be,
0x1312d0, 0x138ce2, 0x1406f4, 0x148106,
0x14fb18, 0x15752a, 0x15ef3c, 0x16694e,
0x16e360, 0x175d72, 0x17d784, 0x185196,
0x18cba8, 0x1945ba, 0x19bfcc, 0x1a39de,
0x1ab3f0, 0x1b2e02, 0x1ba814, 0x1c2226,
0x1c9c38, 0x1d164a, 0x1d905c, 0x1e0a6e,
0x1e8480, 0x1efe92, 0x1f78a4, 0x1ff2b6,
0x206cc8, 0x20e6da, 0x2160ec, 0x21dafe,
0x225510, 0x22cf22, 0x234934, 0x23c346,
0x243d58, 0x24b76a, 0x25317c, 0x25ab8e,
0x2625a0, 0x269fb2, 0x2719c4, 0x2793d6,
0x280de8, 0x2887fa, 0x29020c, 0x297c1e,
0x29f630, 0x2a7042, 0x2aea54, 0x2b6466,
0x2bde78, 0x2c588a, 0x2cd29c, 0x2d4cae,
0x2dc6c0, 0x2e40d2, 0x2ebae4, 0x2f34f6,
0x2faf08, 0x30291a, 0x30a32c, 0x311d3e,
0x319750, 0x321162, 0x328b74, 0x330586,
0x337f98, 0x33f9aa, 0x3473bc, 0x34edce,
0x3567e0, 0x35e1f2, 0x365c04, 0x36d616,
0x375028, 0x37ca3a, 0x38444c, 0x38be5e,
0x393870, 0x39b282, 0x3a2c94, 0x3aa6a6,
0x3b20b8, 0x3b9aca, 0x3c14dc, 0x3c8eee,
0x3d0900, 0x3d8312, 0x3dfd24, 0x3e7736,
0x3ef148, 0x3f6b5a, 0x3fe56c, 0x405f7e,
0x40d990, 0x4153a2, 0x41cdb4, 0x4247c6,
0x42c1d8, 0x433bea, 0x43b5fc, 0x44300e,
0x44aa20, 0x452432, 0x459e44, 0x461856,
0x469268, 0x470c7a, 0x47868c, 0x48009e,
0x487ab0, 0x48f4c2, 0x496ed4, 0x49e8e6,
0x4a62f8, 0x4add0a, 0x4b571c, 0x4bd12e,
0x4c4b40, 0x4cc552, 0x4d3f64, 0x4db976,
0x4e3388, 0x4ead9a, 0x4f27ac, 0x4fa1be,
0x501bd0, 0x5095e2, 0x510ff4, 0x518a06,
0x520418, 0x527e2a, 0x52f83c, 0x53724e,
0x53ec60, 0x546672, 0x54e084, 0x555a96,
0x55d4a8, 0x564eba, 0x56c8cc, 0x5742de,
0x57bcf0, 0x583702, 0x58b114, 0x592b26,
0x59a538, 0x5a1f4a, 0x5a995c, 0x5b136e,
0x5b8d80, 0x5c0792, 0x5c81a4, 0x5cfbb6,
0x5d75c8, 0x5defda, 0x5e69ec, 0x5ee3fe,
0x5f5e10, 0x5fd822, 0x605234, 0x60cc46,
0x614658, 0x61c06a, 0x623a7c, 0x62b48e,
0x632ea0, 0x63a8b2, 0x6422c4, 0x649cd6,
0x6516e8, 0x6590fa, 0x660b0c, 0x66851e,
0x66ff30, 0x677942, 0x67f354, 0x686d66,
0x68e778, 0x69618a, 0x69db9c, 0x6a55ae,
0x6acfc0, 0x6b49d2, 0x6bc3e4, 0x6c3df6,
0x6cb808, 0x6d321a, 0x6dac2c, 0x6e263e,
0x6ea050, 0x6f1a62, 0x6f9474, 0x700e86,
0x708898, 0x7102aa, 0x717cbc, 0x71f6ce,
0x7270e0, 0x72eaf2, 0x736504, 0x73df16,
0x745928, 0x74d33a, 0x754d4c, 0x75c75e,
0x764170, 0x76bb82, 0x773594, 0x77afa6,
0x7829b8, 0x78a3ca, 0x791ddc, 0x7997ee
};
const u_int32 tstousmid[256] = {
0x0000, 0x007a, 0x00f4, 0x016e, 0x01e8, 0x0262, 0x02dc, 0x0356,
0x03d1, 0x044b, 0x04c5, 0x053f, 0x05b9, 0x0633, 0x06ad, 0x0727,
0x07a1, 0x081b, 0x0895, 0x090f, 0x0989, 0x0a03, 0x0a7e, 0x0af8,
0x0b72, 0x0bec, 0x0c66, 0x0ce0, 0x0d5a, 0x0dd4, 0x0e4e, 0x0ec8,
0x0f42, 0x0fbc, 0x1036, 0x10b0, 0x112b, 0x11a5, 0x121f, 0x1299,
0x1313, 0x138d, 0x1407, 0x1481, 0x14fb, 0x1575, 0x15ef, 0x1669,
0x16e3, 0x175d, 0x17d8, 0x1852, 0x18cc, 0x1946, 0x19c0, 0x1a3a,
0x1ab4, 0x1b2e, 0x1ba8, 0x1c22, 0x1c9c, 0x1d16, 0x1d90, 0x1e0a,
0x1e84, 0x1eff, 0x1f79, 0x1ff3, 0x206d, 0x20e7, 0x2161, 0x21db,
0x2255, 0x22cf, 0x2349, 0x23c3, 0x243d, 0x24b7, 0x2531, 0x25ac,
0x2626, 0x26a0, 0x271a, 0x2794, 0x280e, 0x2888, 0x2902, 0x297c,
0x29f6, 0x2a70, 0x2aea, 0x2b64, 0x2bde, 0x2c59, 0x2cd3, 0x2d4d,
0x2dc7, 0x2e41, 0x2ebb, 0x2f35, 0x2faf, 0x3029, 0x30a3, 0x311d,
0x3197, 0x3211, 0x328b, 0x3306, 0x3380, 0x33fa, 0x3474, 0x34ee,
0x3568, 0x35e2, 0x365c, 0x36d6, 0x3750, 0x37ca, 0x3844, 0x38be,
0x3938, 0x39b3, 0x3a2d, 0x3aa7, 0x3b21, 0x3b9b, 0x3c15, 0x3c8f,
0x3d09, 0x3d83, 0x3dfd, 0x3e77, 0x3ef1, 0x3f6b, 0x3fe5, 0x405f,
0x40da, 0x4154, 0x41ce, 0x4248, 0x42c2, 0x433c, 0x43b6, 0x4430,
0x44aa, 0x4524, 0x459e, 0x4618, 0x4692, 0x470c, 0x4787, 0x4801,
0x487b, 0x48f5, 0x496f, 0x49e9, 0x4a63, 0x4add, 0x4b57, 0x4bd1,
0x4c4b, 0x4cc5, 0x4d3f, 0x4db9, 0x4e34, 0x4eae, 0x4f28, 0x4fa2,
0x501c, 0x5096, 0x5110, 0x518a, 0x5204, 0x527e, 0x52f8, 0x5372,
0x53ec, 0x5466, 0x54e1, 0x555b, 0x55d5, 0x564f, 0x56c9, 0x5743,
0x57bd, 0x5837, 0x58b1, 0x592b, 0x59a5, 0x5a1f, 0x5a99, 0x5b13,
0x5b8d, 0x5c08, 0x5c82, 0x5cfc, 0x5d76, 0x5df0, 0x5e6a, 0x5ee4,
0x5f5e, 0x5fd8, 0x6052, 0x60cc, 0x6146, 0x61c0, 0x623a, 0x62b5,
0x632f, 0x63a9, 0x6423, 0x649d, 0x6517, 0x6591, 0x660b, 0x6685,
0x66ff, 0x6779, 0x67f3, 0x686d, 0x68e7, 0x6962, 0x69dc, 0x6a56,
0x6ad0, 0x6b4a, 0x6bc4, 0x6c3e, 0x6cb8, 0x6d32, 0x6dac, 0x6e26,
0x6ea0, 0x6f1a, 0x6f94, 0x700f, 0x7089, 0x7103, 0x717d, 0x71f7,
0x7271, 0x72eb, 0x7365, 0x73df, 0x7459, 0x74d3, 0x754d, 0x75c7,
0x7641, 0x76bc, 0x7736, 0x77b0, 0x782a, 0x78a4, 0x791e, 0x7998
};
const u_int32 tstouslo[128] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
0x1f, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b,
0x5c, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79
};
#else /* !USE_TSF_USEC_TABLES follows */
NONEMPTY_TRANSLATION_UNIT
#endif /* !USE_TSF_USEC_TABLES */
/* -*- EOF -*- */
@@ -0,0 +1,82 @@
/*
* timexsup.c - 'struct timex' support functions
*
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
* The contents of 'html/copyright.html' apply.
*/
#include "ipntp_config.h"
#include "timexsup.h"
#include <limits.h>
#include <math.h>
#ifdef HAVE_SYS_TIMEX_H
# include <sys/timex.h>
#endif
#if defined(MOD_NANO) != defined(STA_NANO)
# warning inconsistent definitions of MOD_NANO vs STA_NANO
#endif
static long
clamp_rounded(
double dval
)
{
/* round */
dval = floor(dval + 0.5);
/* clamp / saturate */
if (dval >= (double)LONG_MAX)
return LONG_MAX;
if (dval <= (double)LONG_MIN)
return LONG_MIN;
return (long)dval;
}
double
dbl_from_var_long(
long lval,
int status
)
{
#ifdef STA_NANO
if (status & STA_NANO)
return (double)lval * 1e-9;
#else
(void)status;
#endif
return (double)lval * 1e-6;
}
double
dbl_from_usec_long(
long lval
)
{
return (double)lval * 1e-6;
}
long
var_long_from_dbl(
double dval,
unsigned int * modes
)
{
#ifdef MOD_NANO
*modes |= MOD_NANO;
dval *= 1e+9;
#else
(void)modes;
dval *= 1e+6;
#endif
return clamp_rounded(dval);
}
long
usec_long_from_dbl(
double dval
)
{
return clamp_rounded(dval * 1e+6);
}
@@ -0,0 +1,51 @@
/*
* uglydate - convert a time stamp to something barely readable
* The string returned is 37 characters long.
*/
#include <ipntp_config.h>
#include <stdio.h>
#include "ntp_fp.h"
#include "ntp_unixtime.h"
#include "lib_strbuf.h"
#include "ntp_stdlib.h"
char *
uglydate(
l_fp *ts
)
{
char *bp;
char *timep;
struct tm *tm;
time_t sec;
long msec;
int year;
timep = ulfptoa(ts, 6); /* returns max 17 characters */
LIB_GETBUF(bp);
sec = ts->l_ui - JAN_1970;
msec = ts->l_uf / 4294967; /* fract / (2**32/1000) */
tm = gmtime(&sec);
if (ts->l_ui == 0) {
/*
* Probably not a real good thing to do. Oh, well.
*/
year = 0;
tm->tm_yday = 0;
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
} else {
year = tm->tm_year;
while (year >= 100)
year -= 100;
}
snprintf(bp, LIB_BUFLENGTH,
"%17s %02d:%03d:%02d:%02d:%02d.%03ld", timep, year,
tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec,
msec);
return bp;
}
@@ -0,0 +1,284 @@
/*
* vint64ops.c - operations on 'vint64' values
*
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
* The contents of 'html/copyright.html' apply.
* ----------------------------------------------------------------------
* This is an attempt to get the vint64 calculations stuff centralised.
*/
#include <ipntp_config.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include "ntp_types.h"
#include "ntp_fp.h"
#include "vint64ops.h"
/* ---------------------------------------------------------------------
* GCC is rather sticky with its 'const' attribute. We have to do it more
* explicit than with a cast if we want to get rid of a CONST qualifier.
* Greetings from the PASCAL world, where casting was only possible via
* untagged unions...
*/
static inline void*
noconst(
const void* ptr
)
{
union {
const void * cp;
void * vp;
} tmp;
tmp.cp = ptr;
return tmp.vp;
}
/* -------------------------------------------------------------------------*/
vint64
strtouv64(
const char * begp,
char ** endp,
int base
)
{
vint64 res;
u_char digit;
int sig, num;
const u_char *src;
num = sig = 0;
src = (const u_char*)begp;
while (isspace(*src))
src++;
if (*src == '-') {
src++;
sig = 1;
} else if (*src == '+') {
src++;
}
if (base == 0) {
base = 10;
if (*src == '0') {
base = 8;
if (toupper(*++src) == 'X') {
src++;
base = 16;
}
}
} else if (base == 16) { /* remove optional leading '0x' or '0X' */
if (src[0] == '0' && toupper(src[1]) == 'X')
src += 2;
} else if (base <= 2 || base > 36) {
memset(&res, 0xFF, sizeof(res));
errno = ERANGE;
return res;
}
memset(&res, 0, sizeof(res));
while (*src) {
if (isdigit(*src))
digit = *src - '0';
else if (isupper(*src))
digit = *src - 'A' + 10;
else if (islower(*src))
digit = *src - 'a' + 10;
else
break;
if (digit >= base)
break;
num = 1;
#if defined(HAVE_INT64)
res.Q_s = res.Q_s * base + digit;
#else
/* res *= base, using 16x16->32 bit
* multiplication. Slow but portable.
*/
{
uint32_t accu;
accu = (uint32_t)res.W_s.ll * base;
res.W_s.ll = (uint16_t)accu;
accu = (accu >> 16)
+ (uint32_t)res.W_s.lh * base;
res.W_s.lh = (uint16_t)accu;
/* the upper bits can be done in one step: */
res.D_s.hi = res.D_s.hi * base + (accu >> 16);
}
M_ADD(res.D_s.hi, res.D_s.lo, 0, digit);
#endif
src++;
}
if (!num)
errno = EINVAL;
if (endp)
*endp = (char*)noconst(src);
if (sig)
M_NEG(res.D_s.hi, res.D_s.lo);
return res;
}
/* -------------------------------------------------------------------------*/
int
icmpv64(
const vint64 * lhs,
const vint64 * rhs
)
{
int res;
#if defined(HAVE_INT64)
res = (lhs->q_s > rhs->q_s)
- (lhs->q_s < rhs->q_s);
#else
res = (lhs->d_s.hi > rhs->d_s.hi)
- (lhs->d_s.hi < rhs->d_s.hi);
if ( ! res )
res = (lhs->D_s.lo > rhs->D_s.lo)
- (lhs->D_s.lo < rhs->D_s.lo);
#endif
return res;
}
/* -------------------------------------------------------------------------*/
int
ucmpv64(
const vint64 * lhs,
const vint64 * rhs
)
{
int res;
#if defined(HAVE_INT64)
res = (lhs->Q_s > rhs->Q_s)
- (lhs->Q_s < rhs->Q_s);
#else
res = (lhs->D_s.hi > rhs->D_s.hi)
- (lhs->D_s.hi < rhs->D_s.hi);
if ( ! res )
res = (lhs->D_s.lo > rhs->D_s.lo)
- (lhs->D_s.lo < rhs->D_s.lo);
#endif
return res;
}
/* -------------------------------------------------------------------------*/
vint64
addv64(
const vint64 *lhs,
const vint64 *rhs
)
{
vint64 res;
#if defined(HAVE_INT64)
res.Q_s = lhs->Q_s + rhs->Q_s;
#else
res = *lhs;
M_ADD(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo);
#endif
return res;
}
/* -------------------------------------------------------------------------*/
vint64
subv64(
const vint64 *lhs,
const vint64 *rhs
)
{
vint64 res;
#if defined(HAVE_INT64)
res.Q_s = lhs->Q_s - rhs->Q_s;
#else
res = *lhs;
M_SUB(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo);
#endif
return res;
}
/* -------------------------------------------------------------------------*/
vint64
addv64i32(
const vint64 * lhs,
int32_t rhs
)
{
vint64 res;
res = *lhs;
#if defined(HAVE_INT64)
res.q_s += rhs;
#else
M_ADD(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs);
#endif
return res;
}
/* -------------------------------------------------------------------------*/
vint64
subv64i32(
const vint64 * lhs,
int32_t rhs
)
{
vint64 res;
res = *lhs;
#if defined(HAVE_INT64)
res.q_s -= rhs;
#else
M_SUB(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs);
#endif
return res;
}
/* -------------------------------------------------------------------------*/
vint64
addv64u32(
const vint64 * lhs,
uint32_t rhs
)
{
vint64 res;
res = *lhs;
#if defined(HAVE_INT64)
res.Q_s += rhs;
#else
M_ADD(res.D_s.hi, res.D_s.lo, 0, rhs);
#endif
return res;
}
/* -------------------------------------------------------------------------*/
vint64
subv64u32(
const vint64 * lhs,
uint32_t rhs
)
{
vint64 res;
res = *lhs;
#if defined(HAVE_INT64)
res.Q_s -= rhs;
#else
M_SUB(res.D_s.hi, res.D_s.lo, 0, rhs);
#endif
return res;
}
@@ -0,0 +1,75 @@
/*
* xsbprintf.c - string buffer formatting helpers
*
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
* The contents of 'html/copyright.html' apply.
*/
#include <ipntp_config.h>
#include <sys/types.h>
#include "ntp_stdlib.h"
/* eXtended Varlist String Buffer printf
*
* Formats via 'vsnprintf' into a string buffer, with some semantic
* specialties:
*
* - The start of the buffer pointer is updated according to the number
* of characters written.
* - If the buffer is insufficient to format the number of charactes,
* the partial result will be be discarded, and zero is returned to
* indicate nothing was written to the buffer.
* - On successful formatting, the return code is the return value of
* the inner call to 'vsnprintf()'.
* - If there is any error, the state of the buffer will not be
* changed. (Bytes in the buffer might be smashed, but the buffer
* position does not change, and the NUL marker stays in place at the
* current buffer position.)
* - If '(*ppbuf - pend) <= 0' (or ppbuf is NULL), fail with EINVAL.
*/
int
xvsbprintf(
char **ppbuf, /* pointer to buffer pointer (I/O) */
char * const pend, /* buffer end (I) */
char const *pfmt, /* printf-like format string */
va_list va /* formatting args for above */
)
{
char *pbuf = (ppbuf) ? *ppbuf : NULL;
int rc = -1;
if (pbuf && (pend - pbuf > 0)) {
size_t blen = (size_t)(pend - pbuf);
rc = vsnprintf(pbuf, blen, pfmt, va);
if (rc > 0) {
if ((size_t)rc >= blen)
rc = 0;
pbuf += rc;
}
*pbuf = '\0'; /* fear of bad vsnprintf */
*ppbuf = pbuf;
} else {
errno = EINVAL;
}
return rc;
}
/* variadic wrapper around the buffer string formatter */
int
xsbprintf(
char **ppbuf, /* pointer to buffer pointer (I/O) */
char * const pend, /* buffer end (I) */
char const *pfmt, /* printf-like format string */
... /* formatting args for above */
)
{
va_list va;
int rc;
va_start(va, pfmt);
rc = xvsbprintf(ppbuf, pend, pfmt, va);
va_end(va);
return rc;
}
/* that's all folks! */
@@ -0,0 +1,26 @@
/*
* ymd2yd - compute the date in the year from y/m/d
*
* A thin wrapper around a more general calendar function.
*/
#include <ipntp_config.h>
#include "ntp_stdlib.h"
#include "ntp_calendar.h"
int
ymd2yd(
int y,
int m,
int d)
{
/*
* convert y/m/d to elapsed calendar units, convert that to
* elapsed days since the start of the given year and convert
* back to unity-based day in year.
*
* This does no further error checking, since the underlying
* function is assumed to work out how to handle the data.
*/
return ntpcal_edate_to_yeardays(y-1, m-1, d-1) + 1;
}