Beispiel #1
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;
}
static void
on_web_socket_open (WebSocketConnection *connection,
                    CockpitWebService *self)
{
  CockpitSocket *socket;
  JsonArray *capabilities;
  GBytes *command;
  JsonObject *object;
  JsonObject *info;

  g_info ("New connection to session from %s", cockpit_creds_get_rhost (self->creds));

  socket = cockpit_socket_lookup_by_connection (&self->sockets, connection);
  g_return_if_fail (socket != NULL);

  object = json_object_new ();
  json_object_set_string_member (object, "command", "init");
  json_object_set_int_member (object, "version", 1);
  json_object_set_string_member (object, "channel-seed", socket->id);
  json_object_set_string_member (object, "host", "localhost");
  json_object_set_string_member (object, "csrf-token", cockpit_creds_get_csrf_token (self->creds));

  capabilities = json_array_new ();
  json_array_add_string_element (capabilities, "multi");
  json_array_add_string_element (capabilities, "credentials");
  json_array_add_string_element (capabilities, "binary");
  json_object_set_array_member (object, "capabilities", capabilities);

  info = json_object_new ();
  json_object_set_string_member (info, "version", PACKAGE_VERSION);
  json_object_set_string_member (info, "build", COCKPIT_BUILD_INFO);
  json_object_set_object_member (object, "system", info);

  command = cockpit_json_write_bytes (object);
  json_object_unref (object);

  web_socket_connection_send (connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, command);
  g_bytes_unref (command);

  /* Do we have an authorize password? if so tell the frontend */
  if (cockpit_creds_get_password (self->creds))
    send_socket_hints (self, "credential", "password");

  g_signal_connect (connection, "message",
                    G_CALLBACK (on_web_socket_message), self);
}
Beispiel #3
0
static const gchar *
cockpit_ssh_authenticate (CockpitSshData *data)
{
  gss_cred_id_t gsscreds = GSS_C_NO_CREDENTIAL;
  const gchar *password = NULL;
  const gchar *problem;
  gboolean tried = FALSE;
  gchar *description;
  int methods;
  int rc;

  problem = "not-authorized";

  rc = ssh_userauth_none (data->session, NULL);
  if (rc == SSH_AUTH_ERROR)
    {
      if (g_atomic_int_get (data->connecting))
        g_message ("%s: server authentication handshake failed: %s",
                   data->logname, ssh_get_error (data->session));
      problem = "internal-error";
      goto out;
    }

  if (rc == SSH_AUTH_SUCCESS)
    {
      problem = NULL;
      goto out;
    }

  methods = ssh_userauth_list (data->session, NULL);
  if (methods & SSH_AUTH_METHOD_PASSWORD)
    {
      password = cockpit_creds_get_password (data->creds);
      if (password)
        {
          tried = TRUE;
          rc = ssh_userauth_password (data->session, NULL, password);
          switch (rc)
            {
            case SSH_AUTH_SUCCESS:
              g_debug ("%s: password auth succeeded", data->logname);
              problem = NULL;
              goto out;
            case SSH_AUTH_DENIED:
              g_debug ("%s: password auth failed", data->logname);
              break;
            case SSH_AUTH_PARTIAL:
              g_message ("%s: password auth worked, but server wants more authentication",
                         data->logname);
              break;
            default:
              if (g_atomic_int_get (data->connecting))
                g_message ("%s: couldn't authenticate: %s", data->logname,
                           ssh_get_error (data->session));
              problem = "internal-error";
              goto out;
            }
        }
    }

  if (methods & SSH_AUTH_METHOD_GSSAPI_MIC)
    {
      tried = TRUE;

      gsscreds = cockpit_creds_push_thread_default_gssapi (data->creds);
      if (gsscreds != GSS_C_NO_CREDENTIAL)
        {
#ifdef HAVE_SSH_GSSAPI_SET_CREDS
          ssh_gssapi_set_creds (data->session, gsscreds);
#else
          g_warning ("unable to forward delegated gssapi kerberos credentials because the "
                     "version of libssh on this system does not support it.");
#endif

          rc = ssh_userauth_gssapi (data->session);

#ifdef HAVE_SSH_GSSAPI_SET_CREDS
          ssh_gssapi_set_creds (data->session, NULL);
#endif

          switch (rc)
            {
            case SSH_AUTH_SUCCESS:
              g_debug("%s: gssapi auth succeeded", data->logname);
              problem = NULL;
              goto out;
            case SSH_AUTH_DENIED:
              g_debug ("%s: gssapi auth failed", data->logname);
              break;
            case SSH_AUTH_PARTIAL:
              g_message ("%s: gssapi auth worked, but server wants more authentication",
                         data->logname);
              break;
            default:
              if (g_atomic_int_get (data->connecting))
                g_message ("%s: couldn't authenticate: %s", data->logname,
                           ssh_get_error (data->session));
              problem = "internal-error";
              goto out;
            }
        }
    }

  if (!tried)
    {
      description = auth_method_description (methods);
      g_message ("%s: server offered unsupported authentication methods: %s",
                 data->logname, description);
      g_free (description);
      problem = "not-authorized";
    }
  else if (!password && gsscreds == GSS_C_NO_CREDENTIAL)
    {
      problem = "no-forwarding";
    }
  else
    {
      problem = "not-authorized";
    }

out:
  cockpit_creds_pop_thread_default_gssapi (data->creds, gsscreds);
  return problem;
}
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;
}
static gboolean
process_socket_authorize (CockpitWebService *self,
                          CockpitSocket *socket,
                          const gchar *channel,
                          JsonObject *options,
                          GBytes *payload)
{
  const gchar *response = NULL;
  gboolean ret = FALSE;
  GBytes *bytes = NULL;
  char *password = NULL;
  char *user = NULL;
  char *type = NULL;
  gpointer data;
  gsize length;

  if (!cockpit_json_get_string (options, "response", NULL, &response))
    {
      g_warning ("%s: received invalid \"response\" field in authorize command", socket->id);
      goto out;
    }

  ret = TRUE;
  if (response)
    {
      if (!cockpit_authorize_type (response, &type) || !g_str_equal (type, "basic"))
        goto out;

      password = cockpit_authorize_parse_basic (response, &user);
      if (password && !user)
        {
          cockpit_memory_clear (password, -1);
          free (password);
          password = NULL;
        }
    }
  else
    {
      send_socket_hints (self, "credential",
                         cockpit_creds_get_password (self->creds) ? "password" : "none");
      if (self->credential_requests)
        send_socket_hints (self, "credential", "request");
      goto out;
    }

  if (password == NULL)
    {
      send_socket_hints (self, "credential", "none");
      self->credential_requests = 0;
      bytes = NULL;
    }
  else
    {
      send_socket_hints (self, "credential", "password");
      bytes = g_bytes_new_with_free_func (password, strlen (password),
                                          clear_and_free_string, password);
      password = NULL;
    }

  cockpit_creds_set_user (self->creds, user);
  cockpit_creds_set_password (self->creds, bytes);

  /* Clear out the payload memory */
  data = (gpointer)g_bytes_get_data (payload, &length);
  cockpit_memory_clear (data, length);

out:
  free (type);
  free (user);
  if (bytes)
    g_bytes_unref (bytes);
  return ret;
}