static void infinoted_plugin_manager_socket_accept_func(InfNativeSocket* socket, InfIoEvent event, gpointer user_data) { InfinotedPluginDocumentStream* plugin; int val; int errval; socklen_t len; InfNativeSocket new_socket; GError* error; plugin = (InfinotedPluginDocumentStream*)user_data; if(event & INF_IO_ERROR) { len = sizeof(errval); val = getsockopt(*socket, SOL_SOCKET, SO_ERROR, &errval, &len); if(val == -1) { infinoted_log_warning( infinoted_plugin_manager_get_log(plugin->manager), "Failed to obtain error from socket: %s", strerror(errno) ); } else { infinoted_log_warning( infinoted_plugin_manager_get_log(plugin->manager), "Document streaming server error: %s", strerror(errval) ); } } else if(event & INF_IO_INCOMING) { error = NULL; new_socket = infinoted_plugin_document_stream_accept_socket( *socket, &error ); if(error != NULL) { infinoted_log_warning( infinoted_plugin_manager_get_log(plugin->manager), "Failed to accept new stream: %s", error->message ); g_error_free(error); } else { infinoted_plugin_document_stream_add_stream(plugin, new_socket); } } }
static void infinoted_plugin_linekeeper_user_join_cb(InfRequest* request, const InfRequestResult* result, const GError* error, gpointer user_data) { InfinotedPluginLinekeeperSessionInfo* info; InfUser* user; info = (InfinotedPluginLinekeeperSessionInfo*)user_data; info->request = NULL; if(error != NULL) { infinoted_log_warning( infinoted_plugin_manager_get_log(info->plugin->manager), _("Could not join LineKeeper user for document: %s\n"), error->message ); } else { inf_request_result_get_join_user(result, NULL, &user); info->user = user; g_object_ref(info->user); /* Initial run */ infinoted_plugin_linekeeper_run(info); g_signal_connect( G_OBJECT(info->buffer), "text-inserted", G_CALLBACK(infinoted_plugin_linekeeper_text_inserted_cb), info ); g_signal_connect( G_OBJECT(info->buffer), "text-erased", G_CALLBACK(infinoted_plugin_linekeeper_text_erased_cb), info ); /* It can happen that while the request is being processed, the situation * changes again. */ if(infinoted_plugin_linekeeper_has_available_users(info) == FALSE) { infinoted_plugin_linekeeper_remove_user(info); } } }
static void infinoted_plugin_dbus_name_lost_func(GDBusConnection* connection, const gchar* name, gpointer user_data) { InfinotedPluginDbus* plugin; plugin = (InfinotedPluginDbus*)user_data; infinoted_log_warning( infinoted_plugin_manager_get_log(plugin->manager), "The name \"%s\" could not be acquired on the bus: " "d-bus functionality is not available", name ); }
static void infinoted_plugin_certificate_auth_set_acl_cb(InfRequest* request, const InfRequestResult* result, const GError* error, gpointer user_data) { InfinotedPluginCertificateAuth* plugin; plugin = (InfinotedPluginCertificateAuth*)user_data; if(error != NULL) { infinoted_log_warning( infinoted_plugin_manager_get_log(plugin->manager), _("Failed to set permissions for super user: %s"), error->message ); } }
static void infinoted_plugin_certificate_auth_remove_acl_account_cb( InfRequest* request, const InfRequestResult* result, const GError* error, gpointer user_data) { InfinotedPluginCertificateAuth* plugin; plugin = (InfinotedPluginCertificateAuth*)user_data; if(error != NULL) { infinoted_log_warning( infinoted_plugin_manager_get_log(plugin->manager), _("Failed to remove super user on server shutdown. This should not be " "a problem since the account is not made persistent, however might " "point to an inconsistency in the server setup. The error message " "was: %s"), error->message ); } }
static gboolean infinoted_plugin_document_stream_send( InfinotedPluginDocumentStreamStream* stream, const void* data, gsize len) { GError* error; gsize sent; if(stream->send_queue.len > 0) { infinoted_plugin_document_stream_queue_append( &stream->send_queue, data, len ); return TRUE; } else { error = NULL; sent = infinoted_plugin_document_stream_send_direct( stream, data, len, &error ); if(error != NULL) { infinoted_log_warning( infinoted_plugin_manager_get_log(stream->plugin->manager), "Document stream error: %s", error->message ); g_error_free(error); return FALSE; } else { if(sent < len) { infinoted_plugin_document_stream_queue_append( &stream->send_queue, (const gchar*)data + sent, len - sent ); inf_io_update_watch( infinoted_plugin_manager_get_io(stream->plugin->manager), stream->watch, INF_IO_INCOMING | INF_IO_OUTGOING ); } return TRUE; } } }
static void infinoted_plugin_document_stream_io_func(InfNativeSocket* socket, InfIoEvent event, gpointer user_data) { InfinotedPluginDocumentStreamStream* stream; InfinotedPluginManager* manager; int val; int errval; socklen_t len; GError* error; stream = (InfinotedPluginDocumentStreamStream*)user_data; manager = stream->plugin->manager; if(event & INF_IO_ERROR) { len = sizeof(errval); val = getsockopt(*socket, SOL_SOCKET, SO_ERROR, &errval, &len); if(val == -1) { infinoted_log_warning( infinoted_plugin_manager_get_log(manager), "Failed to obtain error from socket: %s", strerror(errno) ); } else { if(errval == 0) { /* Connection closed */ infinoted_plugin_document_stream_close_stream(stream); } else { infinoted_log_warning( infinoted_plugin_manager_get_log(manager), "Document stream error: %s", strerror(errval) ); } } } else if(event & INF_IO_INCOMING) { error = NULL; if(!infinoted_plugin_document_stream_io_in(stream, &error)) { infinoted_log_warning( infinoted_plugin_manager_get_log(manager), "Document stream error: %s", error->message ); g_error_free(error); } } else if(event & INF_IO_OUTGOING) { error = NULL; if(!infinoted_plugin_document_stream_io_out(stream, &error)) { infinoted_log_warning( infinoted_plugin_manager_get_log(manager), "Document stream error: %s", error->message ); g_error_free(error); } } }
static void infinoted_plugin_autosave_save(InfinotedPluginAutosaveSessionInfo* info) { InfdDirectory* directory; InfBrowserIter* iter; GError* error; gchar* path; InfSession* session; InfBuffer* buffer; gchar* root_directory; gchar* argv[4]; directory = infinoted_plugin_manager_get_directory(info->plugin->manager); iter = &info->iter; error = NULL; if(info->timeout != NULL) { inf_io_remove_timeout(infd_directory_get_io(directory), info->timeout); info->timeout = NULL; } g_object_get(G_OBJECT(info->proxy), "session", &session, NULL); buffer = inf_session_get_buffer(session); inf_signal_handlers_block_by_func( G_OBJECT(buffer), G_CALLBACK(infinoted_plugin_autosave_buffer_notify_modified_cb), info ); if(infd_directory_iter_save_session(directory, iter, &error) == FALSE) { path = inf_browser_get_path(INF_BROWSER(directory), iter); infinoted_log_warning( infinoted_plugin_manager_get_log(info->plugin->manager), _("Failed to auto-save session \"%s\": %s\n\n" "Will retry in %u seconds."), path, error->message, info->plugin->interval ); g_free(path); g_error_free(error); error = NULL; infinoted_plugin_autosave_start(info); } else { /* TODO: Remove this as soon as directory itself unsets modified flag * on session_write */ inf_buffer_set_modified(INF_BUFFER(buffer), FALSE); if(info->plugin->hook != NULL) { path = inf_browser_get_path(INF_BROWSER(directory), iter); g_object_get( G_OBJECT(infd_directory_get_storage(directory)), "root-directory", &root_directory, NULL ); argv[0] = info->plugin->hook; argv[1] = root_directory; argv[2] = path; argv[3] = NULL; if(!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error)) { infinoted_log_warning( infinoted_plugin_manager_get_log(info->plugin->manager), _("Could not execute autosave hook: \"%s\""), error->message ); g_error_free(error); error = NULL; } g_free(path); g_free(root_directory); } } inf_signal_handlers_unblock_by_func( G_OBJECT(buffer), G_CALLBACK(infinoted_plugin_autosave_buffer_notify_modified_cb), info ); g_object_unref(session); }
static InfAdoptedSessionRecord* infinoted_plugin_record_start(InfinotedPluginRecord* plugin, InfAdoptedSession* session, const gchar* title) { gchar* dirname; gchar* basename; gchar* filename; guint i; gsize pos; InfAdoptedSessionRecord* record; GError* error; basename = g_build_filename(g_get_home_dir(), ".infinoted-records", title, NULL); pos = strlen(basename) + 8; filename = g_strdup_printf("%s.record-00000.xml", basename); g_free(basename); i = 0; while(g_file_test(filename, G_FILE_TEST_EXISTS) && ++i < 100000) g_snprintf(filename + pos, 10, "%05u.xml", i); record = NULL; if(i >= 100000) { dirname = g_path_get_dirname(filename); infinoted_log_warning( infinoted_plugin_manager_get_log(plugin->manager), _("Could not create record file for session \"%s\": Could not generate " "unused record file in directory \"%s\""), title, dirname ); g_free(dirname); } else { error = NULL; if(!infinoted_util_create_dirname(filename, &error)) { dirname = g_path_get_dirname(filename); infinoted_log_warning( infinoted_plugin_manager_get_log(plugin->manager), _("Could not create directory \"%s\": %s"), filename, error->message ); g_error_free(error); g_free(dirname); } else { record = inf_adopted_session_record_new(session); inf_adopted_session_record_start_recording(record, filename, &error); if(error != NULL) { infinoted_log_warning( infinoted_plugin_manager_get_log(plugin->manager), _("Error while writing record for session \"%s\" into \"%s\": %s"), title, filename, error->message ); g_error_free(error); g_object_unref(record); record = NULL; } } } g_free(filename); return record; }
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; }
static gboolean infinoted_plugin_transformation_protection_check_request_cb(InfAdoptedSession* session, InfAdoptedRequest* request, InfAdoptedUser* user, gpointer user_data) { InfinotedPluginTransformationProtectionSessionInfo* info; guint vdiff; InfXmlConnection* connection; gchar* request_str; gchar* current_str; gchar* remote_id; gchar* path; info = (InfinotedPluginTransformationProtectionSessionInfo*)user_data; vdiff = inf_adopted_state_vector_vdiff( inf_adopted_request_get_vector(request), inf_adopted_algorithm_get_current( inf_adopted_session_get_algorithm(session) ) ); if(vdiff > info->plugin->max_vdiff) { connection = inf_user_get_connection(INF_USER(user)); /* Local requests do not need to be transformed, so always have a * zero vdiff. */ g_assert(connection != NULL); /* Kill the connection */ infd_session_proxy_unsubscribe( INFD_SESSION_PROXY(info->proxy), connection ); /* Write a log message */ path = inf_browser_get_path( INF_BROWSER( infinoted_plugin_manager_get_directory(info->plugin->manager) ), &info->iter ); request_str = inf_adopted_state_vector_to_string( inf_adopted_request_get_vector(request) ); current_str = inf_adopted_state_vector_to_string( inf_adopted_algorithm_get_current( inf_adopted_session_get_algorithm(session) ) ); g_object_get(G_OBJECT(connection), "remote-id", &remote_id, NULL); infinoted_log_warning( infinoted_plugin_manager_get_log(info->plugin->manager), _("In document \"%s\": Attempt to transform request \"%s\" to current state \"%s\" " "(vdiff=%u) by user \"%s\" (id=%u, conn=%s). Maximum allowed is %u; the " "connection has been unsubscribed."), path, request_str, current_str, vdiff, inf_user_get_name(INF_USER(user)), inf_user_get_id(INF_USER(user)), remote_id, info->plugin->max_vdiff ); g_free(path); g_free(request_str); g_free(current_str); g_free(remote_id); /* Prevent the request from being transformed */ return TRUE; } return FALSE; }