Esempio n. 1
0
static void
on_web_service_idling (CockpitWebService *service,
                       gpointer data)
{
  CockpitAuthenticated *authenticated = data;

  if (authenticated->timeout_tag)
    g_source_remove (authenticated->timeout_tag);

  g_debug ("%s: login is idle", cockpit_creds_get_user (authenticated->creds));

  /*
   * The minimum amount of time before a request uses this new web service,
   * otherwise it will just go away.
   */
  authenticated->timeout_tag = g_timeout_add_seconds (cockpit_ws_service_idle,
                                                      on_authenticated_timeout,
                                                      authenticated);

  /*
   * Also reset the timer which checks whether anything is going on in the
   * entire process or not.
   */
  if (authenticated->auth->timeout_tag)
    g_source_remove (authenticated->auth->timeout_tag);

  authenticated->auth->timeout_tag = g_timeout_add_seconds (cockpit_ws_process_idle,
                                                            on_process_timeout, authenticated->auth);
}
Esempio n. 2
0
static void
cockpit_ssh_transport_constructed (GObject *object)
{
  CockpitSshTransport *self = COCKPIT_SSH_TRANSPORT (object);
  CockpitSshData *data;

  static GSourceFuncs source_funcs = {
    cockpit_ssh_source_prepare,
    cockpit_ssh_source_check,
    cockpit_ssh_source_dispatch,
    NULL,
  };

  G_OBJECT_CLASS (cockpit_ssh_transport_parent_class)->constructed (object);

  g_return_if_fail (self->data->creds != NULL);
  g_warn_if_fail (ssh_options_set (self->data->session, SSH_OPTIONS_USER,
                                   cockpit_creds_get_user (self->data->creds)) == 0);

  self->io = g_source_new (&source_funcs, sizeof (CockpitSshSource));
  ((CockpitSshSource *)self->io)->transport = self;
  g_source_attach (self->io, self->data->context);

  /* Setup for connect thread */
  self->connect_fd = ssh_get_fd (self->data->session);
  g_atomic_int_set (&self->connecting, 1);
  self->data->connecting = &self->connecting;
  data = self->data;
  self->data = NULL;

  self->connect_thread = g_thread_new ("ssh-transport-connect",
                                       cockpit_ssh_connect_thread, data);

  g_debug ("%s: constructed", self->logname);
}
Esempio n. 3
0
static CockpitCreds *
cookie_to_creds  (CockpitAuth *self,
                  const char *cookie)
{
  CockpitCreds *creds = NULL;
  const char *prefix = "v=2;k=";
  const gsize n_prefix = 6;
  const gchar *id;

  if (!g_str_has_prefix (cookie, prefix))
    {
      g_debug ("invalid or unsupported cookie: %s", cookie);
      return NULL;
    }

  id = cookie + n_prefix;

  creds = g_hash_table_lookup (self->authenticated, id);
  if (creds)
    {
      g_debug ("received credential id '%s' for user '%s'", id,
               cockpit_creds_get_user (creds));
      cockpit_creds_ref (creds);
    }
  else
    g_debug ("received unknown/invalid credential id '%s'", id);

  return creds;
}
static gboolean
authorize_check_user (CockpitCreds *creds,
                      const char *challenge)
{
  char *subject = NULL;
  gboolean ret = FALSE;
  gchar *encoded = NULL;
  const gchar *user;

  if (!cockpit_authorize_subject (challenge, &subject))
    goto out;

  if (!subject || g_str_equal (subject, ""))
    {
      ret = TRUE;
    }
  else
    {
      user = cockpit_creds_get_user (creds);
      if (user == NULL)
        {
          ret = TRUE;
        }
      else
        {
          encoded = cockpit_hex_encode (user, -1);
          ret = g_str_equal (encoded, subject);
        }
    }

out:
  g_free (encoded);
  free (subject);
  return ret;
}
Esempio n. 5
0
static gboolean
on_authenticated_timeout (gpointer data)
{
  CockpitAuthenticated *authenticated = data;
  CockpitAuth *self = authenticated->auth;

  authenticated->timeout_tag = 0;

  if (cockpit_web_service_get_idling (authenticated->service))
    {
      g_info ("%s: timed out", cockpit_creds_get_user (authenticated->creds));
      g_hash_table_remove (self->authenticated, authenticated->cookie);
    }

  return FALSE;
}
Esempio n. 6
0
/**
 * cockpit_auth_start_session:
 * @self: a CockpitAuth
 * @creds: credentials for the session
 *
 * Start a local session process for the given credentials. It may be
 * that one is hanging around from prior authentication, in which case
 * that one is used.
 *
 * If launching the session fails, then the pipe will be created in a
 * failed state, and will close shortly. A CockpitPipe is always returned.
 *
 * Returns: (transfer full): the new pipe
 */
CockpitPipe *
cockpit_auth_start_session (CockpitAuth *self,
                            CockpitCreds *creds)
{
  CockpitPipe *pipe;
  CockpitPipe *auth_pipe = NULL;
  const gchar *password;
  GBytes *bytes;

  g_return_val_if_fail (creds != NULL, NULL);

  pipe = pop_session_process (self, creds);
  if (pipe == NULL)
    {
      password = cockpit_creds_get_password (creds);
      if (password == NULL)
        {
          bytes = NULL;
        }
      else
        {
          bytes = g_bytes_new_with_free_func (password, strlen (password),
                                              cockpit_creds_unref, creds);
        }

      pipe = spawn_session_process (cockpit_creds_get_user (creds),
                                    bytes, cockpit_creds_get_rhost (creds),
                                    &auth_pipe);
      if (auth_pipe)
        {
          /*
           * Any failure will come from the pipe exit code, but the session
           * needs our password (if we have one) so let it get sent.
           */
          g_signal_connect (auth_pipe, "close", G_CALLBACK (g_object_unref), NULL);
        }
    }

  if (!pipe)
    {
      pipe = g_object_new (COCKPIT_TYPE_PIPE,
                           "problem", "internal-error",
                           NULL);
    }

  return pipe;
}
Esempio n. 7
0
static void
send_login_response (CockpitWebResponse *response,
                     CockpitCreds *creds,
                     GHashTable *headers)
{
  JsonObject *object;
  GBytes *content;

  object = json_object_new ();
  json_object_set_string_member (object, "user", cockpit_creds_get_user (creds));

  content = cockpit_json_write_bytes (object);
  json_object_unref (object);

  g_hash_table_replace (headers, g_strdup ("Content-Type"), g_strdup ("application/json"));
  cockpit_web_response_content (response, headers, content, NULL);
  g_bytes_unref (content);
}
Esempio n. 8
0
static void
on_web_service_idling (CockpitWebService *service,
                       gpointer data)
{
  CockpitAuthenticated *authenticated = data;

  if (authenticated->timeout_tag)
    g_source_remove (authenticated->timeout_tag);

  g_debug ("%s: login is idle", cockpit_creds_get_user (authenticated->creds));

  /*
   * The minimum amount of time before a request uses this new web service,
   * otherwise it will just go away.
   */
  authenticated->timeout_tag = g_timeout_add_seconds (cockpit_ws_idle_timeout,
                                                      on_authenticated_timeout,
                                                      authenticated);
}
Esempio n. 9
0
CockpitWebService *
cockpit_auth_check_cookie (CockpitAuth *self,
                           GHashTable *in_headers)
{
  CockpitAuthenticated *authenticated;

  authenticated = authenticated_for_headers (self, in_headers);

  if (authenticated)
    {
      g_debug ("received credential cookie for user '%s'",
               cockpit_creds_get_user (authenticated->creds));
      return g_object_ref (authenticated->service);
    }
  else
    {
      g_debug ("received unknown/invalid credential cookie");
      return NULL;
    }
}
Esempio n. 10
0
static char *
creds_to_cookie (CockpitAuth *self,
                 CockpitCreds *creds)
{
  guint64 seed;
  gchar *cookie;
  char *id;

  seed = self->nonce_seed++;
  id = g_compute_hmac_for_data (G_CHECKSUM_SHA256,
                                self->key->data, self->key->len,
                                (guchar *)&seed, sizeof (seed));

  cookie = g_strdup_printf ("v=2;k=%s", id);
  g_hash_table_insert (self->authenticated, id,
                       cockpit_creds_ref (creds));

  g_debug ("sending credential id '%s' for user '%s'", id,
           cockpit_creds_get_user (creds));

  return cookie;
}
Esempio n. 11
0
void
cockpit_auth_logout (CockpitAuth *self,
                     GHashTable *headers,
                     gboolean secure_req,
                     GHashTable *out_headers)
{
  CockpitAuthenticated *authenticated;
  gchar *cookie;

  authenticated = authenticated_for_headers (self, headers);
  if (authenticated)
    {
      g_info ("logged out user %s", cockpit_creds_get_user (authenticated->creds));
      g_hash_table_remove (self->authenticated, authenticated->cookie);
    }

  if (out_headers)
    {
      cookie = g_strdup_printf ("CockpitAuth=blank; Path=/; Expires=Wed, 13-Jan-2021 22:23:01 GMT;%s HttpOnly",
                                secure_req ? " Secure;" : "");
      g_hash_table_insert (out_headers, g_strdup ("Set-Cookie"), cookie);
    }
}
Esempio n. 12
0
static GBytes *
build_environment (CockpitWebService *service,
                   JsonObject *modules)
{
  const gchar *user;
  CockpitCreds *creds;
  JsonObject *env;
  JsonObject *localhost;
  JsonObject *languages;
  JsonObject *language;
  struct passwd *pwd;
  gchar *hostname;
  GBytes *bytes;
  guint n;

  const struct {
    const gchar *name;
    const gchar *code;
  } supported_languages[] = {
    { NC_("display-language", "English"), "" },
    { NC_("display-language", "Danish"),  "da" },
    { NC_("display-language", "German"),  "de" },
  };

  env = json_object_new ();
  if (service)
    {
      creds = cockpit_web_service_get_creds (service);
      user = cockpit_creds_get_user (creds);
      json_object_set_string_member (env, "user", user);
      pwd = cockpit_getpwnam_a (user, NULL);
      if (pwd)
        {
          json_object_set_string_member (env, "name", pwd->pw_gecos);
          free (pwd);
        }
    }

  localhost = json_object_new ();

  /* This awkwardly takes the localhost reference */
  json_object_set_object_member (env, "localhost", localhost);

  hostname = g_malloc0 (HOST_NAME_MAX + 1);
  gethostname (hostname, HOST_NAME_MAX);
  hostname[HOST_NAME_MAX] = '\0';

  json_object_set_string_member (env, "hostname", hostname);

  /* Only include version info if logged in */
  if (service)
    {
      json_object_set_string_member (localhost, "version", PACKAGE_VERSION);
      json_object_set_string_member (localhost, "build_info", COCKPIT_BUILD_INFO);
    }

  languages = json_object_new ();

  /* This awkwardly takes the languages reference */
  json_object_set_object_member (localhost, "languages", languages);

  for (n = 0; n < G_N_ELEMENTS (supported_languages); n++)
    {
      language = json_object_new ();
      json_object_set_object_member (languages, supported_languages[n].code, language);
      json_object_set_string_member (language, "name", supported_languages[n].name);
    }

  if (modules)
    json_object_set_object_member (localhost, "modules", json_object_ref (modules));

  bytes = cockpit_json_write_bytes (env);
  json_object_unref (env);

  return bytes;
}
Esempio n. 13
0
CockpitWebService *
cockpit_auth_login_finish (CockpitAuth *self,
                           GAsyncResult *result,
                           CockpitAuthFlags flags,
                           GHashTable *out_headers,
                           GError **error)
{
  CockpitAuthClass *klass = COCKPIT_AUTH_GET_CLASS (self);
  CockpitAuthenticated *authenticated;
  CockpitTransport *transport = NULL;
  CockpitCreds *creds;
  gchar *cookie_b64 = NULL;
  gchar *header;
  guint64 seed;
  gchar *id;

  g_return_val_if_fail (klass->login_finish != NULL, FALSE);
  creds = klass->login_finish (self, result, out_headers, &transport, error);

  if (creds == NULL)
    return NULL;

  seed = self->nonce_seed++;
  id = g_compute_hmac_for_data (G_CHECKSUM_SHA256,
                                self->key->data, self->key->len,
                                (guchar *)&seed, sizeof (seed));

  authenticated = g_new0 (CockpitAuthenticated, 1);
  authenticated->cookie = g_strdup_printf ("v=2;k=%s", id);
  authenticated->creds = creds;
  authenticated->service = cockpit_web_service_new (creds, transport);
  authenticated->auth = self;

  authenticated->idling_sig = g_signal_connect (authenticated->service, "idling",
                                                G_CALLBACK (on_web_service_idling), authenticated);
  authenticated->destroy_sig = g_signal_connect (authenticated->service, "destroy",
                                                G_CALLBACK (on_web_service_destroy), authenticated);

  if (transport)
    g_object_unref (transport);

  g_object_weak_ref (G_OBJECT (authenticated->service),
                     on_web_service_gone, authenticated);

  /* Start off in the idling state, and begin a timeout during which caller must do something else */
  on_web_service_idling (authenticated->service, authenticated);

  g_hash_table_insert (self->authenticated, authenticated->cookie, authenticated);

  g_debug ("sending credential id '%s' for user '%s'", id,
           cockpit_creds_get_user (creds));

  g_free (id);

  if (out_headers)
    {
      gboolean force_secure = !(flags & COCKPIT_AUTH_COOKIE_INSECURE);
      cookie_b64 = g_base64_encode ((guint8 *)authenticated->cookie, strlen (authenticated->cookie));
      header = g_strdup_printf ("cockpit=%s; Path=/; %s HttpOnly",
                                cookie_b64, force_secure ? " Secure;" : "");
      g_free (cookie_b64);
      g_hash_table_insert (out_headers, g_strdup ("Set-Cookie"), header);
    }

  g_info ("logged in user: %s", cockpit_creds_get_user (authenticated->creds));
  return g_object_ref (authenticated->service);
}
Esempio n. 14
0
static gboolean
process_transport_authorize (CockpitWebService *self,
                             CockpitTransport *transport,
                             JsonObject *options)
{
  const gchar *cookie = NULL;
  GBytes *payload;
  char *type = NULL;
  char *alloc = NULL;
  const char *response = NULL;
  const gchar *challenge;
  const gchar *password;
  const gchar *host;
  GBytes *data;

  if (!cockpit_json_get_string (options, "challenge", NULL, &challenge) ||
      !cockpit_json_get_string (options, "cookie", NULL, &cookie) ||
      !cockpit_json_get_string (options, "host", NULL, &host))
    {
      g_warning ("received invalid authorize command");
      return FALSE;
    }

  if (!challenge || !cookie)
    {
      g_message ("unsupported or unknown authorize command");
      return FALSE;
    }

  if (!cockpit_authorize_type (challenge, &type))
    {
      g_message ("received invalid authorize challenge command");
    }
  else if (g_str_equal (type, "plain1") ||
           g_str_equal (type, "crypt1") ||
           g_str_equal (type, "basic"))
    {
      data = cockpit_creds_get_password (self->creds);
      if (!data)
        {
          g_debug ("%s: received \"authorize\" %s \"challenge\", but no password", host, type);
        }
      else if (!g_str_equal ("basic", type) && !authorize_check_user (self->creds, challenge))
        {
          g_debug ("received \"authorize\" %s \"challenge\", but for wrong user", type);
        }
      else
        {
          password = g_bytes_get_data (data, NULL);
          if (g_str_equal (type, "crypt1"))
            {
              alloc = cockpit_compat_reply_crypt1 (challenge, password);
              if (alloc)
                response = alloc;
              else
                g_message ("failed to \"authorize\" crypt1 \"challenge\"");
            }
          else if (g_str_equal (type, "basic"))
            {
              response = cockpit_authorize_build_basic (cockpit_creds_get_user (self->creds),
                                                        password);
            }
          else
            {
              response = password;
            }
        }
    }

  /* Tell the frontend that we're reauthorizing */
  if (self->init_received)
    {
      self->credential_requests++;
      send_socket_hints (self, "credential", "request");
    }

  if (cookie && !self->sent_done)
    {
      payload = cockpit_transport_build_control ("command", "authorize",
                                                 "cookie", cookie,
                                                 "response", response ? response : "",
                                                 "host", host,
                                                 NULL);
      cockpit_transport_send (transport, NULL, payload);
      g_bytes_unref (payload);
    }

  free (type);
  free (alloc);
  return TRUE;
}