static void cockpit_pipe_transport_send (CockpitTransport *transport, guint channel, GBytes *payload) { CockpitPipeTransport *self = COCKPIT_PIPE_TRANSPORT (transport); GBytes *prefix; gchar *prefix_str; gsize prefix_len; guint32 size; prefix_str = g_strdup_printf ("xxxx%u\n", channel); prefix_len = strlen (prefix_str); /* See doc/protocol.md */ size = GUINT32_TO_BE (g_bytes_get_size (payload) + prefix_len - 4); memcpy (prefix_str, &size, 4); prefix = g_bytes_new_take (prefix_str, prefix_len); cockpit_pipe_write (self->pipe, prefix); cockpit_pipe_write (self->pipe, payload); g_bytes_unref (prefix); g_debug ("%s: queued %d byte payload", self->name, (int)g_bytes_get_size (payload)); }
static void cockpit_pipe_transport_send (CockpitTransport *transport, const gchar *channel_id, GBytes *payload) { CockpitPipeTransport *self = COCKPIT_PIPE_TRANSPORT (transport); GBytes *prefix; gchar *prefix_str; gsize payload_len; gsize channel_len; if (self->closed) { g_debug ("dropping message on closed transport"); return; } channel_len = channel_id ? strlen (channel_id) : 0; payload_len = g_bytes_get_size (payload); prefix_str = g_strdup_printf ("%" G_GSIZE_FORMAT "\n%s\n", channel_len + 1 + payload_len, channel_id ? channel_id : ""); prefix = g_bytes_new_take (prefix_str, strlen (prefix_str)); cockpit_pipe_write (self->pipe, prefix); cockpit_pipe_write (self->pipe, payload); g_bytes_unref (prefix); g_debug ("%s: queued %" G_GSIZE_FORMAT " byte payload", self->name, payload_len); }
static void cockpit_ssh_transport_attach_pipe (CockpitSshTransport *self) { g_return_if_fail (self->pipe == NULL); g_return_if_fail (self->auth_process != NULL); if (self->agent) cockpit_ssh_agent_close (self->agent); self->pipe = cockpit_auth_process_claim_as_pipe (self->auth_process); self->read_sig = g_signal_connect (self->pipe, "read", G_CALLBACK (on_pipe_read), self); self->close_sig = g_signal_connect (self->pipe, "close", G_CALLBACK (on_pipe_close), self); cockpit_ssh_transport_remove_auth_process (self); while (g_queue_peek_head (self->queue)) { GBytes *block = g_queue_pop_head (self->queue); cockpit_pipe_write (self->pipe, block); g_bytes_unref (block); } if (self->closing && !self->closed) cockpit_pipe_close (self->pipe, NULL); }
static void on_newusers_close (CockpitPipe *pipe, const gchar *problem, gpointer user_data) { CommitAdmin1 *context = user_data; CockpitPipe *next; const gchar *argv[] = { cockpit_bridge_path_chpasswd, "--encrypted", NULL }; if (!check_pipe_exit_status (pipe, problem, "couldn't run newusers command")) { g_dbus_method_invocation_return_error (context->invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, _("Couldn't create new users")); commit_passwd1_free (context); } else { g_debug ("batch changing user passwords"); next = cockpit_pipe_spawn (argv, NULL, NULL, COCKPIT_PIPE_FLAGS_NONE); g_signal_connect (next, "close", G_CALLBACK (on_chpasswd_close), context); cockpit_pipe_write (next, context->chpasswd); cockpit_pipe_close (next, NULL); } g_object_unref (pipe); }
static gboolean on_transport_control (CockpitTransport *transport, const char *command, guint channel, JsonObject *options, GBytes *message, gpointer user_data) { CockpitPolkitAgent *self = COCKPIT_POLKIT_AGENT (user_data); ReauthorizeCaller *caller; const gchar *response; const gchar *cookie; GBytes *bytes; if (!g_str_equal (command, "authorize")) return FALSE; if (!cockpit_json_get_string (options, "cookie", NULL, &cookie) || !cockpit_json_get_string (options, "response", NULL, &response) || !cookie || !response) { g_warning ("got an invalid authorize command from cockpit-ws"); cockpit_transport_close (transport, "protocol-error"); return TRUE; } caller = g_hash_table_lookup (self->callers, cookie); if (!caller) { g_debug ("received authorize response for caller that has gone away"); return TRUE; } g_debug ("got \"authorize\" response from cockpit-ws, will send to helper: %s", response); bytes = g_bytes_new_with_free_func (response, strlen (response), (GDestroyNotify)json_object_unref, json_object_ref (options)); cockpit_pipe_write (caller->helper, bytes); g_bytes_unref (bytes); bytes = g_bytes_new_static ("\n", 1); cockpit_pipe_write (caller->helper, bytes); g_bytes_unref (bytes); return TRUE; }
static CockpitPipe * spawn_session_process (const gchar *type, GBytes *input, const gchar *remote_peer, CockpitPipe **auth_pipe) { CockpitPipe *pipe; int pwfds[2] = { -1, -1 }; GError *error = NULL; GPid pid = 0; gint in_fd = -1; gint out_fd = -1; const gchar *argv[] = { cockpit_ws_session_program, type, remote_peer ? remote_peer : "", NULL, }; g_return_val_if_fail (input != NULL, NULL); if (socketpair (PF_UNIX, SOCK_STREAM, 0, pwfds) < 0) g_return_val_if_reached (NULL); g_debug ("spawning %s", cockpit_ws_session_program); if (!g_spawn_async_with_pipes (NULL, (gchar **)argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_LEAVE_DESCRIPTORS_OPEN, session_child_setup, GINT_TO_POINTER (pwfds[1]), &pid, &in_fd, &out_fd, NULL, &error)) { g_warning ("failed to start %s: %s", cockpit_ws_session_program, error->message); g_error_free (error); return NULL; } else { pipe = g_object_new (COCKPIT_TYPE_PIPE, "name", "localhost", "pid", pid, "in-fd", out_fd, "out-fd", in_fd, NULL); /* Child process end of pipe */ close (pwfds[1]); *auth_pipe = cockpit_pipe_new ("auth-pipe", pwfds[0], pwfds[0]); cockpit_pipe_write (*auth_pipe, input); cockpit_pipe_close (*auth_pipe, NULL); } return pipe; }
static void cockpit_text_stream_recv (CockpitChannel *channel, GBytes *message) { CockpitTextStream *self = COCKPIT_TEXT_STREAM (channel); GBytes *clean; clean = check_utf8_and_force_if_necessary (message); cockpit_pipe_write (self->pipe, clean); g_bytes_unref (clean); }
static void cockpit_interact_transport_send (CockpitTransport *transport, const gchar *channel_id, GBytes *payload) { CockpitInteractTransport *self = COCKPIT_INTERACT_TRANSPORT (transport); GBytes *prefix; GBytes *suffix; GBytes *color; gchar *prefix_str; if (self->colored) { color = g_bytes_new_static ("\x1b[1m", 4); cockpit_pipe_write (self->pipe, color); g_bytes_unref (color); } prefix_str = g_strdup_printf ("%s\n", channel_id ? channel_id : ""); prefix = g_bytes_new_take (prefix_str, strlen (prefix_str)); cockpit_pipe_write (self->pipe, prefix); g_bytes_unref (prefix); cockpit_pipe_write (self->pipe, payload); suffix = g_bytes_new (self->delimiter, self->delimiter_len); cockpit_pipe_write (self->pipe, suffix); g_bytes_unref (suffix); if (self->colored) { color = g_bytes_new_static ("\x1b[0m", 4); cockpit_pipe_write (self->pipe, color); g_bytes_unref (color); } g_debug ("%s: queued %d byte payload", self->name, (int)g_bytes_get_size (payload)); }
static CockpitPipe * spawn_session_process (const gchar *user, GBytes *password, const gchar *remote_peer, CockpitPipe **auth_pipe) { CockpitPipe *pipe; int pwfds[2] = { -1, -1 }; GError *error = NULL; const gchar **argv; char autharg[32]; GPid pid = 0; gint in_fd = -1; gint out_fd = -1; const gchar *argv_password[] = { cockpit_ws_session_program, "-p", autharg, user ? user : "", remote_peer ? remote_peer : "", cockpit_ws_agent_program, NULL, }; const gchar *argv_noauth[] = { cockpit_ws_session_program, user ? user : "", remote_peer ? remote_peer : "", cockpit_ws_agent_program, NULL, }; if (password) { if (socketpair (PF_UNIX, SOCK_STREAM, 0, pwfds) < 0) g_return_val_if_reached (NULL); g_snprintf (autharg, sizeof (autharg), "%d", pwfds[1]); argv = argv_password; } else { argv = argv_noauth; } if (!g_spawn_async_with_pipes (NULL, (gchar **)argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_LEAVE_DESCRIPTORS_OPEN, NULL, NULL, &pid, &in_fd, &out_fd, NULL, &error)) { g_warning ("failed to start %s: %s", cockpit_ws_session_program, error->message); g_error_free (error); return NULL; } else { pipe = g_object_new (COCKPIT_TYPE_PIPE, "pid", pid, "in-fd", out_fd, "out-fd", in_fd, NULL); if (password) { /* Child process end of pipe */ close (pwfds[1]); *auth_pipe = cockpit_pipe_new ("password-pipe", pwfds[0], pwfds[0]); cockpit_pipe_write (*auth_pipe, password); cockpit_pipe_close (*auth_pipe, NULL); } } return pipe; }
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); }