* ! Hash (Bits 224 - 255) !
* +---------------------------------------------------------------+
*/
+#define PART_SIGNATURE_SHA256_SIZE 36
struct part_signature_sha256_s
{
part_header_t head;
static int parse_packet (sockent_t *se,
void *buffer, size_t buffer_size, int flags);
+#define BUFFER_READ(p,s) do { \
+ memcpy ((p), buffer + buffer_offset, (s)); \
+ buffer_offset += (s); \
+} while (0)
+
#if HAVE_GCRYPT_H
static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
- void **ret_buffer, size_t *ret_buffer_len)
+ void **ret_buffer, size_t *ret_buffer_len, int flags)
{
- char *buffer = *ret_buffer;
- size_t buffer_len = *ret_buffer_len;
+ char *buffer;
+ size_t buffer_len;
+ size_t buffer_offset;
- part_signature_sha256_t ps_received;
- char hash[sizeof (ps_received.hash)];
+ part_signature_sha256_t pss;
+ char hash[sizeof (pss.hash)];
gcry_md_hd_t hd;
gcry_error_t err;
unsigned char *hash_ptr;
+ buffer = *ret_buffer;
+ buffer_len = *ret_buffer_len;
+ buffer_offset = 0;
+
if (se->shared_secret == NULL)
{
NOTICE ("network plugin: Received signed network packet but can't verify "
return (0);
}
- if (buffer_len < sizeof (ps_received))
+ if (buffer_len < PART_SIGNATURE_SHA256_SIZE)
return (-ENOMEM);
+ BUFFER_READ (&pss.head.type, sizeof (pss.head.type));
+ BUFFER_READ (&pss.head.length, sizeof (pss.head.length));
+ BUFFER_READ (pss.hash, sizeof (pss.hash));
+
+ assert (buffer_offset == PART_SIGNATURE_SHA256_SIZE);
+
+ if (ntohs (pss.head.length) != PART_SIGNATURE_SHA256_SIZE)
+ {
+ ERROR ("network plugin: HMAC-SHA-256 with invalid length received.");
+ return (-1);
+ }
+
hd = NULL;
err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
if (err != 0)
return (-1);
}
- memcpy (&ps_received, buffer, sizeof (ps_received));
- /* TODO: Check ps_received.head.length! */
-
- buffer += sizeof (ps_received);
- buffer_len -= sizeof (ps_received);
-
- gcry_md_write (hd, buffer, buffer_len);
+ gcry_md_write (hd, buffer + buffer_offset, buffer_len - buffer_offset);
hash_ptr = gcry_md_read (hd, GCRY_MD_SHA256);
if (hash_ptr == NULL)
{
gcry_md_close (hd);
hd = NULL;
- *ret_buffer += sizeof (ps_received);
- *ret_buffer_len -= sizeof (ps_received);
+ if (memcmp (pss.hash, hash, sizeof (pss.hash)) != 0)
+ {
+ WARNING ("network plugin: Verifying HMAC-SHA-256 signature failed: "
+ "Hash mismatch.");
+ }
+ else
+ {
+ parse_packet (se, buffer + buffer_offset, buffer_len - buffer_offset,
+ flags | PP_SIGNED);
+ }
+
+ *ret_buffer = buffer + buffer_len;
+ *ret_buffer_len = 0;
- if (memcmp (ps_received.hash, hash,
- sizeof (ps_received.hash)) == 0)
- return (0);
- else /* hashes do not match. */
- return (1);
+ return (0);
} /* }}} int parse_part_sign_sha256 */
/* #endif HAVE_GCRYPT_H */
#else /* if !HAVE_GCRYPT_H */
static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
- void **ret_buffer, size_t *ret_buffer_len)
+ void **ret_buffer, size_t *ret_buffer_size, int flags)
{
- INFO ("network plugin: Received signed packet, but the network "
- "plugin was not linked with libgcrypt, so I cannot "
- "verify the signature. The packet will be accepted.");
+ static int warning_has_been_printed = 0;
+
+ char *buffer;
+ size_t buffer_size;
+ size_t buffer_offset;
+
+ part_signature_sha256_t pss;
+
+ buffer = *ret_buffer;
+ buffer_size = *ret_buffer_size;
+ buffer_offset = 0;
+
+ if (buffer_size < PART_SIGNATURE_SHA256_SIZE)
+ return (-ENOMEM);
+
+ BUFFER_READ (&pss.head.type, sizeof (pss.head.type));
+ BUFFER_READ (&pss.head.length, sizeof (pss.head.length));
+ BUFFER_READ (pss.hash, sizeof (pss.hash));
+
+ assert (buffer_offset == PART_SIGNATURE_SHA256_SIZE);
+
+ if (ntohs (pss.head.length) != PART_SIGNATURE_SHA256_SIZE)
+ {
+ ERROR ("network plugin: HMAC-SHA-256 with invalid length received.");
+ return (-1);
+ }
+
+ if (warning_has_been_printed == 0)
+ {
+ WARNING ("network plugin: Received signed packet, but the network "
+ "plugin was not linked with libgcrypt, so I cannot "
+ "verify the signature. The packet will be accepted.");
+ warning_has_been_printed = 1;
+ }
+
+ parse_packet (se, buffer + buffer_offset, buffer_size - buffer_offset,
+ flags);
+
+ *ret_buffer = buffer + buffer_size;
+ *ret_buffer_size = 0;
+
return (0);
} /* }}} int parse_part_sign_sha256 */
#endif /* !HAVE_GCRYPT_H */
buffer_offset = 0;
-#define BUFFER_READ(p,s) do { \
- memcpy ((p), buffer + buffer_offset, (s)); \
- buffer_offset += (s); \
-} while (0)
-
/* Copy the unencrypted information into `pea'. */
BUFFER_READ (&pea.head.type, sizeof (pea.head.type));
BUFFER_READ (&pea.head.length, sizeof (pea.head.length));
*ret_buffer_len = buffer_len - part_size;
return (0);
-#undef BUFFER_READ
} /* }}} int parse_part_encr_aes256 */
/* #endif HAVE_GCRYPT_H */
#else /* if !HAVE_GCRYPT_H */
static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
- void **ret_buffer, size_t *ret_buffer_len)
+ void **ret_buffer, size_t *ret_buffer_size, int flags)
{
- INFO ("network plugin: Received encrypted packet, but the network "
- "plugin was not linked with libgcrypt, so I cannot "
- "decrypt it. The packet will be discarded.");
- return (-1);
+ static int warning_has_been_printed = 0;
+
+ char *buffer;
+ size_t buffer_size;
+ size_t buffer_offset;
+
+ part_header_t ph;
+ size_t ph_length;
+
+ buffer = *ret_buffer;
+ buffer_size = *ret_buffer_size;
+ buffer_offset = 0;
+
+ /* parse_packet assures this minimum size. */
+ assert (buffer_size >= (sizeof (ph.type) + sizeof (ph.length)));
+
+ BUFFER_READ (&ph.type, sizeof (ph.type));
+ BUFFER_READ (&ph.length, sizeof (ph.length));
+ ph_length = ntohs (ph.length);
+
+ if ((ph_length < PART_ENCRYPTION_AES256_SIZE)
+ || (ph_length > buffer_size))
+ {
+ ERROR ("network plugin: AES-256 encrypted part "
+ "with invalid length received.");
+ return (-1);
+ }
+
+ if (warning_has_been_printed == 0)
+ {
+ WARNING ("network plugin: Received encrypted packet, but the network "
+ "plugin was not linked with libgcrypt, so I cannot "
+ "decrypt it. The part will be discarded.");
+ warning_has_been_printed = 1;
+ }
+
+ *ret_buffer += ph_length;
+ *ret_buffer_size -= ph_length;
+
+ return (0);
} /* }}} int parse_part_encr_aes256 */
#endif /* !HAVE_GCRYPT_H */
+#undef BUFFER_READ
+
static int parse_packet (sockent_t *se, /* {{{ */
void *buffer, size_t buffer_size, int flags)
{
value_list_t vl = VALUE_LIST_INIT;
notification_t n;
- int packet_was_signed = (flags & PP_SIGNED);
- int packet_was_encrypted = (flags & PP_ENCRYPTED);
#if HAVE_GCRYPT_H
+ int packet_was_signed = (flags & PP_SIGNED);
+ int packet_was_encrypted = (flags & PP_ENCRYPTED);
int printed_ignore_warning = 0;
#endif /* HAVE_GCRYPT_H */
if (pkg_type == TYPE_ENCR_AES256)
{
status = parse_part_encr_aes256 (se,
- &buffer, &buffer_size,
- flags);
+ &buffer, &buffer_size, flags);
if (status != 0)
{
ERROR ("network plugin: Decrypting AES256 "
#endif /* HAVE_GCRYPT_H */
else if (pkg_type == TYPE_SIGN_SHA256)
{
- status = parse_part_sign_sha256 (se, &buffer, &buffer_size);
- if (status < 0)
+ status = parse_part_sign_sha256 (se,
+ &buffer, &buffer_size, flags);
+ if (status != 0)
{
ERROR ("network plugin: Verifying HMAC-SHA-256 "
"signature failed "
"with status %i.", status);
break;
}
- else if (status > 0)
- {
- ERROR ("network plugin: Ignoring packet with "
- "invalid HMAC-SHA-256 signature.");
- break;
- }
- else
- {
- packet_was_signed = 1;
- }
}
#if HAVE_GCRYPT_H
else if ((se->security_level == SECURITY_LEVEL_SIGN)
#include "plugin.h"
#if KERNEL_LINUX
-# define UPTIME_FILE "/proc/uptime"
-/* No need for includes, using /proc filesystem, Linux only. */
+# define STAT_FILE "/proc/stat"
+/* Using /proc filesystem to retrieve the boot time, Linux only. */
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
-/* Using kstats chain to retrieve the boot time, this applies to:
- * - Solaris / OpenSolaris
- */
+/* Using kstats chain to retrieve the boot time on Solaris / OpenSolaris systems */
/* #endif HAVE_LIBKSTAT */
#elif HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
-/* Using sysctl interface to retrieve the boot time, this applies to:
- * - *BSD
- * - Darwin / OS X
- */
+/* Using sysctl interface to retrieve the boot time on *BSD / Darwin / OS X systems */
/* #endif HAVE_SYS_SYSCTL_H */
#else
# error "No applicable input method."
#endif
-/*
+/*
* Global variables
*/
-#if KERNEL_LINUX
-/* global variables not needed */
-/* #endif KERNEL_LINUX */
-
-#elif HAVE_LIBKSTAT
+/* boottime always used, no OS distinction */
static time_t boottime;
-extern kstat_ctl_t *kc;
-/* #endif HAVE_LIBKSTAT */
-#elif HAVE_SYS_SYSCTL_H
-static time_t boottime;
-#endif
+#if HAVE_LIBKSTAT
+extern kstat_ctl_t *kc;
+#endif /* #endif HAVE_LIBKSTAT */
static void uptime_submit (gauge_t uptime)
{
plugin_dispatch_values (&vl);
}
-#if !defined(KERNEL_LINUX) || !KERNEL_LINUX
-static int uptime_init (void)
+static int uptime_init (void) /* {{{ */
{
-/* NOTE
-
- On unix systems other than Linux there is no /proc filesystem which
- calculates the uptime every time we call a read for the /proc/uptime
- file, the only information available is the boot time (in unix time,
- since epoch). Hence there is no need to read, every time the
- plugin_read is called, a value that won't change: this is a right
- task for the uptime_init function. However, since uptime_init is run
- only once, if the function fails in retrieving the boot time, the
- plugin is unregistered and there is no chance to try again later.
- Nevertheless, this is very unlikely to happen.
- */
+ /*
+ * On most unix systems the uptime is calculated by looking at the boot
+ * time (stored in unix time, since epoch) and the current one. We are
+ * going to do the same, reading the boot time value while executing
+ * the uptime_init function (there is no need to read, every time the
+ * plugin_read is called, a value that won't change). However, since
+ * uptime_init is run only once, if the function fails in retrieving
+ * the boot time, the plugin is unregistered and there is no chance to
+ * try again later. Nevertheless, this is very unlikely to happen.
+ */
+
+#if KERNEL_LINUX
+ unsigned long starttime;
+ char buffer[1024];
+ int ret;
+ FILE *fh;
+
+ ret = 0;
+
+ fh = fopen (STAT_FILE, "r");
+
+ if (fh == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("uptime plugin: Cannot open "STAT_FILE": %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ while (fgets (buffer, 1024, fh) != NULL)
+ {
+ /* look for the btime string and read the value */
+ ret = sscanf (buffer, "btime %lu", &starttime);
+ /* avoid further loops if btime has been found and read
+ * correctly (hopefully) */
+ if (ret == 1)
+ break;
+ }
+
+ fclose (fh);
+
+ /* loop done, check if no value has been found/read */
+ if (ret != 1)
+ {
+ ERROR ("uptime plugin: No value read from "STAT_FILE"");
+ return (-1);
+ }
+
+ boottime = (time_t) starttime;
+
+ if (boottime == 0)
+ {
+ ERROR ("uptime plugin: btime read from "STAT_FILE", "
+ "but `boottime' is zero!");
+ return (-1);
+ }
+/* #endif KERNEL_LINUX */
-# if HAVE_LIBKSTAT
+#elif HAVE_LIBKSTAT
kstat_t *ksp;
kstat_named_t *knp;
ksp = NULL;
knp = NULL;
- /* kstats chain already opened by update_kstat (using *kc), let's verify everything went fine. */
+ /* kstats chain already opened by update_kstat (using *kc), verify everything went fine. */
if (kc == NULL)
{
ERROR ("uptime plugin: kstat chain control structure not available.");
}
boottime = (time_t) knp->value.ui32;
+
+ if (boottime == 0)
+ {
+ ERROR ("uptime plugin: kstat_data_lookup returned success, "
+ "but `boottime' is zero!");
+ return (-1);
+ }
/* #endif HAVE_LIBKSTAT */
# elif HAVE_SYS_SYSCTL_H
size_t boottv_len;
int status;
- int mib[2];
+ int mib[2];
- mib[0] = CTL_KERN;
- mib[1] = KERN_BOOTTIME;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
- memset (&boottv, 0, sizeof (boottv));
- boottv_len = sizeof (boottv);
+ boottv_len = sizeof (boottv);
+ memset (&boottv, 0, boottv_len);
status = sysctl (mib, STATIC_ARRAY_SIZE (mib), &boottv, &boottv_len,
/* new_value = */ NULL, /* new_length = */ 0);
if (status != 0)
- {
- char errbuf[1024];
- ERROR ("uptime plugin: No value read from sysctl interface: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
+ {
+ char errbuf[1024];
+ ERROR ("uptime plugin: No value read from sysctl interface: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
boottime = boottv.tv_sec;
+
if (boottime == 0)
{
ERROR ("uptime plugin: sysctl(3) returned success, "
#endif /* HAVE_SYS_SYSCTL_H */
return (0);
-
-}
-#endif /* !KERNEL_LINUX */
+} /* }}} int uptime_init */
static int uptime_read (void)
{
gauge_t uptime;
-
-#if KERNEL_LINUX
- FILE *fh;
-
- fh = fopen (UPTIME_FILE, "r");
-
- if (fh == NULL)
- {
- char errbuf[1024];
- ERROR ("uptime plugin: Cannot open "UPTIME_FILE": %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
-
- if ( fscanf (fh, "%lf", &uptime) < 1 )
- {
- WARNING ("uptime plugin: No value read from "UPTIME_FILE);
- fclose (fh);
- return (-1);
- }
-
- fclose (fh);
-/* #endif KERNEL_LINUX */
-
-#elif HAVE_LIBKSTAT || HAVE_SYS_SYSCTL_H
time_t elapsed;
+ /* calculate the ammount of time elapsed since boot, AKA uptime */
elapsed = time (NULL) - boottime;
uptime = (gauge_t) elapsed;
-#endif /* HAVE_LIBKSTAT || HAVE_SYS_SYSCTL_H */
uptime_submit (uptime);
void module_register (void)
{
-#if !defined(KERNEL_LINUX) || !KERNEL_LINUX
plugin_register_init ("uptime", uptime_init);
-#endif
plugin_register_read ("uptime", uptime_read);
} /* void module_register */