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;
}
Beispiel #6
0
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));
}
Beispiel #9
0
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;
}
Beispiel #10
0
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);
}