From: Florian Forster Date: Sat, 25 Apr 2009 13:29:08 +0000 (+0200) Subject: Merge branch 'master' into ff/auth X-Git-Tag: collectd-4.7.0~40^2~4 X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=72be377eaaeda26f4268aba543a2677db3940666;p=collectd.git Merge branch 'master' into ff/auth Conflicts: src/network.c --- 72be377eaaeda26f4268aba543a2677db3940666 diff --cc src/network.c index 91cfa4c6,25db4fee..1425629c --- a/src/network.c +++ b/src/network.c @@@ -78,53 -78,23 +78,53 @@@ /* * Private data types */ -typedef struct sockent +#define SECURITY_LEVEL_NONE 0 - #if HAVE_GCRYPT_H ++#if HAVE_LIBGCRYPT +# define SECURITY_LEVEL_SIGN 1 +# define SECURITY_LEVEL_ENCRYPT 2 +#endif +struct sockent_client { - int fd; + int fd; struct sockaddr_storage *addr; socklen_t addrlen; - #if HAVE_GCRYPT_H ++#if HAVE_LIBGCRYPT + int security_level; + char *username; + char *password; + gcry_cipher_hd_t cypher; + unsigned char password_hash[32]; +#endif +}; -#define SECURITY_LEVEL_NONE 0 +struct sockent_server +{ + int *fd; + size_t fd_num; - #if HAVE_GCRYPT_H + #if HAVE_LIBGCRYPT -# define SECURITY_LEVEL_SIGN 1 -# define SECURITY_LEVEL_ENCRYPT 2 int security_level; - char *shared_secret; - unsigned char shared_secret_hash[32]; + char *auth_file; + fbhash_t *userdb; gcry_cipher_hd_t cypher; -#endif /* HAVE_LIBGCRYPT */ +#endif +}; + +typedef struct sockent +{ +#define SOCKENT_TYPE_CLIENT 1 +#define SOCKENT_TYPE_SERVER 2 + int type; + + char *node; + char *service; + + union + { + struct sockent_client client; + struct sockent_server server; + } data; - struct sockent *next; + struct sockent *next; } sockent_t; /* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 @@@ -403,44 -369,16 +403,44 @@@ static int cache_check (const value_lis return (retval); } /* int cache_check */ - #if HAVE_GCRYPT_H + #if HAVE_LIBGCRYPT static gcry_cipher_hd_t network_get_aes256_cypher (sockent_t *se, /* {{{ */ - const void *iv, size_t iv_size) + const void *iv, size_t iv_size, const char *username) { gcry_error_t err; + gcry_cipher_hd_t *cyper_ptr; + unsigned char password_hash[32]; - if (se->cypher == NULL) + if (se->type == SOCKENT_TYPE_CLIENT) { - err = gcry_cipher_open (&se->cypher, - GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, /* flags = */ 0); + cyper_ptr = &se->data.client.cypher; + memcpy (password_hash, se->data.client.password_hash, + sizeof (password_hash)); + } + else + { + char *secret; + + cyper_ptr = &se->data.server.cypher; + + if (username == NULL) + return (NULL); + + secret = fbh_get (se->data.server.userdb, username); + if (secret == NULL) + return (NULL); + + gcry_md_hash_buffer (GCRY_MD_SHA256, + password_hash, + secret, strlen (secret)); + + sfree (secret); + } + + if (*cyper_ptr == NULL) + { + err = gcry_cipher_open (cyper_ptr, + GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0); if (err != 0) { ERROR ("network plugin: gcry_cipher_open returned: %s", @@@ -476,9 -414,9 +476,9 @@@ return (NULL); } - return (se->cypher); + return (*cyper_ptr); } /* }}} int network_get_aes256_cypher */ - #endif /* HAVE_GCRYPT_H */ + #endif /* HAVE_LIBGCRYPT */ static int write_part_values (char **ret_buffer, int *ret_buffer_len, const data_set_t *ds, const value_list_t *vl) @@@ -1255,8 -1149,8 +1255,8 @@@ static int parse_packet (sockent_t *se break; } } - #if HAVE_GCRYPT_H + #if HAVE_LIBGCRYPT - else if ((se->security_level == SECURITY_LEVEL_ENCRYPT) + else if ((se->data.server.security_level == SECURITY_LEVEL_ENCRYPT) && (packet_was_encrypted == 0)) { if (printed_ignore_warning == 0) @@@ -1281,8 -1175,8 +1281,8 @@@ break; } } - #if HAVE_GCRYPT_H + #if HAVE_LIBGCRYPT - else if ((se->security_level == SECURITY_LEVEL_SIGN) + else if ((se->data.server.security_level == SECURITY_LEVEL_SIGN) && (packet_was_encrypted == 0) && (packet_was_signed == 0)) { @@@ -1434,66 -1328,28 +1434,66 @@@ return (status); } /* }}} int parse_packet */ -static void free_sockent (sockent_t *se) /* {{{ */ +static void free_sockent_client (struct sockent_client *sec) /* {{{ */ { - sockent_t *next; - while (se != NULL) - { - next = se->next; + if (sec->fd >= 0) + { + close (sec->fd); + sec->fd = -1; + } + sfree (sec->addr); - #if HAVE_GCRYPT_H ++#if HAVE_LIBGCRYPT + sfree (sec->username); + sfree (sec->password); + if (sec->cypher != NULL) + gcry_cipher_close (sec->cypher); +#endif +} /* }}} void free_sockent_client */ + +static void free_sockent_server (struct sockent_server *ses) /* {{{ */ +{ + size_t i; + + for (i = 0; i < ses->fd_num; i++) + { + if (ses->fd[i] >= 0) + { + close (ses->fd[i]); + ses->fd[i] = -1; + } + } + sfree (ses->fd); - #if HAVE_GCRYPT_H + #if HAVE_LIBGCRYPT - if (se->cypher != NULL) - { - gcry_cipher_close (se->cypher); - se->cypher = NULL; - } - free (se->shared_secret); -#endif /* HAVE_LIBGCRYPT */ + sfree (ses->auth_file); + fbh_destroy (ses->userdb); + if (ses->cypher != NULL) + gcry_cipher_close (ses->cypher); +#endif +} /* }}} void free_sockent_server */ - free (se->addr); - free (se); +static void sockent_destroy (sockent_t *se) /* {{{ */ +{ + sockent_t *next; - se = next; - } -} /* }}} void free_sockent */ + DEBUG ("network plugin: sockent_destroy (se = %p);", (void *) se); + + while (se != NULL) + { + next = se->next; + + sfree (se->node); + sfree (se->service); + + if (se->type == SOCKENT_TYPE_CLIENT) + free_sockent_client (&se->data.client); + else + free_sockent_server (&se->data.server); + + sfree (se); + se = next; + } +} /* }}} void sockent_destroy */ /* * int network_set_ttl @@@ -1667,117 -1521,24 +1667,117 @@@ static int network_bind_socket (int fd return (0); } /* int network_bind_socket */ -#define CREATE_SOCKET_FLAGS_LISTEN 0x0001 -static sockent_t *network_create_socket (const char *node, /* {{{ */ - const char *service, - const char *shared_secret, - int security_level, - int flags) +/* Initialize a sockent structure. `type' must be either `SOCKENT_TYPE_CLIENT' + * or `SOCKENT_TYPE_SERVER' */ +static int sockent_init (sockent_t *se, int type) /* {{{ */ +{ + if (se == NULL) + return (-1); + + memset (se, 0, sizeof (*se)); + + se->type = SOCKENT_TYPE_CLIENT; + se->node = NULL; + se->service = NULL; + se->next = NULL; + + if (type == SOCKENT_TYPE_SERVER) + { + se->type = SOCKENT_TYPE_SERVER; + se->data.server.fd = NULL; - #if HAVE_GCRYPT_H ++#if HAVE_LIBGCRYPT + se->data.server.security_level = SECURITY_LEVEL_NONE; + se->data.server.auth_file = NULL; + se->data.server.userdb = NULL; + se->data.server.cypher = NULL; +#endif + } + else + { + se->data.client.fd = -1; + se->data.client.addr = NULL; - #if HAVE_GCRYPT_H ++#if HAVE_LIBGCRYPT + se->data.client.security_level = SECURITY_LEVEL_NONE; + se->data.client.username = NULL; + se->data.client.password = NULL; + se->data.client.cypher = NULL; +#endif + } + + return (0); +} /* }}} int sockent_init */ + +/* Open the file descriptors for a initialized sockent structure. */ +static int sockent_open (sockent_t *se) /* {{{ */ { struct addrinfo ai_hints; struct addrinfo *ai_list, *ai_ptr; int ai_return; - sockent_t *se_head = NULL; - sockent_t *se_tail = NULL; + const char *node; + const char *service; + + if (se == NULL) + return (-1); + + /* Set up the security structures. */ - #if HAVE_GCRYPT_H /* {{{ */ ++#if HAVE_LIBGCRYPT /* {{{ */ + if (se->type == SOCKENT_TYPE_CLIENT) + { + if (se->data.client.security_level > SECURITY_LEVEL_NONE) + { + if ((se->data.client.username == NULL) + || (se->data.client.password == NULL)) + { + ERROR ("network plugin: Client socket with " + "security requested, but no " + "credentials are configured."); + return (-1); + } + gcry_md_hash_buffer (GCRY_MD_SHA256, + se->data.client.password_hash, + se->data.client.password, + strlen (se->data.client.password)); + } + } + else /* (se->type == SOCKENT_TYPE_SERVER) */ + { + if (se->data.server.security_level > SECURITY_LEVEL_NONE) + { + if (se->data.server.auth_file == NULL) + { + ERROR ("network plugin: Server socket with " + "security requested, but no " + "password file is configured."); + return (-1); + } + } + if (se->data.server.auth_file != NULL) + { + se->data.server.userdb = fbh_create (se->data.server.auth_file); + if (se->data.server.userdb == NULL) + { + ERROR ("network plugin: Reading password file " + "`%s' failed.", + se->data.server.auth_file); + if (se->data.server.security_level > SECURITY_LEVEL_NONE) + return (-1); + } + } + } - #endif /* }}} HAVE_GCRYPT_H */ ++#endif /* }}} HAVE_LIBGCRYPT */ + + node = se->node; + service = se->service; - DEBUG ("node = %s, service = %s", node, service); + if (service == NULL) + service = NET_DEFAULT_PORT; - memset (&ai_hints, '\0', sizeof (ai_hints)); - ai_hints.ai_flags = 0; + DEBUG ("network plugin: sockent_open: node = %s; service = %s;", + node, service); + + memset (&ai_hints, 0, sizeof (ai_hints)); + ai_hints.ai_flags = 0; #ifdef AI_PASSIVE ai_hints.ai_flags |= AI_PASSIVE; #endif @@@ -2164,12 -1993,7 +2164,12 @@@ static void networt_send_buffer_plain ( } /* while (42) */ } /* }}} void networt_send_buffer_plain */ - #if HAVE_GCRYPT_H + #if HAVE_LIBGCRYPT +#define BUFFER_ADD(p,s) do { \ + memcpy (buffer + buffer_offset, (p), (s)); \ + buffer_offset += (s); \ +} while (0) + static void networt_send_buffer_signed (const sockent_t *se, /* {{{ */ const char *in_buffer, size_t in_buffer_size) { @@@ -2326,9 -2134,9 +2326,9 @@@ static void networt_send_buffer_encrypt /* Send it out without further modifications */ networt_send_buffer_plain (se, buffer, buffer_size); -#undef BUFFER_ADD } /* }}} void networt_send_buffer_encrypted */ +#undef BUFFER_ADD - #endif /* HAVE_GCRYPT_H */ + #endif /* HAVE_LIBGCRYPT */ static void network_send_buffer (char *buffer, size_t buffer_len) /* {{{ */ { @@@ -2338,13 -2146,13 +2338,13 @@@ for (se = sending_sockets; se != NULL; se = se->next) { - #if HAVE_GCRYPT_H + #if HAVE_LIBGCRYPT - if (se->security_level == SECURITY_LEVEL_ENCRYPT) + if (se->data.client.security_level == SECURITY_LEVEL_ENCRYPT) networt_send_buffer_encrypted (se, buffer, buffer_len); - else if (se->security_level == SECURITY_LEVEL_SIGN) + else if (se->data.client.security_level == SECURITY_LEVEL_SIGN) networt_send_buffer_signed (se, buffer, buffer_len); - else /* if (se->security_level == SECURITY_LEVEL_NONE) */ + else /* if (se->data.client.security_level == SECURITY_LEVEL_NONE) */ - #endif /* HAVE_GCRYPT_H */ + #endif /* HAVE_LIBGCRYPT */ networt_send_buffer_plain (se, buffer, buffer_len); } /* for (sending_sockets) */ } /* }}} void network_send_buffer */ @@@ -2545,29 -2353,7 +2545,29 @@@ static int network_config_set_ttl (cons return (0); } /* }}} int network_config_set_ttl */ +static int network_config_set_string (const oconfig_item_t *ci, /* {{{ */ + char **ret_string) +{ + char *tmp; + if ((ci->values_num != 1) + || (ci->values[0].type != OCONFIG_TYPE_STRING)) + { + WARNING ("network plugin: The `%s' config option needs exactly " + "one string argument.", ci->key); + return (-1); + } + + tmp = strdup (ci->values[0].value.string); + if (tmp == NULL) + return (-1); + + sfree (*ret_string); + *ret_string = tmp; + + return (0); +} /* }}} int network_config_set_string */ + - #if HAVE_GCRYPT_H + #if HAVE_LIBGCRYPT static int network_config_set_security_level (oconfig_item_t *ci, /* {{{ */ int *retval) { @@@ -2595,12 -2381,14 +2595,12 @@@ return (0); } /* }}} int network_config_set_security_level */ - #endif /* HAVE_GCRYPT_H */ + #endif /* HAVE_LIBGCRYPT */ -static int network_config_listen_server (const oconfig_item_t *ci) /* {{{ */ +static int network_config_add_listen (const oconfig_item_t *ci) /* {{{ */ { - char *node; - char *service; - char *shared_secret = NULL; - int security_level = SECURITY_LEVEL_NONE; + sockent_t *se; + int status; int i; if ((ci->values_num < 1) || (ci->values_num > 2) @@@ -2628,90 -2410,20 +2628,90 @@@ { oconfig_item_t *child = ci->children + i; - #if HAVE_GCRYPT_H + #if HAVE_LIBGCRYPT - if (strcasecmp ("Secret", child->key) == 0) + if (strcasecmp ("AuthFile", child->key) == 0) + network_config_set_string (child, &se->data.server.auth_file); + else if (strcasecmp ("SecurityLevel", child->key) == 0) + network_config_set_security_level (child, + &se->data.server.security_level); + else - #endif /* HAVE_GCRYPT_H */ ++#endif /* HAVE_LIBGCRYPT */ { - if ((child->values_num == 1) - && (child->values[0].type == OCONFIG_TYPE_STRING)) - shared_secret = child->values[0].value.string; - else - ERROR ("network plugin: The `Secret' option needs exactly one string " - "argument."); + WARNING ("network plugin: Option `%s' is not allowed here.", + child->key); } + } + + if ((se->data.server.security_level > SECURITY_LEVEL_NONE) + && (se->data.server.auth_file == NULL)) + { + ERROR ("network plugin: A security level higher than `none' was " + "requested, but no AuthFile option was given. Cowardly refusing to " + "open this socket!"); + sockent_destroy (se); + return (-1); + } + + status = sockent_open (se); + if (status != 0) + { + ERROR ("network plugin: network_config_add_listen: sockent_open failed."); + sockent_destroy (se); + return (-1); + } + + status = sockent_add (se); + if (status != 0) + { + ERROR ("network plugin: network_config_add_listen: sockent_add failed."); + sockent_destroy (se); + return (-1); + } + + return (0); +} /* }}} int network_config_add_listen */ + +static int network_config_add_server (const oconfig_item_t *ci) /* {{{ */ +{ + sockent_t *se; + int status; + int i; + + if ((ci->values_num < 1) || (ci->values_num > 2) + || (ci->values[0].type != OCONFIG_TYPE_STRING) + || ((ci->values_num > 1) && (ci->values[1].type != OCONFIG_TYPE_STRING))) + { + ERROR ("network plugin: The `%s' config option needs " + "one or two string arguments.", ci->key); + return (-1); + } + + se = malloc (sizeof (*se)); + if (se == NULL) + { + ERROR ("network plugin: malloc failed."); + return (-1); + } + sockent_init (se, SOCKENT_TYPE_CLIENT); + + se->node = strdup (ci->values[0].value.string); + if (ci->values_num >= 2) + se->service = strdup (ci->values[1].value.string); + + for (i = 0; i < ci->children_num; i++) + { + oconfig_item_t *child = ci->children + i; + - #if HAVE_GCRYPT_H ++#if HAVE_LIBGCRYPT + if (strcasecmp ("Username", child->key) == 0) + network_config_set_string (child, &se->data.client.username); + else if (strcasecmp ("Password", child->key) == 0) + network_config_set_string (child, &se->data.client.password); else if (strcasecmp ("SecurityLevel", child->key) == 0) - network_config_set_security_level (child, &security_level); + network_config_set_security_level (child, + &se->data.client.security_level); else - #endif /* HAVE_GCRYPT_H */ + #endif /* HAVE_LIBGCRYPT */ { WARNING ("network plugin: Option `%s' is not allowed here.", child->key);