static gboolean process_logout (CockpitWebService *self, JsonObject *options) { gboolean disconnect; if (!cockpit_json_get_bool (options, "disconnect", FALSE, &disconnect)) { g_warning ("received 'logout' command with invalid 'disconnect' field"); return FALSE; } /* Makes the credentials unusable */ cockpit_creds_poison (self->creds); /* Destroys our web service, disconnects everything */ if (disconnect) { g_info ("Logging out session from %s", cockpit_creds_get_rhost (self->creds)); g_object_run_dispose (G_OBJECT (self)); } else { g_info ("Deauthorizing session from %s", cockpit_creds_get_rhost (self->creds)); } send_socket_hints (self, "credential", "none"); return TRUE; }
/* * For backwards compatibility we need to normalize some host params * so they can be matched against. * * Some sessions shouldn't be shared by multiple channels, such as those that * explicitly specify a host-key or specific user. This changed over time * so modify things to make it a simple match. * * If the given user is the current user, remove it. Preserves the current * behavior. * */ static void cockpit_router_normalize_host_params (JsonObject *options) { const gchar *sharable = NULL; const gchar *user = NULL; gboolean needs_private = FALSE; if (!cockpit_json_get_string (options, "session", NULL, &sharable)) sharable = NULL; if (!cockpit_json_get_string (options, "user", NULL, &user)) user = NULL; if (!sharable) { /* Fallback to older ways of indicating this */ if (user || json_object_has_member (options, "host-key")) needs_private = TRUE; if (json_object_has_member (options, "temp-session")) { if (needs_private && !cockpit_json_get_bool (options, "temp-session", TRUE, &needs_private)) needs_private = TRUE; json_object_remove_member (options, "temp-session"); } } if (g_strcmp0 (user, g_get_user_name ()) == 0) json_object_remove_member (options, "user"); if (needs_private) json_object_set_string_member (options, "session", "private"); }
/** * cockpit_channel_get_bool_option: * @self: a channel * @name: the option name * * Called by implementations to get an int value from the * channel's options. * * Returns: TRUE of option set, FALSE if missing or set to false */ gboolean cockpit_channel_get_bool_option (CockpitChannel *self, const gchar *name) { gboolean value; if (!cockpit_json_get_bool (self->priv->open_options, name, FALSE, &value)) value = FALSE; return value; }
static gboolean superuser_filter (CockpitPortal *self, const gchar *command, const gchar *channel, JsonObject *options, GBytes *payload) { CockpitPortalFlags flags = COCKPIT_PORTAL_NORMAL; gboolean privileged = FALSE; const gchar *superuser; if (g_str_equal (command, "logout")) { g_debug ("got logout at super proxy"); transition_none (self); return FALSE; } if (g_str_equal (command, "open") && channel) { if (!cockpit_json_get_bool (options, "superuser", FALSE, &privileged)) { if (!cockpit_json_get_string (options, "superuser", NULL, &superuser)) { g_warning ("invalid value for \"superuser\" channel open option"); send_close_channel (self, channel, "protocol-error"); return TRUE; } else if (g_strcmp0 (superuser, "try") == 0) { privileged = TRUE; flags = COCKPIT_PORTAL_FALLBACK; } else if (g_strcmp0 (superuser, "require") == 0) { privileged = TRUE; } else if (superuser) { g_warning ("invalid value for \"superuser\" channel open option: %s", superuser); send_close_channel (self, channel, "protocol-error"); return TRUE; } } if (!privileged) return FALSE; g_debug ("superuser channel open: %s", channel); cockpit_portal_add_channel (self, channel, flags); return TRUE; } return FALSE; }
static void cockpit_channel_real_prepare (CockpitChannel *channel) { CockpitChannel *self = COCKPIT_CHANNEL (channel); JsonObject *options; const gchar *binary; options = cockpit_channel_get_options (self); if (!cockpit_channel_ensure_capable (self, options)) return; if (G_OBJECT_TYPE (channel) == COCKPIT_TYPE_CHANNEL) { cockpit_channel_close (channel, "not-supported"); return; } if (!cockpit_json_get_string (options, "binary", NULL, &binary)) { cockpit_channel_fail (self, "protocol-error", "channel has invalid \"binary\" option"); } else if (binary != NULL) { self->priv->binary_ok = TRUE; if (!g_str_equal (binary, "raw")) { cockpit_channel_fail (self, "protocol-error", "channel has invalid \"binary\" option: %s", binary); } } /* * The default here, can change from FALSE to TRUE over time once we assume that all * cockpit-ws participants have been upgraded sufficiently. The default when we're * on the channel creation side is to handle flow control. */ if (!cockpit_json_get_bool (options, "flow-control", FALSE, &self->priv->flow_control)) { cockpit_channel_fail (self, "protocol-error", "channel has invalid \"flow-control\" option"); } }
static void cockpit_fslist_prepare (CockpitChannel *channel) { CockpitFslist *self = COCKPIT_FSLIST (channel); const gchar *problem = "protocol-error"; JsonObject *options; GError *error = NULL; GFile *file = NULL; gboolean watch; COCKPIT_CHANNEL_CLASS (cockpit_fslist_parent_class)->prepare (channel); options = cockpit_channel_get_options (channel); if (!cockpit_json_get_string (options, "path", NULL, &self->path)) { g_warning ("invalid \"path\" option for fslist1 channel"); goto out; } if (self->path == NULL || *(self->path) == 0) { g_warning ("missing \"path\" option for fslist1 channel"); goto out; } if (!cockpit_json_get_bool (options, "watch", TRUE, &watch)) { g_warning ("invalid \"watch\" option for fslist1 channel"); goto out; } self->cancellable = g_cancellable_new (); file = g_file_new_for_path (self->path); g_file_enumerate_children_async (file, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, self->cancellable, on_enumerator_ready, self); if (watch) { self->monitor = g_file_monitor_directory (file, 0, NULL, &error); if (self->monitor == NULL) { g_message ("%s: couldn't monitor directory: %s", self->path, error->message); options = cockpit_channel_close_options (channel); json_object_set_string_member (options, "message", error->message); problem = "internal-error"; goto out; } self->sig_changed = g_signal_connect (self->monitor, "changed", G_CALLBACK (on_changed), self); } cockpit_channel_ready (channel); problem = NULL; out: g_clear_error (&error); if (file) g_object_unref (file); if (problem) cockpit_channel_close (channel, problem); }
CockpitStreamOptions * cockpit_channel_parse_stream (CockpitChannel *self, gboolean local_address) { const gchar *problem = "protocol-error"; GTlsCertificate *cert = NULL; GTlsDatabase *database = NULL; CockpitStreamOptions *ret; gboolean use_tls = FALSE; GError *error = NULL; GString *pem = NULL; JsonObject *options; JsonNode *node; /* No validation for local servers by default */ gboolean validate = !local_address; node = json_object_get_member (self->priv->open_options, "tls"); if (node && !JSON_NODE_HOLDS_OBJECT (node)) { g_warning ("invalid \"tls\" option for channel"); goto out; } else if (node) { options = json_node_get_object (node); use_tls = TRUE; /* * The only function in GLib to parse private keys takes * them in PEM concatenated form. This is a limitation of GLib, * rather than concatenated form being a decent standard for * certificates and keys. So build a combined PEM as expected by * GLib here. */ pem = g_string_sized_new (8192); problem = parse_cert_option_as_pem (options, "certificate", pem); if (problem) goto out; if (pem->len) { problem = parse_cert_option_as_pem (options, "key", pem); if (problem) goto out; cert = g_tls_certificate_new_from_pem (pem->str, pem->len, &error); if (error != NULL) { g_warning ("invalid \"certificate\" or \"key\" content: %s", error->message); g_error_free (error); problem = "internal-error"; goto out; } } problem = parse_cert_option_as_database (options, "authority", &database); if (problem) goto out; if (!cockpit_json_get_bool (options, "validate", validate, &validate)) { g_warning ("invalid \"validate\" option"); problem = "protocol-error"; goto out; } } problem = NULL; out: if (problem) { cockpit_channel_close (self, problem); ret = NULL; } else { ret = g_new0 (CockpitStreamOptions, 1); ret->refs = 1; ret->tls_client = use_tls; ret->tls_cert = cert; cert = NULL; if (database) { ret->tls_database = database; ret->tls_client_flags = G_TLS_CERTIFICATE_VALIDATE_ALL; if (!validate) ret->tls_client_flags &= ~(G_TLS_CERTIFICATE_INSECURE | G_TLS_CERTIFICATE_BAD_IDENTITY); database = NULL; } else { if (validate) ret->tls_client_flags = G_TLS_CERTIFICATE_VALIDATE_ALL; else ret->tls_client_flags = G_TLS_CERTIFICATE_GENERIC_ERROR; } } if (pem) g_string_free (pem, TRUE); if (cert) g_object_unref (cert); if (database) g_object_unref (database); return ret; }