static GBytes * check_utf8_and_force_if_necessary (GBytes *input) { const gchar *data; const gchar *end; gsize length; GString *string; data = g_bytes_get_data (input, &length); if (g_utf8_validate (data, length, &end)) return g_bytes_ref (input); string = g_string_sized_new (length + 16); do { /* Valid part of the string */ g_string_append_len (string, data, end - data); /* Replacement character */ g_string_append (string, "\xef\xbf\xbd"); length -= (end - data) + 1; data = end + 1; } while (!g_utf8_validate (data, length, &end)); if (length) g_string_append_len (string, data, length); return g_string_free_to_bytes (string); }
gboolean ostree_bootconfig_parser_write (OstreeBootconfigParser *self, GFile *output, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GHashTableIter hashiter; gpointer hashkey, hashvalue; GString *buf = g_string_new (""); gs_unref_bytes GBytes *bytes = NULL; guint i; gs_unref_hashtable GHashTable *written_overrides = NULL; written_overrides = g_hash_table_new (g_str_hash, g_str_equal); for (i = 0; i < self->lines->len; i++) { GVariant *linedata = self->lines->pdata[i]; const char *key; const char *value; const char *line; g_variant_get (linedata, "(&s&s)", &key, &line); value = g_hash_table_lookup (self->options, key); if (value == NULL) { g_string_append (buf, line); g_string_append_c (buf, '\n'); } else { write_key (self, buf, key, value); g_hash_table_insert (written_overrides, (gpointer)key, (gpointer)key); } } g_hash_table_iter_init (&hashiter, self->options); while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) { if (g_hash_table_lookup (written_overrides, hashkey)) continue; write_key (self, buf, hashkey, hashvalue); } bytes = g_string_free_to_bytes (buf); buf = NULL; if (!ot_gfile_replace_contents_fsync (output, bytes, cancellable, error)) goto out; ret = TRUE; out: if (buf) g_string_free (buf, TRUE); return ret; }
static GBytes * finish_headers (CockpitWebResponse *self, GString *string, gssize length, gboolean success, guint seen) { gint i; static const struct { const gchar *extension; const gchar *content_type; } content_types[] = { { ".css", "text/css" }, { ".gif", "image/gif" }, { ".eot", "application/vnd.ms-fontobject" }, { ".html", "text/html" }, { ".ico", "image/vnd.microsoft.icon" }, { ".jpg", "image/jpg" }, { ".js", "application/javascript" }, { ".otf", "font/opentype" }, { ".png", "image/png" }, { ".svg", "image/svg+xml" }, { ".ttf", "application/octet-stream" }, /* unassigned */ { ".woff", "application/font-woff" }, { ".xml", "text/xml" }, }; /* Automatically figure out content type */ if ((seen & HEADER_CONTENT_TYPE) == 0 && self->path != NULL && success) { for (i = 0; i < G_N_ELEMENTS (content_types); i++) { if (g_str_has_suffix (self->path, content_types[i].extension)) { g_string_append_printf (string, "Content-Type: %s\r\n", content_types[i].content_type); break; } } } if (length >= 0) { self->chunked = FALSE; g_string_append_printf (string, "Content-Length: %" G_GSSIZE_FORMAT "\r\n", length); } else { self->chunked = TRUE; g_string_append_printf (string, "Transfer-Encoding: chunked\r\n"); } if (!self->keep_alive) g_string_append (string, "Connection: close\r\n"); g_string_append (string, "\r\n"); return g_string_free_to_bytes (string); }
static GBytes * finish_headers (CockpitWebResponse *self, GString *string, gssize length, gint status, guint seen) { const gchar *content_type; /* Automatically figure out content type */ if ((seen & HEADER_CONTENT_TYPE) == 0 && self->full_path != NULL && status >= 200 && status <= 299) { content_type = cockpit_web_response_content_type (self->full_path); if (content_type) g_string_append_printf (string, "Content-Type: %s\r\n", content_type); } if (status != 304) { if (length >= 0 && !self->filters) g_string_append_printf (string, "Content-Length: %" G_GSSIZE_FORMAT "\r\n", length); if (length < 0 || seen & HEADER_CONTENT_ENCODING || self->filters) { self->chunked = TRUE; g_string_append_printf (string, "Transfer-Encoding: chunked\r\n"); } else { self->chunked = FALSE; } } if ((seen & HEADER_CACHE_CONTROL) == 0 && status >= 200 && status <= 299) { if (self->cache_type == COCKPIT_WEB_RESPONSE_CACHE_FOREVER) g_string_append (string, "Cache-Control: max-age=31556926, public\r\n"); else if (self->cache_type == COCKPIT_WEB_RESPONSE_NO_CACHE) g_string_append (string, "Cache-Control: no-cache, no-store\r\n"); else if (self->cache_type == COCKPIT_WEB_RESPONSE_CACHE_PRIVATE) g_string_append (string, "Cache-Control: max-age=86400, private\r\n"); } if ((seen & HEADER_VARY) == 0 && status >= 200 && status <= 299 && self->cache_type == COCKPIT_WEB_RESPONSE_CACHE_PRIVATE) { g_string_append (string, "Vary: Cookie\r\n"); } if (!self->keep_alive) g_string_append (string, "Connection: close\r\n"); g_string_append (string, "\r\n"); return g_string_free_to_bytes (string); }
static GBytes * _encode_wanted_services (const char *type, GSList *list) { GString *encoded = g_string_new(type); g_string_append_c (encoded, '\0'); g_string_append_c (encoded, '['); for (GSList *l=list; l ;l=l->next) { if (!l->data) continue; if (l != list) g_string_append_c (encoded, ','); service_info_encode_json (encoded, l->data, FALSE); } g_string_append_c (encoded, ']'); return g_string_free_to_bytes(encoded); }
static void cockpit_channel_inject_perform (CockpitChannelInject *inject, CockpitWebResponse *response, CockpitTransport *transport) { static const gchar *marker = "<head>"; CockpitWebFilter *filter; CockpitCreds *creds; const gchar *application; const gchar *checksum; const gchar *host; GString *str; GBytes *base; str = g_string_new (""); if (!inject->service) return; creds = cockpit_web_service_get_creds (inject->service); application = cockpit_creds_get_application (creds); checksum = cockpit_web_service_get_checksum (inject->service, transport); if (checksum) { g_string_printf (str, "\n <base href=\"/%s/$%s%s\">", application, checksum, inject->base_path); } else { host = cockpit_web_service_get_host (inject->service, transport); g_string_printf (str, "\n <base href=\"/%s/@%s%s\">", application, host, inject->base_path); } base = g_string_free_to_bytes (str); filter = cockpit_web_inject_new (marker, base, 1); g_bytes_unref (base); cockpit_web_response_add_filter (response, filter); g_object_unref (filter); }
void set_body_gstr(GString *gstr) { return set_body_bytes (g_string_free_to_bytes (gstr)); }
static void send_http_request (CockpitHttpStream *self) { CockpitChannel *channel = COCKPIT_CHANNEL (self); JsonObject *options; gboolean had_host; gboolean had_encoding; const gchar *method; const gchar *path; GString *string = NULL; JsonNode *node; JsonObject *headers; const gchar *header; const gchar *value; GList *request = NULL; GList *names = NULL; GBytes *bytes; GList *l; gsize total; options = cockpit_channel_get_options (channel); /* * The checks we do here for token validity are just enough to be able * to format an HTTP response, without leaking across lines etc. */ if (!cockpit_json_get_string (options, "path", NULL, &path)) { cockpit_channel_fail (channel, "protocol-error", "%s: bad \"path\" field in HTTP stream request", self->name); goto out; } else if (path == NULL) { cockpit_channel_fail (channel, "protocol-error", "%s: missing \"path\" field in HTTP stream request", self->name); goto out; } else if (!cockpit_web_response_is_simple_token (path)) { cockpit_channel_fail (channel, "protocol-error", "%s: invalid \"path\" field in HTTP stream request", self->name); goto out; } if (!cockpit_json_get_string (options, "method", NULL, &method)) { cockpit_channel_fail (channel, "protocol-error", "%s: bad \"method\" field in HTTP stream request", self->name); goto out; } else if (method == NULL) { cockpit_channel_fail (channel, "protocol-error", "%s: missing \"method\" field in HTTP stream request", self->name); goto out; } else if (!cockpit_web_response_is_simple_token (method)) { cockpit_channel_fail (channel, "protocol-error", "%s: invalid \"method\" field in HTTP stream request", self->name); goto out; } g_debug ("%s: sending %s request", self->name, method); string = g_string_sized_new (128); g_string_printf (string, "%s %s HTTP/1.1\r\n", method, path); had_encoding = had_host = FALSE; node = json_object_get_member (options, "headers"); if (node) { if (!JSON_NODE_HOLDS_OBJECT (node)) { cockpit_channel_fail (channel, "protocol-error", "%s: invalid \"headers\" field in HTTP stream request", self->name); goto out; } headers = json_node_get_object (node); names = json_object_get_members (headers); for (l = names; l != NULL; l = g_list_next (l)) { header = l->data; if (!cockpit_web_response_is_simple_token (header)) { cockpit_channel_fail (channel, "protocol-error", "%s: invalid header in HTTP stream request: %s", self->name, header); goto out; } node = json_object_get_member (headers, header); if (!node || !JSON_NODE_HOLDS_VALUE (node) || json_node_get_value_type (node) != G_TYPE_STRING) { cockpit_channel_fail (channel, "protocol-error", "%s: invalid header value in HTTP stream request: %s", self->name, header); goto out; } value = json_node_get_string (node); if (disallowed_header (header, value, self->binary)) { cockpit_channel_fail (channel, "protocol-error", "%s: disallowed header in HTTP stream request: %s", self->name, header); goto out; } if (!cockpit_web_response_is_header_value (value)) { cockpit_channel_fail (channel, "protocol-error", "%s: invalid header value in HTTP stream request: %s", self->name, header); goto out; } g_string_append_printf (string, "%s: %s\r\n", (gchar *)l->data, value); g_debug ("%s: sending header: %s %s", self->name, (gchar *)l->data, value); if (g_ascii_strcasecmp (l->data, "Host") == 0) had_host = TRUE; if (g_ascii_strcasecmp (l->data, "Accept-Encoding") == 0) had_encoding = TRUE; } } if (!had_host) { g_string_append (string, "Host: "); g_string_append_uri_escaped (string, self->client->connectable->name, "[]!%$&()*+,-.:;=\\_~", FALSE); g_string_append (string, "\r\n"); } if (!had_encoding) g_string_append (string, "Accept-Encoding: identity\r\n"); if (!self->binary) g_string_append (string, "Accept-Charset: UTF-8\r\n"); request = g_list_reverse (self->request); self->request = NULL; /* Calculate how much data we have to send */ total = 0; for (l = request; l != NULL; l = g_list_next (l)) total += g_bytes_get_size (l->data); if (request || g_ascii_strcasecmp (method, "POST") == 0) g_string_append_printf (string, "Content-Length: %" G_GSIZE_FORMAT "\r\n", total); g_string_append (string, "\r\n"); bytes = g_string_free_to_bytes (string); string = NULL; cockpit_stream_write (self->stream, bytes); g_bytes_unref (bytes); /* Now send all the data */ for (l = request; l != NULL; l = g_list_next (l)) cockpit_stream_write (self->stream, l->data); out: g_list_free (names); g_list_free_full (request, (GDestroyNotify)g_bytes_unref); if (string) g_string_free (string, TRUE); }
static void setup_commit_passwd1 (GVariant *parameters, GDBusMethodInvocation *invocation) { const gchar *mechanism; GVariant *transferred = NULL; const gchar **lines; GHashTable *users = NULL; GHashTable *groups = NULL; GString *chpasswd = NULL; GString *newusers = NULL; CommitAdmin1 *context; CockpitPipe *pipe; gsize length, i, j; gchar **parts; GBytes *bytes; GVariant *pwdata = NULL; GVariant *grdata = NULL; GHashTable *usermod; gchar **memlist; GString *string; gboolean user_exists; /* We are getting crypted passwords so we need to use * --crypt-method=NONE with newusers and chpasswd so that the string * is installed unchanged. Unfortunately, newusers might or might * not support the --crypt-method option, depending on whether it * was compiled with or without PAM. When the option is missing, we * fix up the password afterwards via chpasswd. * * However, newusers needs some valid password to create new users. * Thus, we need a good random string that passes all password * quality criteria, and we just use the crpyted password for that. */ const gchar *argv[] = { cockpit_bridge_path_newusers, "--crypt-method=NONE", NULL }; if (!cockpit_bridge_have_newusers_crypt_method) argv[1] = NULL; g_variant_get (parameters, "(&sv)", &mechanism, &transferred); if (!g_str_equal (mechanism, "passwd1")) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "Unsupported setup mechanism: %s", mechanism); goto out; } if (!g_variant_is_of_type (transferred, G_VARIANT_TYPE ("(asas)"))) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Bad data passed for passwd1 mechanism"); goto out; } users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); if (!fgetpwent_callback (add_name_to_hashtable, users) || !fgetgrent_callback (add_group_to_hashtable, groups)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, _("Couldn't list local users")); goto out; } g_debug ("starting setup synchronization"); g_variant_get (transferred, "(@as@as)", &pwdata, &grdata); chpasswd = g_string_new (""); newusers = g_string_new (""); usermod = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, string_free); lines = g_variant_get_strv (pwdata, &length); for (i = 0; i < length; i++) { parts = g_strsplit(lines[i], ":", 3); user_exists = (g_hash_table_lookup (users, parts[0]) != NULL); if (!user_exists) { g_string_append (newusers, lines[i]); g_string_append_c (newusers, '\n'); } if (user_exists || !cockpit_bridge_have_newusers_crypt_method) { g_string_append_printf (chpasswd, "%s:%s\n", parts[0], parts[1]); } g_strfreev (parts); } g_free (lines); lines = g_variant_get_strv (grdata, &length); for (i = 0; i < length; i++) { parts = g_strsplit(lines[i], ":", 4); if (g_hash_table_lookup (groups, parts[0])) { memlist = g_strsplit (parts[3], ",", -1); for (j = 0; memlist[j] != NULL; j++) { string = g_hash_table_lookup (usermod, memlist[j]); if (!string) { string = g_string_new (""); g_hash_table_insert (usermod, g_strdup (memlist[j]), string); } if (string->len > 0) g_string_append_c (string, ','); g_string_append (string, parts[0]); } g_strfreev (memlist); } g_strfreev (parts); } g_free (lines); context = g_new0 (CommitAdmin1, 1); context->invocation = g_object_ref (invocation); context->chpasswd = g_string_free_to_bytes (chpasswd); context->usermod = usermod; g_debug ("batch creating new users"); bytes = g_string_free_to_bytes (newusers); pipe = cockpit_pipe_spawn (argv, NULL, NULL, COCKPIT_PIPE_FLAGS_NONE); g_signal_connect (pipe, "close", G_CALLBACK (on_newusers_close), context); cockpit_pipe_write (pipe, bytes); cockpit_pipe_close (pipe, NULL); g_bytes_unref (bytes); out: if (users) g_hash_table_unref (users); if (groups) g_hash_table_unref (groups); if (pwdata) g_variant_unref (pwdata); if (grdata) g_variant_unref (grdata); g_variant_unref (transferred); }