Merge branch 'master' into ff/auth
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 25 Apr 2009 13:29:08 +0000 (15:29 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 25 Apr 2009 13:29:08 +0000 (15:29 +0200)
Conflicts:
src/network.c

1  2 
src/network.c

diff --cc src/network.c
  /*
   * 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",
      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)
                                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))
                {
        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;
 +    }
 +  }
  
- #if HAVE_GCRYPT_H
 +  sfree (ses->fd);
 -              if (se->cypher != NULL)
 -              {
 -                      gcry_cipher_close (se->cypher);
 -                      se->cypher = NULL;
 -              }
 -              free (se->shared_secret);
 -#endif /* HAVE_LIBGCRYPT */
+ #if 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 */
- #endif /* HAVE_GCRYPT_H */
 +#undef BUFFER_ADD
+ #endif /* HAVE_LIBGCRYPT */
  
  static void network_send_buffer (char *buffer, size_t buffer_len) /* {{{ */
  {
  
    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 */
  
- #if HAVE_GCRYPT_H
 +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_LIBGCRYPT
  static int network_config_set_security_level (oconfig_item_t *ci, /* {{{ */
      int *retval)
  {
  
    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)
    {
      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 HAVE_GCRYPT_H
 +  }
 +
 +  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_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);