* Florian octo Forster <octo at collectd.org>
**/
-#if HAVE_CONFIG_H
#include "config.h"
-#endif
#if !defined(__GNUC__) || !__GNUC__
#define __attribute__(x) /**/
#include "collectd/lcc_features.h"
#include "collectd/network_parse.h"
+#include "globals.h"
#include <errno.h>
#include <math.h>
#include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* for be{16,64}toh */
+#if HAVE_ENDIAN_H
+#include <endian.h>
+#elif HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#else /* fallback */
+#include "collectd/stdendian.h"
+#endif
+#if HAVE_GCRYPT_H
#define GCRYPT_NO_DEPRECATED
#include <gcrypt.h>
+#endif
#include <stdio.h>
#define DEBUG(...) printf(__VA_ARGS__)
+#if HAVE_GCRYPT_H
+#if GCRYPT_VERSION_NUMBER < 0x010600
GCRY_THREAD_OPTION_PTHREAD_IMPL;
+#endif
+#endif
/* forward declaration because parse_sign_sha256()/parse_encrypt_aes256() and
* network_parse() need to call each other. */
static int network_parse(void *data, size_t data_size, lcc_security_level_t sl,
lcc_network_parse_options_t const *opts);
-static int init_gcrypt() {
+#if HAVE_GCRYPT_H
+static int init_gcrypt(void) {
/* http://lists.gnupg.org/pipermail/gcrypt-devel/2003-August/000458.html
* Because you can't know in a library whether another library has
* already initialized the library */
gcry_control(GCRYCTL_INITIALIZATION_FINISHED);
return 0;
}
+#endif
typedef struct {
uint8_t *data;
static double ntohd(double val) /* {{{ */
{
- static int config = 0;
+ static int config;
union {
uint8_t byte[8];
state->values = calloc(sizeof(*state->values), state->values_len);
state->values_types = calloc(sizeof(*state->values_types), state->values_len);
if ((state->values == NULL) || (state->values_types == NULL)) {
- free(state->values);
- free(state->values_types);
return ENOMEM;
}
return 0;
}
+#if HAVE_GCRYPT_H
static int verify_sha256(void *payload, size_t payload_size,
char const *username, char const *password,
uint8_t hash_provided[32]) {
gcry_error_t err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
if (err != 0) {
- /* TODO(octo): use gcry_strerror(err) to create an error string. */
- return -1;
+ return (int)err;
}
err = gcry_md_setkey(hd, password, strlen(password));
if (err != 0) {
gcry_md_close(hd);
- return -1;
+ return (int)err;
}
gcry_md_write(hd, username, strlen(username));
return !!ret;
}
+#else /* !HAVE_GCRYPT_H */
+static int verify_sha256(void *payload, size_t payload_size,
+ char const *username, char const *password,
+ uint8_t hash_provided[32]) {
+ return ENOTSUP;
+}
+#endif
static int parse_sign_sha256(void *signature, size_t signature_len,
void *payload, size_t payload_size,
lcc_network_parse_options_t const *opts) {
if (opts->password_lookup == NULL) {
- /* TODO(octo): print warning */
+ /* The sender signed the packet but we can't verify it. Handle it as if it
+ * were unsigned, i.e. security level NONE. */
return network_parse(payload, payload_size, NONE, opts);
}
return network_parse(payload, payload_size, SIGN, opts);
}
+#if HAVE_GCRYPT_H
static int decrypt_aes256(buffer_t *b, void *iv, size_t iv_size,
char const *password) {
gcry_cipher_hd_t cipher = NULL;
uint8_t pwhash[32] = {0};
gcry_md_hash_buffer(GCRY_MD_SHA256, pwhash, password, strlen(password));
- fprintf(stderr, "sizeof(iv) = %zu\n", sizeof(iv));
+ fprintf(stderr, "sizeof(iv) = %" PRIsz "\n", sizeof(iv));
if (gcry_cipher_setkey(cipher, pwhash, sizeof(pwhash)) ||
gcry_cipher_setiv(cipher, iv, iv_size) ||
gcry_cipher_decrypt(cipher, b->data, b->len, /* in = */ NULL,
static int parse_encrypt_aes256(void *data, size_t data_size,
lcc_network_parse_options_t const *opts) {
if (opts->password_lookup == NULL) {
- /* TODO(octo): print warning */
+ /* Without a password source it's (hopefully) impossible to decrypt the
+ * network packet. */
return ENOENT;
}
return ENOMEM;
char username[((size_t)username_len) + 1];
memset(username, 0, sizeof(username));
- if (buffer_next(b, username, sizeof(username)))
+ if (buffer_next(b, username, (size_t)username_len))
return EINVAL;
char const *password = opts->password_lookup(username);
return network_parse(b->data, b->len, ENCRYPT, opts);
}
+#else /* !HAVE_GCRYPT_H */
+static int parse_encrypt_aes256(void *data, size_t data_size,
+ lcc_network_parse_options_t const *opts) {
+ return ENOTSUP;
+}
+#endif
static int network_parse(void *data, size_t data_size, lcc_security_level_t sl,
lcc_network_parse_options_t const *opts) {
if ((sz < 5) || (((size_t)sz - 4) > b->len)) {
DEBUG("lcc_network_parse(): invalid 'sz' field: sz = %" PRIu16
- ", b->len = %zu\n",
+ ", b->len = %" PRIsz "\n",
sz, b->len);
return EINVAL;
}
case TYPE_VALUES: {
lcc_value_list_t vl = state;
if (parse_values(payload, sizeof(payload), &vl)) {
+ free(vl.values);
+ free(vl.values_types);
DEBUG("lcc_network_parse(): parse_values failed.\n");
return EINVAL;
}
- /* TODO(octo): skip if current_security_level < required_security_level */
+ int status = 0;
- int status = opts->writer(&vl);
+ /* Write metrics if they have the required security level. */
+ if (sl >= opts->security_level)
+ status = opts->writer(&vl);
free(vl.values);
free(vl.values_types);
int lcc_network_parse(void *data, size_t data_size,
lcc_network_parse_options_t opts) {
if (opts.password_lookup) {
+#if HAVE_GCRYPT_H
int status;
if ((status = init_gcrypt())) {
return status;
}
+#else
+ return ENOTSUP;
+#endif
}
return network_parse(data, data_size, NONE, &opts);