コード例 #1
0
static gnutls_x509_privkey_t
infinoted_startup_load_key(InfinotedLog* log,
                           gboolean create_key,
                           const gchar* key_file,
                           GError** error)
{
  gnutls_x509_privkey_t key;

  if(create_key == TRUE)
  {
    if(infinoted_util_create_dirname(key_file, error) == FALSE)
      return NULL;

    /* TODO: Open the key file beforehand */

    infinoted_log_info(log, _("Generating 4096 bit RSA private key..."));
    key = inf_cert_util_create_private_key(GNUTLS_PK_RSA, 4096, error);

    if(key == NULL)
      return NULL;

    if(inf_cert_util_write_private_key(key, key_file, error) == FALSE)
    {
      gnutls_x509_privkey_deinit(key);
      return NULL;
    }
  }
  else
  {
    key = inf_cert_util_read_private_key(key_file, error);
  }

  return key;
}
コード例 #2
0
static void
infinoted_signal_sig_func(InfNativeSocket* fd,
                          InfIoEvent event,
                          gpointer user_data)
{
  InfinotedSignal* sig;
  int occured;
  GError* error;

  sig = (InfinotedSignal*)user_data;

  if(event & INF_IO_ERROR)
  {
    inf_io_remove_watch(INF_IO(sig->run->io), sig->watch);
    daemon_signal_done();

    sig->run = NULL;
    sig->signal_fd = 0;
    sig->watch = NULL;

    infinoted_log_error(
      sig->run->startup->log,
      _("Error on signal handler connection; signal "
        "handlers have been removed from now on")
    );
  }
  else if(event & INF_IO_INCOMING)
  {
    occured = daemon_signal_next();
    if(occured == SIGINT || occured == SIGTERM || occured == SIGQUIT)
    {
      printf("\n");
      inf_standalone_io_loop_quit(sig->run->io);
    }
    else if(occured == SIGHUP)
    {
      error = NULL;
      if(!infinoted_config_reload(sig->run, &error))
      {
        infinoted_log_error(
          sig->run->startup->log,
          _("Configuration reload failed: %s"), error->message
        );

        g_error_free(error);
      }
      else
      {
        infinoted_log_info(
          sig->run->startup->log,
          _("Configuration reloaded")
        );
      }
    }
  }
}
コード例 #3
0
static void
infinoted_plugin_manager_unload_plugin(InfinotedPluginManager* manager,
                                       InfinotedPluginInstance* instance)
{
  InfinotedPluginManagerPrivate* priv;
  InfinotedPluginManagerForeachConnectionData data;
  InfBrowserIter root;

  priv = INFINOTED_PLUGIN_MANAGER_PRIVATE(manager);
  priv->plugins = g_slist_remove(priv->plugins, instance);

  /* Unregister all sessions with the plugin */
  inf_browser_get_root(INF_BROWSER(priv->directory), &root);
  infinoted_plugin_manager_walk_directory(
    manager,
    &root,
    instance,
    infinoted_plugin_manager_remove_session
  );

  /* Unregister all connections with the plugin */
  data.manager = manager;
  data.instance = instance;
  infd_directory_foreach_connection(
    priv->directory,
    infinoted_plugin_manager_unload_plugin_foreach_connection_func,
    &data
  );

  if(instance->plugin->on_deinitialize != NULL)
    instance->plugin->on_deinitialize(instance+1);

  infinoted_log_info(
    priv->log,
    _("Unloaded plugin \"%s\" from \"%s\""),
    instance->plugin->name,
    g_module_name(instance->module)
  );

  g_module_close(instance->module);
  g_free(instance);
}
コード例 #4
0
static gboolean
infinoted_plugin_manager_load_plugin(InfinotedPluginManager* manager,
                                     const gchar* plugin_path,
                                     const gchar* plugin_name,
                                     GKeyFile* key_file,
                                     GError** error)
{
  gchar* plugin_basename;
  gchar* plugin_filename;

  GModule* module;
  const InfinotedPlugin* plugin;
  InfinotedPluginInstance* instance;

  gboolean result;
  GError* local_error;

  InfBrowserIter root;
  InfinotedPluginManagerForeachConnectionData data;

  plugin_basename = g_strdup_printf(
    "libinfinoted-plugin-%s.%s",
    plugin_name,
    G_MODULE_SUFFIX
  );

  plugin_filename = g_build_filename(plugin_path, plugin_basename, NULL);
  g_free(plugin_basename);

  module = g_module_open(plugin_filename, G_MODULE_BIND_LOCAL);
  g_free(plugin_filename);

  if(module == NULL)
  {
    g_set_error(
      error,
      infinoted_plugin_manager_error_quark(),
      INFINOTED_PLUGIN_MANAGER_ERROR_OPEN_FAILED,
      "%s",
      g_module_error()
    );

    
    return FALSE;
  }

  if(g_module_symbol(module, "INFINOTED_PLUGIN", (gpointer*)&plugin) == FALSE)
  {
    g_set_error(
      error,
      infinoted_plugin_manager_error_quark(),
      INFINOTED_PLUGIN_MANAGER_ERROR_NO_ENTRY_POINT,
      "%s",
      g_module_error()
    );
    
    g_module_close(module);
    return FALSE;
  }

  instance = g_malloc(sizeof(InfinotedPluginInstance) + plugin->info_size);
  instance->module = module;
  instance->plugin = plugin;

  /* Call on_info_initialize, allowing the plugin to set default values */
  if(plugin->on_info_initialize != NULL)
    plugin->on_info_initialize(instance+1);

  /* Next, parse options from keyfile */
  if(plugin->options != NULL)
  {
    local_error = NULL;

    result = infinoted_parameter_load_from_key_file(
      plugin->options,
      key_file,
      plugin->name,
      instance+1,
      &local_error
    );
    
    if(result == FALSE)
    {
      g_free(instance);
      g_module_close(module);

      g_propagate_prefixed_error(
        error,
        local_error,
        "Failed to initialize plugin \"%s\": ",
        plugin_name
      );

      return FALSE;
    }
  }

  /* Finally, call on_initialize, which allows the plugin to initialize
   * itself with the plugin options. */
  if(plugin->on_initialize != NULL)
  {
    local_error = NULL;

    result = plugin->on_initialize(manager, instance+1, &local_error);

    if(local_error != NULL)
    {
      if(instance->plugin->on_deinitialize != NULL)
        instance->plugin->on_deinitialize(instance+1);

      g_free(instance);
      g_module_close(module);

      g_propagate_prefixed_error(
        error,
        local_error,
        "Failed to initialize plugin \"%s\": ",
        plugin_name
      );

      return FALSE;
    }
  }

  /* Register initial connections with plugin */
  data.manager = manager;
  data.instance = instance;
  infd_directory_foreach_connection(
    manager->directory,
    infinoted_plugin_manager_load_plugin_foreach_connection_func,
    &data
  );

  /* Register initial sessions with plugin */
  inf_browser_get_root(INF_BROWSER(manager->directory), &root);
  infinoted_plugin_manager_walk_directory(
    manager,
    &root,
    instance,
    infinoted_plugin_manager_add_session
  );

  infinoted_log_info(
    manager->log,
    _("Loaded plugin \"%s\" from \"%s\""),
    plugin_name,
    g_module_name(module)
  );

  manager->plugins = g_slist_prepend(manager->plugins, instance);

  return TRUE;
}
コード例 #5
0
static gnutls_x509_crt_t*
infinoted_startup_load_certificate(InfinotedLog* log,
                                   gboolean create_self_signed_certificate,
                                   gnutls_x509_privkey_t key,
                                   const gchar* certificate_file,
                                   const gchar* certificate_chain_file,
                                   guint* n_certificates,
                                   GError** error)
{
  InfCertUtilDescription desc;
  gnutls_x509_crt_t* result;
  gnutls_x509_crt_t cert;
  GPtrArray* certs;
  GPtrArray* chain_certs;
  gboolean res;

  if(create_self_signed_certificate == TRUE)
  {
    if(infinoted_util_create_dirname(certificate_file, error) == FALSE)
      return NULL;


    infinoted_log_info(log, _("Generating self-signed certificate..."));
    desc.validity = 365 * 24 * 3600;
    desc.dn_common_name = g_get_host_name();
    desc.san_dnsname = g_get_host_name();

    cert = inf_cert_util_create_self_signed_certificate(key, &desc, error);
    if(cert == NULL) return NULL;

    res = inf_cert_util_write_certificate(&cert, 1, certificate_file, error);
    if(res == FALSE)
    {
      gnutls_x509_crt_deinit(cert);
      return NULL;
    }
    else
    {
      result = g_malloc(sizeof(gnutls_x509_crt_t));
      *result = cert;
      *n_certificates = 1;
    }
  }
  else
  {
    certs = inf_cert_util_read_certificate(certificate_file, NULL, error);
    if(certs == NULL) return NULL;

    if(certificate_chain_file != NULL)
    {
      chain_certs =
        inf_cert_util_read_certificate(certificate_chain_file, certs, error);

      if(chain_certs == NULL)
      {
        result = (gnutls_x509_crt_t*)g_ptr_array_free(certs, FALSE);
        infinoted_startup_free_certificate_array(result, *n_certificates);
        return NULL;
      }
    }

    *n_certificates = certs->len;
    result = (gnutls_x509_crt_t*)g_ptr_array_free(certs, FALSE);
  }

  return result;
}
コード例 #6
0
static void
infinoted_startup_sasl_callback(InfSaslContextSession* session,
                                Gsasl_property prop,
                                gpointer session_data,
                                gpointer user_data)
{
  InfinotedStartup* startup;
  const char* username;
  const char* password;
  InfXmppConnection* xmpp;
  gchar cmp;
  gsize password_len;
  gsize i;

#ifdef LIBINFINITY_HAVE_PAM
  const gchar* pam_service;
  GError* error;
#endif
  gchar* remote_id;

  xmpp = INF_XMPP_CONNECTION(session_data);
  g_object_get(xmpp, "remote-id", &remote_id, NULL);

  switch(prop)
  {
  case GSASL_VALIDATE_SIMPLE:
    startup = (InfinotedStartup*)user_data;
    username = inf_sasl_context_session_get_property(session, GSASL_AUTHID);
    password = inf_sasl_context_session_get_property(session, GSASL_PASSWORD);
#ifdef LIBINFINITY_HAVE_PAM
    pam_service = startup->options->pam_service;
    if(pam_service != NULL)
    {
      error = NULL;
      if(!infinoted_pam_authenticate(pam_service, username, password))
      {
        infinoted_log_warning(
          startup->log,
          _("User %s failed to log in from %s: PAM authentication failed"),
          username,
          remote_id
        );

        infinoted_startup_sasl_callback_set_error(
          xmpp,
          INF_AUTHENTICATION_DETAIL_ERROR_AUTHENTICATION_FAILED,
          NULL
        );

        inf_sasl_context_session_continue(
          session,
          GSASL_AUTHENTICATION_ERROR
        );
      }
      else if(!infinoted_pam_user_is_allowed(startup, username, &error))
      {
        infinoted_log_warning(
          startup->log,
          _("User %s failed to log in from %s: PAM user not allowed"),
          username,
          remote_id
        );

        infinoted_startup_sasl_callback_set_error(
          xmpp,
          INF_AUTHENTICATION_DETAIL_ERROR_USER_NOT_AUTHORIZED,
          error
        );

        inf_sasl_context_session_continue(
          session,
          GSASL_AUTHENTICATION_ERROR
        );
      }
      else
      {
        infinoted_log_info(
          startup->log,
          _("User %s logged in from %s via PAM"),
          username,
          remote_id
        );

        inf_sasl_context_session_continue(session, GSASL_OK);
      }
    }
    else
#endif /* LIBINFINITY_HAVE_PAM */
    {
      g_assert(startup->options->password != NULL);

      /* length-independent string compare */
      cmp = 0;
      password_len = strlen(password);
      for(i = 0; i < startup->options->password_len; ++i)
      {
        if(i < password_len)
          cmp |= (startup->options->password[i] ^ password[i]);
        else
          cmp |= (startup->options->password[i] ^ 0x00);
      }

      if(startup->options->password_len != password_len)
        cmp |= 0xFF;

      if(cmp == 0)
      {
        infinoted_log_info(
          startup->log,
          _("User %s logged in from %s via password"),
          username,
          remote_id
        );

        inf_sasl_context_session_continue(session, GSASL_OK);
      }
      else
      {
        infinoted_log_warning(
          startup->log,
          _("User %s failed to log in from %s: wrong password"),
          username,
          remote_id
        );

        infinoted_startup_sasl_callback_set_error(
          xmpp,
          INF_AUTHENTICATION_DETAIL_ERROR_AUTHENTICATION_FAILED,
          NULL
        );

        inf_sasl_context_session_continue(
          session,
          GSASL_AUTHENTICATION_ERROR
        );
      }
    }

    break;
  default:
    inf_sasl_context_session_continue(session, GSASL_AUTHENTICATION_ERROR);
    break;
  }

  g_free(remote_id);
}
コード例 #7
0
static gboolean
infinoted_plugin_certificate_auth_initialize(InfinotedPluginManager* manager,
                                             gpointer plugin_info,
                                             GError** error)
{
  InfinotedPluginCertificateAuth* plugin;
  InfCertificateCredentials* creds;
  GPtrArray* read_certs;
  int res;
  guint i;

  gnutls_x509_crt_t* sign_certs;
  InfCertificateChain* sign_chain;

  gnutls_x509_privkey_t super_key;
  InfCertUtilDescription desc;
  gnutls_x509_crt_t super_cert;
  InfAclAccountId super_id;
  gnutls_x509_crt_t chain[2];
  gboolean written;

  InfdDirectory* directory;
  InfBrowserIter iter;
  InfAclSheetSet sheet_set;
  InfAclSheet sheet;
  InfRequest* request;

  plugin = (InfinotedPluginCertificateAuth*)plugin_info;
  plugin->manager = manager;

  creds = infinoted_plugin_manager_get_credentials(manager);
  if(creds == NULL)
  {
    g_set_error(
      error,
      infinoted_plugin_certificate_auth_error_quark(),
      INFINOTED_PLUGIN_CERTIFICATE_AUTH_ERROR_NO_CREDENTIALS,
      "%s",
      _("The certificate-auth plugin can only be used when TLS is enabled "
        "and a server certificate has been set.")
    );

    return FALSE;
  }

  read_certs =
    inf_cert_util_read_certificate(plugin->ca_list_file, NULL, error);
  if(read_certs == NULL) return FALSE;

  if(read_certs->len == 0)
  {
    g_set_error(
      error,
      infinoted_plugin_certificate_auth_error_quark(),
      INFINOTED_PLUGIN_CERTIFICATE_AUTH_ERROR_NO_CAS,
      _("File \"%s\" does not contain any CA certificates"),
      plugin->ca_list_file
    );

    g_ptr_array_free(read_certs, TRUE);
    return FALSE;
  }

  plugin->n_cas = read_certs->len;
  plugin->cas = (gnutls_x509_crt_t*)g_ptr_array_free(read_certs, FALSE);

  res = gnutls_certificate_set_x509_trust(
    inf_certificate_credentials_get(creds),
    plugin->cas,
    plugin->n_cas
  );

  if(res < 0)
  {
    inf_gnutls_set_error(error, res);
    return FALSE;
  }

  if(plugin->ca_key_file != NULL)
  {
    plugin->ca_key =
      inf_cert_util_read_private_key(plugin->ca_key_file, error);
    if(plugin->ca_key == NULL)
      return FALSE;

    /* Walk through certificates and find the certificate that the key
     * belongs to. */
    for(i = 0; i < plugin->n_cas; ++i)
      if(inf_cert_util_check_certificate_key(plugin->cas[i], plugin->ca_key))
        break;

    if(i == plugin->n_cas)
    {
      gnutls_x509_privkey_deinit(plugin->ca_key);
      plugin->ca_key = NULL;

      g_set_error(
        error,
        infinoted_plugin_certificate_auth_error_quark(),
        INFINOTED_PLUGIN_CERTIFICATE_AUTH_ERROR_NO_CA_FOR_KEY,
        "%s",
        _("The given CA key does not match with any of the CA certificates")
      );

      return FALSE;
    }

    plugin->ca_key_index = i;

    /* Set the signing certificate of the directory, so that it can handle
     * account creation requests. Note that this takes ownership of the
     * certificate, so we take special care in the cleanup code in
     * infinoted_plugin_certificate_auth_deinitialize(). */
    sign_certs = g_malloc(sizeof(gnutls_x509_crt_t));
    sign_certs[0] = plugin->cas[plugin->ca_key_index];
    sign_chain = inf_certificate_chain_new(sign_certs, 1);

    infd_directory_set_certificate(
      infinoted_plugin_manager_get_directory(plugin->manager),
      plugin->ca_key,
      sign_chain
    );

    inf_certificate_chain_unref(sign_chain);
  }

  if(plugin->super_user != NULL)
  {
    if(plugin->ca_key == NULL)
    {
      g_set_error(
        error,
        infinoted_plugin_certificate_auth_error_quark(),
        INFINOTED_PLUGIN_CERTIFICATE_AUTH_ERROR_NO_CA_KEY,
        "%s",
        _("Cannot generate a superuser certificate without CA key")
      );

      return FALSE;
    }

    /* Create a private key and certificate for the super user. */
    infinoted_log_info(
      infinoted_plugin_manager_get_log(plugin->manager),
      _("Creating 4096-bit RSA private key for the super user account...")
    );

    super_key =
      inf_cert_util_create_private_key(GNUTLS_PK_RSA, 4096, error);
    if(super_key == NULL)
      return FALSE;

    desc.validity = 12 * 3600; /* 12 hours */
    desc.dn_common_name = "Super User";
    desc.san_dnsname = NULL;

    super_cert = inf_cert_util_create_signed_certificate(
      super_key,
      &desc,
      plugin->cas[plugin->ca_key_index],
      plugin->ca_key,
      error
    );

    if(super_cert == NULL)
    {
      gnutls_x509_privkey_deinit(super_key);
      return FALSE;
    }

    super_id = infd_directory_create_acl_account(
      infinoted_plugin_manager_get_directory(plugin->manager),
      _("Super User"),
      TRUE, /* transient */
      &super_cert,
      1,
      error
    );

    if(super_id == 0)
    {
      gnutls_x509_crt_deinit(super_cert);
      gnutls_x509_privkey_deinit(super_key);
      return FALSE;
    }

    plugin->super_id = super_id;

    chain[0] = super_cert;
    chain[1] = plugin->cas[plugin->ca_key_index];

    written = inf_cert_util_write_certificate_with_key(
      super_key,
      chain,
      2,
      plugin->super_user,
      error
    );

    gnutls_x509_crt_deinit(super_cert);
    gnutls_x509_privkey_deinit(super_key);

    if(written == FALSE)
      return FALSE;

    inf_browser_get_root(
      INF_BROWSER(infinoted_plugin_manager_get_directory(plugin->manager)),
      &iter
    );

    directory = infinoted_plugin_manager_get_directory(plugin->manager);

    sheet.account = super_id;
    sheet.mask = INF_ACL_MASK_ALL;
    infd_directory_get_support_mask(directory, &sheet.perms);
    sheet_set.n_sheets = 1;
    sheet_set.own_sheets = NULL;
    sheet_set.sheets = &sheet;

    request = inf_browser_set_acl(
      INF_BROWSER(directory),
      &iter,
      &sheet_set,
      infinoted_plugin_certificate_auth_set_acl_cb,
      plugin
    );

    if(request != NULL)
    {
      plugin->set_acl_request = request;
      g_object_ref(plugin->set_acl_request);
    }
  }

  return TRUE;
}