static CockpitChannelResponse * cockpit_channel_response_create (CockpitWebService *service, CockpitWebResponse *response, CockpitTransport *transport, const gchar *logname, GHashTable *headers, JsonObject *open) { CockpitChannelResponse *chesp; const gchar *payload; JsonObject *done; GBytes *bytes; payload = json_object_get_string_member (open, "payload"); chesp = g_new0 (CockpitChannelResponse, 1); chesp->response = g_object_ref (response); chesp->transport = g_object_ref (transport); chesp->headers = g_hash_table_ref (headers); chesp->channel = cockpit_web_service_unique_channel (service); chesp->open = json_object_ref (open); if (!cockpit_json_get_string (open, "path", chesp->channel, &chesp->logname)) chesp->logname = chesp->channel; json_object_set_string_member (open, "command", "open"); json_object_set_string_member (open, "channel", chesp->channel); /* Special handling for http-stream1, splice in headers, handle injection */ if (g_strcmp0 (payload, "http-stream1") == 0) chesp->transport_recv = g_signal_connect (transport, "recv", G_CALLBACK (on_httpstream_recv), chesp); else chesp->transport_recv = g_signal_connect (transport, "recv", G_CALLBACK (on_transport_recv), chesp); /* Special handling for http-stream2, splice in headers, handle injection */ if (g_strcmp0 (payload, "http-stream2") == 0) chesp->transport_control = g_signal_connect (transport, "control", G_CALLBACK (on_httpstream_control), chesp); else chesp->transport_control = g_signal_connect (transport, "control", G_CALLBACK (on_transport_control), chesp); chesp->transport_closed = g_signal_connect (transport, "closed", G_CALLBACK (on_transport_closed), chesp); bytes = cockpit_json_write_bytes (chesp->open); cockpit_transport_send (transport, NULL, bytes); g_bytes_unref (bytes); done = cockpit_transport_build_json ("command", "done", "channel", chesp->channel, NULL); bytes = cockpit_json_write_bytes (done); json_object_unref (done); cockpit_transport_send (transport, NULL, bytes); g_bytes_unref (bytes); return chesp; }
/** * cockpit_channel_control: * @self: the channel * @command: the control command * @options: optional control message or NULL * * Send a control message to the other side. * * If @options is not NULL, then it may be modified by this code. * * With @command of "done" will send an EOF to the other side. This * should only be called once. Whether an EOF should be sent or not * depends on the payload type. */ void cockpit_channel_control (CockpitChannel *self, const gchar *command, JsonObject *options) { JsonObject *object; GBytes *message; g_return_if_fail (COCKPIT_IS_CHANNEL (self)); g_return_if_fail (command != NULL); if (g_str_equal (command, "done")) { g_return_if_fail (self->priv->sent_done == FALSE); self->priv->sent_done = TRUE; } if (options) object = json_object_ref (options); else object = json_object_new (); json_object_set_string_member (object, "command", command); json_object_set_string_member (object, "channel", self->priv->id); message = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (self->priv->transport, NULL, message); g_bytes_unref (message); }
static void send_init_command (CockpitTransport *transport) { const gchar *checksum; const gchar *name; JsonObject *object; GBytes *bytes; object = json_object_new (); json_object_set_string_member (object, "command", "init"); json_object_set_int_member (object, "version", 1); checksum = cockpit_packages_get_checksum (packages); if (checksum) json_object_set_string_member (object, "checksum", checksum); /* Happens when we're in --interact mode */ name = cockpit_dbus_internal_name (); if (name) json_object_set_string_member (object, "bridge-dbus-name", name); bytes = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (transport, NULL, bytes); g_bytes_unref (bytes); }
static void on_helper_read (CockpitPipe *pipe, GByteArray *buffer, gboolean eof, gpointer user_data) { ReauthorizeCaller *caller = user_data; JsonObject *object; GBytes *bytes; guint8 *lf; lf = memchr (buffer->data, '\n', buffer->len); if (!lf) return; /* Null terminate the challenge */ *lf = 0; g_debug ("got challenge from helper, will send to cockpit-ws: %s", (gchar *)buffer->data); /* send an authorize packet here */ object = json_object_new (); json_object_set_string_member (object, "command", "authorize"); json_object_set_string_member (object, "cookie", caller->cookie); json_object_set_string_member (object, "challenge", (gchar *)buffer->data); bytes = cockpit_json_write_bytes (object); json_object_unref (object); /* Consume from buffer, including null termination */ cockpit_pipe_skip (buffer, lf - buffer->data); cockpit_transport_send (caller->self->transport, NULL, bytes); g_bytes_unref (bytes); }
static GBytes * build_environment (GHashTable *os_release) { /* * We don't include entirety of os-release into the * environment for the login.html page. There could * be unexpected things in here. * * However since we are displaying branding based on * the OS name variant flavor and version, including * the corresponding information is not a leak. */ static const gchar *release_fields[] = { "NAME", "ID", "PRETTY_NAME", "VARIANT", "VARIANT_ID", "CPE_NAME", }; static const gchar *prefix = "\n <script>\nvar environment = "; static const gchar *suffix = ";\n </script>"; GByteArray *buffer; GBytes *bytes; JsonObject *object; const gchar *value; gchar *hostname; JsonObject *osr; gint i; object = json_object_new (); add_page_to_environment (object); hostname = g_malloc0 (HOST_NAME_MAX + 1); gethostname (hostname, HOST_NAME_MAX); hostname[HOST_NAME_MAX] = '\0'; json_object_set_string_member (object, "hostname", hostname); g_free (hostname); if (os_release) { osr = json_object_new (); for (i = 0; i < G_N_ELEMENTS (release_fields); i++) { value = g_hash_table_lookup (os_release, release_fields[i]); if (value) json_object_set_string_member (osr, release_fields[i], value); } json_object_set_object_member (object, "os-release", osr); } add_oauth_to_environment (object); bytes = cockpit_json_write_bytes (object); json_object_unref (object); buffer = g_bytes_unref_to_array (bytes); g_byte_array_prepend (buffer, (const guint8 *)prefix, strlen (prefix)); g_byte_array_append (buffer, (const guint8 *)suffix, strlen (suffix)); return g_byte_array_free_to_bytes (buffer); }
static void process_open (CockpitRouter *self, CockpitTransport *transport, const gchar *channel, JsonObject *options, GBytes *data) { GList *l; GBytes *new_payload = NULL; if (!channel) { g_warning ("Caller tried to open channel with invalid id"); cockpit_transport_close (transport, "protocol-error"); } /* Check that this isn't a local channel */ else if (g_hash_table_lookup (self->channels, channel)) { g_warning ("%s: caller tried to reuse a channel that's already in use", channel); cockpit_transport_close (self->transport, "protocol-error"); return; } /* Request that this channel is frozen, and requeue its open message for later */ else if (g_hash_table_size (self->fences) > 0 && !g_hash_table_lookup (self->fences, channel)) { if (!self->fenced) self->fenced = g_queue_new (); g_queue_push_tail (self->fenced, g_strdup (channel)); cockpit_transport_freeze (self->transport, channel); cockpit_transport_emit_control (self->transport, "open", channel, options, data); } else if (!cockpit_router_normalize_host (self, options)) { g_warning ("%s: caller specified invalid 'host' field in open message", channel); process_open_not_supported (self, channel, options, data, NULL); } /* Now go throgh the rules */ else { cockpit_router_normalize_host_params (options); new_payload = cockpit_json_write_bytes (options); for (l = self->rules; l != NULL; l = g_list_next (l)) { if (router_rule_match (l->data, options) && router_rule_invoke (l->data, self, channel, options, new_payload)) { break; } } } if (new_payload) g_bytes_unref (new_payload); }
/** * cockpit_channel_control: * @self: the channel * @command: the control command * @options: optional control message or NULL * * Send a control message to the other side. * * If @options is not NULL, then it may be modified by this code. * * With @command of "done" will send an EOF to the other side. This * should only be called once. Whether an EOF should be sent or not * depends on the payload type. */ void cockpit_channel_control (CockpitChannel *self, const gchar *command, JsonObject *options) { JsonObject *object; GBytes *message; const gchar *problem; gchar *problem_copy = NULL; g_return_if_fail (COCKPIT_IS_CHANNEL (self)); g_return_if_fail (command != NULL); if (g_str_equal (command, "done")) { g_return_if_fail (self->priv->sent_done == FALSE); self->priv->sent_done = TRUE; } /* If closing save the close options * and let close send the message */ else if (g_str_equal (command, "close")) { if (!self->priv->close_options) { /* Ref for close_options, freed in parent */ self->priv->close_options = json_object_ref (options); } if (!cockpit_json_get_string (options, "problem", NULL, &problem)) problem = NULL; /* Use a problem copy so it out lasts the value in close_options */ problem_copy = g_strdup (problem); cockpit_channel_close (self, problem_copy); goto out; } if (options) object = json_object_ref (options); else object = json_object_new (); json_object_set_string_member (object, "command", command); json_object_set_string_member (object, "channel", self->priv->id); message = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (self->priv->transport, NULL, message); g_bytes_unref (message); out: g_free (problem_copy); }
static void send_login_response (CockpitWebResponse *response, JsonObject *object, GHashTable *headers) { GBytes *content; content = cockpit_json_write_bytes (object); g_hash_table_replace (headers, g_strdup ("Content-Type"), g_strdup ("application/json")); cockpit_web_response_content (response, headers, content, NULL); g_bytes_unref (content); }
static void send_init_command (CockpitTransport *transport) { JsonObject *object; GBytes *bytes; object = json_object_new (); json_object_set_string_member (object, "command", "init"); json_object_set_int_member (object, "version", 1); bytes = cockpit_json_write_bytes (object); cockpit_transport_send (transport, NULL, bytes); g_bytes_unref (bytes); }
void cockpit_fswatch_emit_event (CockpitChannel *channel, GFile *file, GFile *other_file, GFileMonitorEvent event_type) { JsonObject *msg; GBytes *msg_bytes; msg = json_object_new (); json_object_set_string_member (msg, "event", event_type_to_string (event_type)); if (file) { char *p = g_file_get_path (file); char *t = cockpit_get_file_tag (p); json_object_set_string_member (msg, "path", p); json_object_set_string_member (msg, "tag", t); if (event_type == G_FILE_MONITOR_EVENT_CREATED) { GError *error = NULL; GFileInfo *info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error); if (info) { json_object_set_string_member (msg, "type", cockpit_file_type_to_string (g_file_info_get_file_type (info))); g_object_unref (info); } g_clear_error (&error); } g_free (p); g_free (t); } if (other_file) { char *p = g_file_get_path (other_file); json_object_set_string_member (msg, "other", p); g_free (p); } msg_bytes = cockpit_json_write_bytes (msg); json_object_unref (msg); cockpit_channel_send (channel, msg_bytes, TRUE); g_bytes_unref (msg_bytes); }
static void on_login_complete (GObject *object, GAsyncResult *result, gpointer user_data) { CockpitWebResponse *response = user_data; GError *error = NULL; JsonObject *response_data = NULL; GHashTable *headers; GIOStream *io_stream; GBytes *content; io_stream = cockpit_web_response_get_stream (response); headers = cockpit_web_server_new_table (); response_data = cockpit_auth_login_finish (COCKPIT_AUTH (object), result, io_stream, headers, &error); /* Never cache a login response */ cockpit_web_response_set_cache_type (response, COCKPIT_WEB_RESPONSE_NO_CACHE); if (error) { if (response_data) { g_hash_table_insert (headers, g_strdup ("Content-Type"), g_strdup ("application/json")); content = cockpit_json_write_bytes (response_data); cockpit_web_response_headers_full (response, 401, "Authentication required", -1, headers); cockpit_web_response_queue (response, content); cockpit_web_response_complete (response); g_bytes_unref (content); } else { cockpit_web_response_gerror (response, headers, error); } g_error_free (error); } else { send_login_response (response, response_data, headers); } if (response_data) json_object_unref (response_data); g_hash_table_unref (headers); g_object_unref (response); }
static gboolean process_ping (CockpitWebService *self, CockpitSocket *socket, JsonObject *options) { GBytes *payload; /* Respond to a ping without a channel, by saying "pong" */ json_object_set_string_member (options, "command", "pong"); payload = cockpit_json_write_bytes (options); if (web_socket_connection_get_ready_state (socket->connection) == WEB_SOCKET_STATE_OPEN) web_socket_connection_send (socket->connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, payload); g_bytes_unref (payload); return TRUE; }
static void on_socket_open (WebSocketConnection *connection, CockpitChannelSocket *chock) { GBytes *payload; /* * Actually open the channel. We wait until the WebSocket is open * before doing this, so we don't receive messages from the bridge * before the websocket is open. */ payload = cockpit_json_write_bytes (chock->open); cockpit_transport_send (chock->transport, NULL, payload); g_bytes_unref (payload); }
static void on_web_socket_open (WebSocketConnection *connection, CockpitWebService *self) { CockpitSocket *socket; JsonArray *capabilities; GBytes *command; JsonObject *object; JsonObject *info; g_info ("New connection to session from %s", cockpit_creds_get_rhost (self->creds)); socket = cockpit_socket_lookup_by_connection (&self->sockets, connection); g_return_if_fail (socket != NULL); object = json_object_new (); json_object_set_string_member (object, "command", "init"); json_object_set_int_member (object, "version", 1); json_object_set_string_member (object, "channel-seed", socket->id); json_object_set_string_member (object, "host", "localhost"); json_object_set_string_member (object, "csrf-token", cockpit_creds_get_csrf_token (self->creds)); capabilities = json_array_new (); json_array_add_string_element (capabilities, "multi"); json_array_add_string_element (capabilities, "credentials"); json_array_add_string_element (capabilities, "binary"); json_object_set_array_member (object, "capabilities", capabilities); info = json_object_new (); json_object_set_string_member (info, "version", PACKAGE_VERSION); json_object_set_string_member (info, "build", COCKPIT_BUILD_INFO); json_object_set_object_member (object, "system", info); command = cockpit_json_write_bytes (object); json_object_unref (object); web_socket_connection_send (connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, command); g_bytes_unref (command); /* Do we have an authorize password? if so tell the frontend */ if (cockpit_creds_get_password (self->creds)) send_socket_hints (self, "credential", "password"); g_signal_connect (connection, "message", G_CALLBACK (on_web_socket_message), self); }
static GBytes * build_environment (GHashTable *os_release) { static const gchar *prefix = "\n <script>\nvar environment = "; static const gchar *suffix = ";\n </script>"; GByteArray *buffer; GHashTableIter iter; GBytes *bytes; JsonObject *object; const gchar *title; gchar *hostname; gpointer key, value; JsonObject *osr; object = json_object_new (); title = cockpit_conf_string ("WebService", "LoginTitle"); if (title) json_object_set_string_member (object, "title", title); hostname = g_malloc0 (HOST_NAME_MAX + 1); gethostname (hostname, HOST_NAME_MAX); hostname[HOST_NAME_MAX] = '\0'; json_object_set_string_member (object, "hostname", hostname); g_free (hostname); if (os_release) { osr = json_object_new (); g_hash_table_iter_init (&iter, os_release); while (g_hash_table_iter_next (&iter, &key, &value)) json_object_set_string_member (osr, key, value); json_object_set_object_member (object, "os-release", osr); } add_oauth_to_environment (object); bytes = cockpit_json_write_bytes (object); json_object_unref (object); buffer = g_bytes_unref_to_array (bytes); g_byte_array_prepend (buffer, (const guint8 *)prefix, strlen (prefix)); g_byte_array_append (buffer, (const guint8 *)suffix, strlen (suffix)); return g_byte_array_free_to_bytes (buffer); }
static void send_login_response (CockpitWebResponse *response, CockpitCreds *creds, GHashTable *headers) { JsonObject *object; GBytes *content; object = json_object_new (); json_object_set_string_member (object, "user", cockpit_creds_get_user (creds)); content = cockpit_json_write_bytes (object); json_object_unref (object); g_hash_table_replace (headers, g_strdup ("Content-Type"), g_strdup ("application/json")); cockpit_web_response_content (response, headers, content, NULL); g_bytes_unref (content); }
static gboolean process_and_relay_open (CockpitWebService *self, CockpitSocket *socket, const gchar *channel, JsonObject *options) { WebSocketDataType data_type = WEB_SOCKET_DATA_TEXT; GBytes *payload; if (self->closing) { g_debug ("Ignoring open command while web socket is closing"); return TRUE; } if (channel == NULL) { g_warning ("open command is missing the 'channel' field"); return FALSE; } if (cockpit_socket_lookup_by_channel (&self->sockets, channel)) { g_warning ("cannot open a channel %s with the same id as another channel", channel); return FALSE; } if (!cockpit_web_service_parse_binary (options, &data_type)) return FALSE; if (socket) cockpit_socket_add_channel (&self->sockets, socket, channel, data_type); if (!self->sent_done) { payload = cockpit_json_write_bytes (options); cockpit_transport_send (self->transport, NULL, payload); g_bytes_unref (payload); } return TRUE; }
static const gchar * process_transport_init (CockpitWebService *self, CockpitTransport *transport, JsonObject *options) { JsonObject *object; GBytes *payload; gint64 version; if (!cockpit_json_get_int (options, "version", -1, &version)) { g_warning ("invalid version field in init message"); return "protocol-error"; } if (version == 1) { g_debug ("received init message"); self->init_received = TRUE; g_object_set_data_full (G_OBJECT (transport), "init", json_object_ref (options), (GDestroyNotify) json_object_unref); /* Always send an init message down the new transport */ object = cockpit_transport_build_json ("command", "init", NULL); json_object_set_int_member (object, "version", 1); json_object_set_string_member (object, "host", "localhost"); payload = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (transport, NULL, payload); g_bytes_unref (payload); } else { g_message ("unsupported version of cockpit protocol: %" G_GINT64_FORMAT, version); return "not-supported"; } g_signal_emit (self, sig_transport_init, 0); return NULL; }
static void send_init_command (CockpitTransport *transport) { const gchar *checksum; JsonObject *object; GBytes *bytes; object = json_object_new (); json_object_set_string_member (object, "command", "init"); json_object_set_int_member (object, "version", 1); checksum = cockpit_packages_get_checksum (packages); if (checksum) json_object_set_string_member (object, "checksum", checksum); bytes = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (transport, NULL, bytes); g_bytes_unref (bytes); }
/** * cockpit_channel_done: * @self: the channel * * Send an EOF to the other side. This should only be called once. * Whether an EOF should be sent or not depends on the payload type. */ void cockpit_channel_done (CockpitChannel *self) { JsonObject *object; GBytes *message; g_return_if_fail (COCKPIT_IS_CHANNEL (self)); g_return_if_fail (self->priv->sent_done == FALSE); self->priv->sent_done = TRUE; object = json_object_new (); json_object_set_string_member (object, "command", "done"); json_object_set_string_member (object, "channel", self->priv->id); message = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (self->priv->transport, NULL, message); g_bytes_unref (message); }
static void cockpit_channel_real_close (CockpitChannel *self, const gchar *problem) { JsonObject *object; GBytes *message; if (self->priv->sent_close) return; self->priv->sent_close = TRUE; if (!self->priv->transport_closed) { flush_buffer (self); if (self->priv->close_options) { object = self->priv->close_options; self->priv->close_options = NULL; } else { object = json_object_new (); } json_object_set_string_member (object, "command", "close"); json_object_set_string_member (object, "channel", self->priv->id); if (problem) json_object_set_string_member (object, "problem", problem); message = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (self->priv->transport, NULL, message); g_bytes_unref (message); } g_signal_emit (self, cockpit_channel_sig_closed, 0, problem); }
static gboolean process_ping (CockpitChannel *self, JsonObject *ping) { GBytes *payload; if (self->priv->throttled) { g_debug ("%s: received ping while throttled", self->priv->id); g_queue_push_tail (self->priv->throttled, json_object_ref (ping)); return FALSE; } else { g_debug ("%s: replying to ping with pong", self->priv->id); json_object_set_string_member (ping, "command", "pong"); payload = cockpit_json_write_bytes (ping); cockpit_transport_send (self->priv->transport, NULL, payload); g_bytes_unref (payload); return TRUE; } }
static void send_close_channel (CockpitPortal *self, const gchar *channel_id, const gchar *problem) { JsonObject *object; GBytes *bytes; g_debug ("sending close for portal channel: %s: %s", channel_id, problem); object = json_object_new (); json_object_set_string_member (object, "command", "close"); json_object_set_string_member (object, "channel", channel_id); json_object_set_string_member (object, "problem", problem); bytes = cockpit_json_write_bytes (object); json_object_unref (object); if (self->transport) cockpit_transport_send (self->transport, NULL, bytes); g_bytes_unref (bytes); }
static void cockpit_channel_real_close (CockpitChannel *self, const gchar *problem) { const gchar *reason = problem; JsonObject *object; GBytes *message; if (self->priv->closed) return; self->priv->closed = TRUE; if (reason == NULL) reason = ""; if (self->priv->close_options) { object = self->priv->close_options; self->priv->close_options = NULL; } else { object = json_object_new (); } json_object_set_string_member (object, "command", "close"); json_object_set_string_member (object, "channel", self->priv->id); json_object_set_string_member (object, "reason", reason); message = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (self->priv->transport, 0, message); g_bytes_unref (message); g_signal_emit (self, cockpit_channel_sig_closed, 0, problem); }
static GBytes * substitute_environment (const gchar *variable, gpointer user_data) { GHashTable *os_release = user_data; GHashTableIter iter; GBytes *ret = NULL; JsonObject *object; gchar *hostname; gpointer key, value; JsonObject *osr; if (g_str_equal (variable, "environment")) { object = json_object_new (); hostname = g_malloc0 (HOST_NAME_MAX + 1); gethostname (hostname, HOST_NAME_MAX); hostname[HOST_NAME_MAX] = '\0'; json_object_set_string_member (object, "hostname", hostname); g_free (hostname); if (os_release) { osr = json_object_new (); g_hash_table_iter_init (&iter, os_release); while (g_hash_table_iter_next (&iter, &key, &value)) json_object_set_string_member (osr, key, value); json_object_set_object_member (object, "os-release", osr); } ret = cockpit_json_write_bytes (object); json_object_unref (object); } return ret; }
static void send_init_command (CockpitTransport *transport, gboolean interactive) { const gchar *checksum; JsonObject *object; GBytes *bytes; object = json_object_new (); json_object_set_string_member (object, "command", "init"); json_object_set_int_member (object, "version", 1); /* * When in interactive mode pretend we received an init * message, and don't print one out. */ if (interactive) { json_object_set_string_member (object, "host", "localhost"); } else { checksum = cockpit_packages_get_checksum (packages); if (checksum) json_object_set_string_member (object, "checksum", checksum); } bytes = cockpit_json_write_bytes (object); json_object_unref (object); if (interactive) cockpit_transport_emit_recv (transport, NULL, bytes); else cockpit_transport_send (transport, NULL, bytes); g_bytes_unref (bytes); }
static void on_files_listed (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; JsonObject *options; GList *files; files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source_object), res, &error); if (error) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { CockpitFslist *self = COCKPIT_FSLIST (user_data); g_message ("%s: couldn't process files %s", COCKPIT_FSLIST(user_data)->path, error->message); options = cockpit_channel_close_options (COCKPIT_CHANNEL (self)); json_object_set_string_member (options, "message", error->message); cockpit_channel_close (COCKPIT_CHANNEL (self), "internal-error"); } g_clear_error (&error); return; } CockpitFslist *self = COCKPIT_FSLIST (user_data); if (files == NULL) { JsonObject *msg; GBytes *msg_bytes; msg = json_object_new (); json_object_set_string_member (msg, "event", "present-done"); msg_bytes = cockpit_json_write_bytes (msg); json_object_unref (msg); cockpit_channel_send (COCKPIT_CHANNEL(self), msg_bytes, FALSE); g_bytes_unref (msg_bytes); g_clear_object (&self->cancellable); g_object_unref (source_object); if (self->monitor == NULL) { cockpit_channel_done (COCKPIT_CHANNEL (self)); cockpit_channel_close (COCKPIT_CHANNEL (self), NULL); } return; } for (GList *l = files; l; l = l->next) { GFileInfo *info = G_FILE_INFO (l->data); JsonObject *msg; GBytes *msg_bytes; msg = json_object_new (); json_object_set_string_member (msg, "event", "present"); json_object_set_string_member (msg, "path", g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_NAME)); json_object_set_string_member (msg, "type", cockpit_file_type_to_string (g_file_info_get_file_type (info))); msg_bytes = cockpit_json_write_bytes (msg); json_object_unref (msg); cockpit_channel_send (COCKPIT_CHANNEL(self), msg_bytes, FALSE); g_bytes_unref (msg_bytes); } g_list_free_full (files, g_object_unref); g_file_enumerator_next_files_async (G_FILE_ENUMERATOR (source_object), 10, G_PRIORITY_DEFAULT, self->cancellable, on_files_listed, self); }
static gboolean relay_headers (CockpitHttpStream *self, CockpitChannel *channel, GByteArray *buffer) { GHashTable *headers = NULL; gchar *version = NULL; gchar *reason = NULL; JsonObject *object; const gchar *data; JsonObject *heads; GHashTableIter iter; GBytes *message; gpointer key; gpointer value; guint status; gsize length; gssize offset; gssize offset2; data = (const gchar *)buffer->data; length = buffer->len; offset = web_socket_util_parse_status_line (data, length, &version, &status, &reason); if (offset == 0) return FALSE; /* want more data */ if (offset < 0) { cockpit_channel_fail (channel, "protocol-error", "%s: received response with bad HTTP status line", self->name); goto out; } offset2 = web_socket_util_parse_headers (data + offset, length - offset, &headers); if (offset2 == 0) return FALSE; /* want more data */ if (offset2 < 0) { cockpit_channel_fail (channel, "protocol-error", "%s: received response with bad HTTP headers", self->name); goto out; } g_debug ("%s: response: %u %s", self->name, status, reason); g_hash_table_iter_init (&iter, headers); while (g_hash_table_iter_next (&iter, &key, &value)) g_debug ("%s: header: %s %s", self->name, (gchar *)key, (gchar *)value); if (!parse_transfer_encoding (self, channel, headers) || !parse_content_length (self, channel, status, headers) || !parse_keep_alive (self, channel, version, headers)) goto out; cockpit_pipe_skip (buffer, offset + offset2); if (!self->binary) { g_hash_table_remove (headers, "Content-Length"); g_hash_table_remove (headers, "Range"); } g_hash_table_remove (headers, "Connection"); g_hash_table_remove (headers, "Transfer-Encoding"); /* Now serialize all the rest of this into JSON */ object = json_object_new (); json_object_set_int_member (object, "status", status); json_object_set_string_member (object, "reason", reason); heads = json_object_new(); g_hash_table_iter_init (&iter, headers); while (g_hash_table_iter_next (&iter, &key, &value)) json_object_set_string_member (heads, key, value); json_object_set_object_member (object, "headers", heads); if (self->headers_inline) { message = cockpit_json_write_bytes (object); cockpit_channel_send (channel, message, TRUE); g_bytes_unref (message); } else { cockpit_channel_control (channel, "response", object); } json_object_unref (object); out: if (headers) g_hash_table_unref (headers); g_free (version); g_free (reason); return TRUE; }
static GBytes * build_environment (CockpitWebService *service, JsonObject *modules) { const gchar *user; CockpitCreds *creds; JsonObject *env; JsonObject *localhost; JsonObject *languages; JsonObject *language; struct passwd *pwd; gchar *hostname; GBytes *bytes; guint n; const struct { const gchar *name; const gchar *code; } supported_languages[] = { { NC_("display-language", "English"), "" }, { NC_("display-language", "Danish"), "da" }, { NC_("display-language", "German"), "de" }, }; env = json_object_new (); if (service) { creds = cockpit_web_service_get_creds (service); user = cockpit_creds_get_user (creds); json_object_set_string_member (env, "user", user); pwd = cockpit_getpwnam_a (user, NULL); if (pwd) { json_object_set_string_member (env, "name", pwd->pw_gecos); free (pwd); } } localhost = json_object_new (); /* This awkwardly takes the localhost reference */ json_object_set_object_member (env, "localhost", localhost); hostname = g_malloc0 (HOST_NAME_MAX + 1); gethostname (hostname, HOST_NAME_MAX); hostname[HOST_NAME_MAX] = '\0'; json_object_set_string_member (env, "hostname", hostname); /* Only include version info if logged in */ if (service) { json_object_set_string_member (localhost, "version", PACKAGE_VERSION); json_object_set_string_member (localhost, "build_info", COCKPIT_BUILD_INFO); } languages = json_object_new (); /* This awkwardly takes the languages reference */ json_object_set_object_member (localhost, "languages", languages); for (n = 0; n < G_N_ELEMENTS (supported_languages); n++) { language = json_object_new (); json_object_set_object_member (languages, supported_languages[n].code, language); json_object_set_string_member (language, "name", supported_languages[n].name); } if (modules) json_object_set_object_member (localhost, "modules", json_object_ref (modules)); bytes = cockpit_json_write_bytes (env); json_object_unref (env); return bytes; }