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; }
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") ); } } } }
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); }
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; }
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; }
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); }
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; }