} /* }}} int lcc_server_set_ttl */
int lcc_server_set_security_level (lcc_server_t *srv, /* {{{ */
- lcc_security_level_t level)
-{
- if ((srv == NULL)
- || ((level != NONE) && (level != SIGN) && (level != ENCRYPT)))
- return (EINVAL);
-
- srv->security_level = level;
-
- return (0);
-} /* }}} int lcc_server_set_security_level */
-
-int lcc_server_set_credentials (lcc_server_t *srv, /* {{{ */
+ lcc_security_level_t level,
const char *username, const char *password)
{
- char *tmp_username;
- char *tmp_password;
-
- if ((srv == NULL) || (username == NULL) || (password == NULL))
- return (EINVAL);
-
- tmp_username = strdup (username);
- if (tmp_username == NULL)
- return (ENOMEM);
-
- tmp_password = strdup (password);
- if (tmp_password == NULL)
- {
- free (tmp_username);
- return (ENOMEM);
- }
-
- free (srv->username);
- free (srv->password);
-
- srv->username = tmp_username;
- srv->password = tmp_password;
-
- return (0);
-} /* }}} int lcc_server_set_credentials */
+ return (lcc_network_buffer_set_security_level (srv->buffer,
+ level, username, password));
+} /* }}} int lcc_server_set_security_level */
int lcc_network_values_send (lcc_network_t *net, /* {{{ */
const lcc_value_list_t *vl)
* Florian octo Forster <octo at verplant.org>
**/
+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <arpa/inet.h> /* htons */
+#include <pthread.h>
+
+#if HAVE_LIBGCRYPT
+#include <gcrypt.h>
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+#endif
+
#include "collectd/network_buffer.h"
#define TYPE_HOST 0x0000
#define TYPE_SIGN_SHA256 0x0200
#define TYPE_ENCR_AES256 0x0210
+#define PART_SIGNATURE_SHA256_SIZE 36
+
/*
* Data types
*/
lcc_value_list_t state;
char *ptr;
size_t free;
+
+ lcc_security_level_t seclevel;
+ char *username;
+ char *password;
};
#define SSTRNCPY(dst,src,sz) do { \
/*
* Private functions
*/
+static _Bool have_gcrypt (void) /* {{{ */
+{
+ static _Bool result = 0;
+ static _Bool need_init = 1;
+
+ if (!need_init)
+ return (result);
+ need_init = 0;
+
+ gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+
+ if (!gcry_check_version (GCRYPT_VERSION))
+ return (0);
+
+ gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+ result = 1;
+ return (1);
+} /* }}} _Bool have_gcrypt */
+
static uint64_t htonll (uint64_t val) /* {{{ */
{
static int config = 0;
return (0);
} /* }}} int nb_add_value_list */
+static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
+{
+ char *buffer;
+ size_t buffer_size;
+
+ gcry_md_hd_t hd;
+ gcry_error_t err;
+ unsigned char *hash;
+ const size_t hash_length = 32;
+
+ /* The type, length and username have already been filled in by
+ * "lcc_network_buffer_initialize". All we do here is calculate the hash over
+ * the username and the data and add the hash value to the buffer. */
+
+ buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
+ assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
+ buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
+
+ hd = NULL;
+ err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+ if (err != 0)
+ return (-1);
+
+ assert (nb->password != NULL);
+ err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
+ if (err != 0)
+ {
+ gcry_md_close (hd);
+ return (-1);
+ }
+
+ gcry_md_write (hd, buffer, buffer_size);
+ hash = gcry_md_read (hd, GCRY_MD_SHA256);
+ if (hash == NULL)
+ {
+ gcry_md_close (hd);
+ return (-1);
+ }
+
+ assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
+ memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
+
+ gcry_md_close (hd);
+ return (0);
+} /* }}} int nb_add_signature */
+
/*
* Public functions
*/
nb->ptr = nb->buffer;
nb->free = nb->size;
+ nb->seclevel = NONE;
+ nb->username = NULL;
+ nb->password = NULL;
+
return (nb);
} /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
lcc_security_level_t level,
- const char *user, const char *password)
+ const char *username, const char *password)
{
- /* FIXME: Not yet implemented */
- return (-1);
+ char *username_copy;
+ char *password_copy;
+
+ if (level == NONE)
+ {
+ free (nb->username);
+ free (nb->password);
+ nb->username = NULL;
+ nb->password = NULL;
+ nb->seclevel = NONE;
+ lcc_network_buffer_initialize (nb);
+ return (0);
+ }
+
+ if (!have_gcrypt ())
+ return (ENOTSUP);
+
+ username_copy = strdup (username);
+ password_copy = strdup (password);
+ if ((username_copy == NULL) || (password_copy == NULL))
+ {
+ free (username_copy);
+ free (password_copy);
+ return (ENOMEM);
+ }
+
+ free (nb->username);
+ free (nb->password);
+ nb->username = username_copy;
+ nb->password = password_copy;
+ nb->seclevel = level;
+
+ lcc_network_buffer_initialize (nb);
+ return (0);
} /* }}} int lcc_network_buffer_set_security_level */
int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
nb->ptr = nb->buffer;
nb->free = nb->size;
+ if (nb->seclevel == SIGN)
+ {
+ size_t username_len;
+ uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
+ uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
+
+ assert (nb->username != NULL);
+ username_len = strlen (nb->username);
+ pkg_length = htons (pkg_length + ((uint16_t) username_len));
+
+ /* Fill in everything but the hash value here. */
+ memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
+ memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
+ nb->ptr += PART_SIGNATURE_SHA256_SIZE;
+ nb->free -= PART_SIGNATURE_SHA256_SIZE;
+
+ memcpy (nb->ptr, nb->username, username_len);
+ nb->ptr += username_len;
+ nb->free -= username_len;
+ }
+
/* FIXME: If security is enabled, reserve space for the signature /
* encryption block here. */
if (nb == NULL)
return (EINVAL);
+ if (nb->seclevel == SIGN)
+ nb_add_signature (nb);
/* FIXME: If security is enabled, sign or encrypt the packet here. */
return (0);