CockpitStreamOptions * cockpit_channel_parse_stream (CockpitChannel *self) { 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; 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; } 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 & ~(G_TLS_CERTIFICATE_INSECURE | G_TLS_CERTIFICATE_BAD_IDENTITY); database = NULL; } else { /* No validation for local servers by default */ 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; }
static gboolean parse_stream_options (CockpitChannel *self, CockpitConnectable *connectable) { gboolean ret = FALSE; GTlsCertificate *cert = NULL; GTlsDatabase *database = NULL; gboolean use_tls = FALSE; GError *error = NULL; GString *pem = NULL; JsonObject *options; JsonNode *node; /* No validation for local servers by default */ gboolean validate = !connectable->local; node = json_object_get_member (self->priv->open_options, "tls"); if (node && !JSON_NODE_HOLDS_OBJECT (node)) { cockpit_channel_fail (self, "protocol-error", "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); if (!parse_cert_option_as_pem (self, options, "certificate", pem)) goto out; if (pem->len) { if (!parse_cert_option_as_pem (self, options, "key", pem)) goto out; cert = g_tls_certificate_new_from_pem (pem->str, pem->len, &error); if (error != NULL) { cockpit_channel_fail (self, "internal-error", "invalid \"certificate\" or \"key\" content: %s", error->message); g_error_free (error); goto out; } } if (!parse_cert_option_as_database (self, options, "authority", &database)) goto out; if (!cockpit_json_get_bool (options, "validate", validate, &validate)) { cockpit_channel_fail (self, "protocol-error", "invalid \"validate\" option"); goto out; } } ret = TRUE; out: if (ret) { connectable->tls = use_tls; connectable->tls_cert = cert; cert = NULL; if (database) { connectable->tls_database = database; connectable->tls_flags = G_TLS_CERTIFICATE_VALIDATE_ALL; if (!validate) connectable->tls_flags &= ~(G_TLS_CERTIFICATE_INSECURE | G_TLS_CERTIFICATE_BAD_IDENTITY); database = NULL; } else { if (validate) connectable->tls_flags = G_TLS_CERTIFICATE_VALIDATE_ALL; else connectable->tls_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; }