/*
 * Copyright (C) 2018 Red Hat Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 */

#include "config.h"

#include "grd-settings.h"

#include <gio/gio.h>

#ifdef HAVE_RDP
#include <freerdp/freerdp.h>
#endif

#include "grd-credentials-file.h"
#include "grd-credentials-libsecret.h"
#include "grd-credentials-one-time.h"
#include "grd-credentials-tpm.h"
#include "grd-enum-types.h"

#define GRD_DEFAULT_RDP_SERVER_PORT 3389
#define GRD_DEFAULT_VNC_SERVER_PORT 5900

enum
{
  PROP_0,

  PROP_RUNTIME_MODE,
  PROP_RDP_PORT,
  PROP_RDP_NEGOTIATE_PORT,
  PROP_VNC_PORT,
  PROP_VNC_NEGOTIATE_PORT,
  PROP_RDP_ENABLED,
  PROP_VNC_ENABLED,
  PROP_RDP_VIEW_ONLY,
  PROP_VNC_VIEW_ONLY,
  PROP_RDP_SCREEN_SHARE_MODE,
  PROP_VNC_SCREEN_SHARE_MODE,
  PROP_RDP_SERVER_CERT,
  PROP_RDP_SERVER_FINGERPRINT,
  PROP_RDP_SERVER_KEY,
  PROP_RDP_SERVER_CERT_PATH,
  PROP_RDP_SERVER_KEY_PATH,
  PROP_VNC_AUTH_METHOD,
  PROP_RDP_AUTH_METHODS,
  PROP_RDP_KERBEROS_KEYTAB,
};

typedef struct _GrdSettingsPrivate
{
  GrdRuntimeMode runtime_mode;
  GrdCredentials *credentials;

  struct {
    int port;
    gboolean negotiate_port;
    gboolean is_enabled;
    gboolean view_only;
    GrdRdpScreenShareMode screen_share_mode;
    GrdRdpAuthMethods auth_methods;
    char *server_cert;
    char *server_fingerprint;
    char *server_key;
    char *server_cert_path;
    char *server_key_path;
    char *kerberos_keytab;
  } rdp;
  struct {
    int port;
    gboolean negotiate_port;
    gboolean is_enabled;
    gboolean view_only;
    GrdVncScreenShareMode screen_share_mode;
    GrdVncAuthMethod auth_method;
  } vnc;

  int max_parallel_connections;
} GrdSettingsPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (GrdSettings, grd_settings, G_TYPE_OBJECT)

#ifdef HAVE_RDP
G_DEFINE_AUTOPTR_CLEANUP_FUNC (rdpCertificate, freerdp_certificate_free)
#endif

GrdRuntimeMode
grd_settings_get_runtime_mode (GrdSettings *settings)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  return priv->runtime_mode;
}

void
grd_settings_override_max_parallel_connections (GrdSettings *settings,
                                                int          max_parallel_connections)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  priv->max_parallel_connections = max_parallel_connections;
}

int
grd_settings_get_max_parallel_connections (GrdSettings *settings)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  return priv->max_parallel_connections;
}

void
grd_settings_override_rdp_port (GrdSettings *settings,
                                int          port)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  priv->rdp.port = port;
}

void
grd_settings_override_vnc_port (GrdSettings *settings,
                                int          port)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  priv->vnc.port = port;
}

gboolean
grd_settings_get_rdp_credentials (GrdSettings  *settings,
                                  char        **out_username,
                                  char        **out_password,
                                  GError      **error)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);
  const char *test_username_override;
  const char *test_password_override;
  g_autofree char *credentials_string = NULL;
  g_autoptr (GVariant) credentials = NULL;
  g_autofree char *username = NULL;
  g_autofree char *password = NULL;

  test_username_override = g_getenv ("GNOME_REMOTE_DESKTOP_TEST_RDP_USERNAME");
  test_password_override = g_getenv ("GNOME_REMOTE_DESKTOP_TEST_RDP_PASSWORD");

  if (test_username_override && test_password_override)
    {
      *out_username = g_strdup (test_username_override);
      *out_password = g_strdup (test_password_override);
      return TRUE;
    }

  credentials = grd_credentials_lookup (priv->credentials,
                                        GRD_CREDENTIALS_TYPE_RDP,
                                        error);
  if (!credentials)
    return FALSE;

  if (!test_username_override)
    {
      g_variant_lookup (credentials, "username", "s", &username);
      if (!username)
        {
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
                       "Username not set");
          return FALSE;
        }
    }
  else
    {
      username = g_strdup (test_username_override);
    }

  if (!test_password_override)
    {
      g_variant_lookup (credentials, "password", "s", &password);
      if (!password)
        {
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
                       "Username not set");
          return FALSE;
        }
    }
  else
    {
      password = g_strdup (test_password_override);
    }

  *out_username = g_steal_pointer (&username);
  *out_password = g_steal_pointer (&password);
  return TRUE;
}

gboolean
grd_settings_set_rdp_credentials (GrdSettings  *settings,
                                  const char   *username,
                                  const char   *password,
                                  GError      **error)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);
  GVariantBuilder builder;

  g_assert (username);
  g_assert (password);

  if (!g_utf8_validate (username, -1, NULL))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
                   "Username is not a valid UTF-8 string");
      return FALSE;
    }
  if (!g_utf8_validate (password, -1, NULL))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
                   "Password is not a valid UTF-8 string");
      return FALSE;
    }

  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
  g_variant_builder_add (&builder, "{sv}",
                         "username", g_variant_new_string (username));
  g_variant_builder_add (&builder, "{sv}",
                         "password", g_variant_new_string (password));

  return grd_credentials_store (priv->credentials,
                                GRD_CREDENTIALS_TYPE_RDP,
                                g_variant_builder_end (&builder),
                                error);
}

gboolean
grd_settings_clear_rdp_credentials (GrdSettings  *settings,
                                    GError      **error)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  return grd_credentials_clear (priv->credentials,
                                GRD_CREDENTIALS_TYPE_RDP,
                                error);
}

char *
grd_settings_get_vnc_password (GrdSettings  *settings,
                               GError      **error)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);
  const char *test_password_override;
  g_autoptr (GVariant) password = NULL;

  test_password_override = g_getenv ("GNOME_REMOTE_DESKTOP_TEST_VNC_PASSWORD");
  if (test_password_override)
    return g_strdup (test_password_override);

  password = grd_credentials_lookup (priv->credentials,
                                     GRD_CREDENTIALS_TYPE_VNC,
                                     error);
  if (!password)
    return NULL;

  return g_variant_dup_string (password, NULL);
}

gboolean
grd_settings_set_vnc_password (GrdSettings  *settings,
                               const char   *password,
                               GError      **error)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  g_assert (password);

  if (!g_utf8_validate (password, -1, NULL))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
                   "Password is not a valid UTF-8 string");
      return FALSE;
    }

  return grd_credentials_store (priv->credentials,
                                GRD_CREDENTIALS_TYPE_VNC,
                                g_variant_new_string (password),
                                error);
}

gboolean
grd_settings_clear_vnc_password (GrdSettings  *settings,
                                 GError      **error)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  return grd_credentials_clear (priv->credentials,
                                GRD_CREDENTIALS_TYPE_VNC,
                                error);
}

static GrdCredentials *
create_headless_credentials (void)
{
  g_autoptr (GrdCredentials) credentials = NULL;
  g_autoptr (GError) error = NULL;

  credentials = GRD_CREDENTIALS (grd_credentials_tpm_new (&error));
  if (credentials)
    return g_steal_pointer (&credentials);

  g_warning ("Init TPM credentials failed because %s, using GKeyFile as fallback",
             error->message);

  g_clear_error (&error);
  credentials = GRD_CREDENTIALS (grd_credentials_file_new (&error));
  if (credentials)
    return g_steal_pointer (&credentials);

  g_warning ("Init file credentials failed: %s", error->message);

  return NULL;
}

static GrdCredentials *
create_credentials (GrdRuntimeMode runtime_mode)
{
  switch (runtime_mode)
    {
    case GRD_RUNTIME_MODE_HEADLESS:
    case GRD_RUNTIME_MODE_SYSTEM:
      return create_headless_credentials ();
    case GRD_RUNTIME_MODE_SCREEN_SHARE:
      return GRD_CREDENTIALS (grd_credentials_libsecret_new ());
    case GRD_RUNTIME_MODE_HANDOVER:
      return GRD_CREDENTIALS (grd_credentials_one_time_new ());
    }

  g_assert_not_reached ();
}

void
grd_settings_recreate_rdp_credentials (GrdSettings *settings)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  g_clear_object (&priv->credentials);
  priv->credentials = create_credentials (priv->runtime_mode);
}

static void
grd_settings_constructed (GObject *object)
{
  GrdSettings *settings = GRD_SETTINGS (object);
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  priv->credentials = create_credentials (priv->runtime_mode);
  g_assert (priv->credentials);
}

static void
grd_settings_finalize (GObject *object)
{
  GrdSettings *settings = GRD_SETTINGS (object);
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  g_clear_pointer (&priv->rdp.server_cert, g_free);
  g_clear_pointer (&priv->rdp.server_fingerprint, g_free);
  g_clear_pointer (&priv->rdp.server_key, g_free);
  g_clear_pointer (&priv->rdp.server_cert_path, g_free);
  g_clear_pointer (&priv->rdp.server_key_path, g_free);
  g_clear_object (&priv->credentials);

  G_OBJECT_CLASS (grd_settings_parent_class)->finalize (object);
}

static void
grd_settings_get_property (GObject    *object,
                           guint       prop_id,
                           GValue     *value,
                           GParamSpec *pspec)
{
  GrdSettings *settings = GRD_SETTINGS (object);
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  switch (prop_id)
    {
    case PROP_RUNTIME_MODE:
      g_value_set_enum (value, priv->runtime_mode);
      break;
    case PROP_RDP_PORT:
      g_value_set_int (value, priv->rdp.port);
      break;
    case PROP_RDP_NEGOTIATE_PORT:
      g_value_set_boolean (value, priv->rdp.negotiate_port);
      break;
    case PROP_VNC_PORT:
      g_value_set_int (value, priv->vnc.port);
      break;
    case PROP_VNC_NEGOTIATE_PORT:
      g_value_set_boolean (value, priv->vnc.negotiate_port);
      break;
    case PROP_RDP_ENABLED:
      g_value_set_boolean (value, priv->rdp.is_enabled);
      break;
    case PROP_VNC_ENABLED:
      g_value_set_boolean (value, priv->vnc.is_enabled);
      break;
    case PROP_RDP_VIEW_ONLY:
      g_value_set_boolean (value, priv->rdp.view_only);
      break;
    case PROP_VNC_VIEW_ONLY:
      g_value_set_boolean (value, priv->vnc.view_only);
      break;
    case PROP_RDP_SCREEN_SHARE_MODE:
      g_value_set_enum (value, priv->rdp.screen_share_mode);
      break;
    case PROP_VNC_SCREEN_SHARE_MODE:
      g_value_set_enum (value, priv->vnc.screen_share_mode);
      break;
    case PROP_RDP_SERVER_CERT:
      g_value_set_string (value, priv->rdp.server_cert);
      break;
    case PROP_RDP_SERVER_FINGERPRINT:
      g_value_set_string (value, priv->rdp.server_fingerprint);
      break;
    case PROP_RDP_SERVER_KEY:
      g_value_set_string (value, priv->rdp.server_key);
      break;
    case PROP_RDP_SERVER_CERT_PATH:
      g_value_set_string (value, priv->rdp.server_cert_path);
      break;
    case PROP_RDP_SERVER_KEY_PATH:
      g_value_set_string (value, priv->rdp.server_key_path);
      break;
    case PROP_VNC_AUTH_METHOD:
      if (g_getenv ("GNOME_REMOTE_DESKTOP_TEST_VNC_PASSWORD"))
        g_value_set_enum (value, GRD_VNC_AUTH_METHOD_PASSWORD);
      else
        g_value_set_enum (value, priv->vnc.auth_method);
      break;
    case PROP_RDP_AUTH_METHODS:
      g_value_set_flags (value, priv->rdp.auth_methods);
      break;
    case PROP_RDP_KERBEROS_KEYTAB:
      g_value_set_string (value, priv->rdp.kerberos_keytab);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

static void
update_rdp_server_fingerprint (GrdSettings *settings)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);
#ifdef HAVE_RDP
  g_autoptr (rdpCertificate) rdp_certificate = NULL;
#endif
  g_autofree char *fingerprint = NULL;

  if (!priv->rdp.server_cert_path)
    return;

#ifdef HAVE_RDP
  rdp_certificate = freerdp_certificate_new_from_file (priv->rdp.server_cert_path);
  if (!rdp_certificate)
    {
      g_warning ("RDP server certificate is invalid");
      return;
    }

  fingerprint = freerdp_certificate_get_fingerprint (rdp_certificate);
  if (!fingerprint)
    {
      g_warning ("Could not compute RDP server certificate fingerprint");
      return;
    }
#endif

  if (fingerprint)
    g_object_set (G_OBJECT (settings), "rdp-server-fingerprint", fingerprint, NULL);
}

static void
update_rdp_server_cert (GrdSettings *settings)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);
  g_autofree char *server_cert = NULL;

  if (!priv->rdp.server_cert_path)
    return;

  g_file_get_contents (priv->rdp.server_cert_path,
                       &server_cert,
                       NULL, NULL);
  g_object_set (G_OBJECT (settings), "rdp-server-cert", server_cert, NULL);
}

static void
update_rdp_server_key (GrdSettings *settings)
{
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);
  g_autofree char *server_key = NULL;

  if (!priv->rdp.server_key_path)
    return;

  g_file_get_contents (priv->rdp.server_key_path,
                       &server_key,
                       NULL, NULL);
  g_object_set (G_OBJECT (settings), "rdp-server-key", server_key, NULL);
}

static void
grd_settings_set_property (GObject      *object,
                           guint         prop_id,
                           const GValue *value,
                           GParamSpec   *pspec)
{
  GrdSettings *settings = GRD_SETTINGS (object);
  GrdSettingsPrivate *priv = grd_settings_get_instance_private (settings);

  switch (prop_id)
    {
    case PROP_RUNTIME_MODE:
      priv->runtime_mode = g_value_get_enum (value);
      break;
    case PROP_RDP_PORT:
      priv->rdp.port = g_value_get_int (value);
      break;
    case PROP_RDP_NEGOTIATE_PORT:
      priv->rdp.negotiate_port = g_value_get_boolean (value);
      break;
    case PROP_VNC_PORT:
      priv->vnc.port = g_value_get_int (value);
      break;
    case PROP_VNC_NEGOTIATE_PORT:
      priv->vnc.negotiate_port = g_value_get_boolean (value);
      break;
    case PROP_RDP_ENABLED:
      priv->rdp.is_enabled = g_value_get_boolean (value);
      break;
    case PROP_VNC_ENABLED:
      priv->vnc.is_enabled = g_value_get_boolean (value);
      break;
    case PROP_RDP_VIEW_ONLY:
      priv->rdp.view_only = g_value_get_boolean (value);
      break;
    case PROP_VNC_VIEW_ONLY:
      priv->vnc.view_only = g_value_get_boolean (value);
      break;
    case PROP_RDP_SCREEN_SHARE_MODE:
      priv->rdp.screen_share_mode = g_value_get_enum (value);
      break;
    case PROP_VNC_SCREEN_SHARE_MODE:
      priv->vnc.screen_share_mode = g_value_get_enum (value);
      break;
    case PROP_RDP_SERVER_CERT:
      g_clear_pointer (&priv->rdp.server_cert, g_free);
      priv->rdp.server_cert = g_strdup (g_value_get_string (value));
      break;
    case PROP_RDP_SERVER_FINGERPRINT:
      g_clear_pointer (&priv->rdp.server_fingerprint, g_free);
      priv->rdp.server_fingerprint = g_strdup (g_value_get_string (value));
      break;
    case PROP_RDP_SERVER_KEY:
      g_clear_pointer (&priv->rdp.server_key, g_free);
      priv->rdp.server_key = g_strdup (g_value_get_string (value));
      break;
    case PROP_RDP_SERVER_CERT_PATH:
      g_clear_pointer (&priv->rdp.server_cert_path, g_free);
      priv->rdp.server_cert_path = g_strdup (g_value_get_string (value));
      update_rdp_server_cert (settings);
      update_rdp_server_fingerprint (settings);
      break;
    case PROP_RDP_SERVER_KEY_PATH:
      g_clear_pointer (&priv->rdp.server_key_path, g_free);
      priv->rdp.server_key_path = g_strdup (g_value_get_string (value));
      update_rdp_server_key (settings);
      break;
    case PROP_VNC_AUTH_METHOD:
      priv->vnc.auth_method = g_value_get_enum (value);
      break;
    case PROP_RDP_AUTH_METHODS:
      priv->rdp.auth_methods = g_value_get_flags (value);
      break;
    case PROP_RDP_KERBEROS_KEYTAB:
      g_clear_pointer (&priv->rdp.kerberos_keytab, g_free);
      priv->rdp.kerberos_keytab = g_value_dup_string (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

static void
grd_settings_init (GrdSettings *settings)
{
}

static void
grd_settings_class_init (GrdSettingsClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->constructed = grd_settings_constructed;
  object_class->finalize = grd_settings_finalize;
  object_class->get_property = grd_settings_get_property;
  object_class->set_property = grd_settings_set_property;

  g_object_class_install_property (object_class,
                                   PROP_RUNTIME_MODE,
                                   g_param_spec_enum ("runtime-mode",
                                                      "runtime mode",
                                                      "runtime mode",
                                                      GRD_TYPE_RUNTIME_MODE,
                                                      GRD_RUNTIME_MODE_SCREEN_SHARE,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT |
                                                      G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_PORT,
                                   g_param_spec_int ("rdp-port",
                                                     "rdp port",
                                                     "rdp port",
                                                     0,
                                                     G_MAXUINT16,
                                                     GRD_DEFAULT_RDP_SERVER_PORT,
                                                     G_PARAM_READWRITE |
                                                     G_PARAM_CONSTRUCT |
                                                     G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_NEGOTIATE_PORT,
                                   g_param_spec_boolean ("rdp-negotiate-port",
                                                         "rdp negotiate port",
                                                         "rdp negotiate port",
                                                         FALSE,
                                                         G_PARAM_READWRITE |
                                                         G_PARAM_CONSTRUCT |
                                                         G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_VNC_PORT,
                                   g_param_spec_int ("vnc-port",
                                                     "vnc port",
                                                     "vnc port",
                                                     0,
                                                     G_MAXUINT16,
                                                     GRD_DEFAULT_VNC_SERVER_PORT,
                                                     G_PARAM_READWRITE |
                                                     G_PARAM_CONSTRUCT |
                                                     G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_VNC_NEGOTIATE_PORT,
                                   g_param_spec_boolean ("vnc-negotiate-port",
                                                         "vnc negotiate port",
                                                         "vnc negotiate port",
                                                         FALSE,
                                                         G_PARAM_READWRITE |
                                                         G_PARAM_CONSTRUCT |
                                                         G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_ENABLED,
                                   g_param_spec_boolean ("rdp-enabled",
                                                         "rdp enabled",
                                                         "rdp enabled",
                                                         FALSE,
                                                         G_PARAM_READWRITE |
                                                         G_PARAM_CONSTRUCT |
                                                         G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_VNC_ENABLED,
                                   g_param_spec_boolean ("vnc-enabled",
                                                         "vnc enabled",
                                                         "vnc enabled",
                                                         FALSE,
                                                         G_PARAM_READWRITE |
                                                         G_PARAM_CONSTRUCT |
                                                         G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_VIEW_ONLY,
                                   g_param_spec_boolean ("rdp-view-only",
                                                         "rdp view only",
                                                         "rdp view only",
                                                         FALSE,
                                                         G_PARAM_READWRITE |
                                                         G_PARAM_CONSTRUCT |
                                                         G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_VNC_VIEW_ONLY,
                                   g_param_spec_boolean ("vnc-view-only",
                                                         "vnc view only",
                                                         "vnc view only",
                                                         FALSE,
                                                         G_PARAM_READWRITE |
                                                         G_PARAM_CONSTRUCT |
                                                         G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_SCREEN_SHARE_MODE,
                                   g_param_spec_enum ("rdp-screen-share-mode",
                                                      "rdp screen share mode",
                                                      "rdp screen share mode",
                                                      GRD_TYPE_RDP_SCREEN_SHARE_MODE,
                                                      GRD_RDP_SCREEN_SHARE_MODE_MIRROR_PRIMARY,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT |
                                                      G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_VNC_SCREEN_SHARE_MODE,
                                   g_param_spec_enum ("vnc-screen-share-mode",
                                                      "vnc screen share mode",
                                                      "vnc screen share mode",
                                                      GRD_TYPE_VNC_SCREEN_SHARE_MODE,
                                                      GRD_VNC_SCREEN_SHARE_MODE_MIRROR_PRIMARY,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT |
                                                      G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_SERVER_CERT,
                                   g_param_spec_string ("rdp-server-cert",
                                                        "rdp server cert",
                                                        "rdp server cert",
                                                        NULL,
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT |
                                                        G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_SERVER_FINGERPRINT,
                                   g_param_spec_string ("rdp-server-fingerprint",
                                                        "rdp server fingerprint",
                                                        "rdp server fingerprint",
                                                        NULL,
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT |
                                                        G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_SERVER_KEY,
                                   g_param_spec_string ("rdp-server-key",
                                                        "rdp server key",
                                                        "rdp server key",
                                                        NULL,
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT |
                                                        G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_SERVER_CERT_PATH,
                                   g_param_spec_string ("rdp-server-cert-path",
                                                        "rdp server cert path",
                                                        "rdp server cert path",
                                                        NULL,
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT |
                                                        G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_SERVER_KEY_PATH,
                                   g_param_spec_string ("rdp-server-key-path",
                                                        "rdp server key path",
                                                        "rdp server key path",
                                                        NULL,
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT |
                                                        G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_VNC_AUTH_METHOD,
                                   g_param_spec_enum ("vnc-auth-method",
                                                      "vnc auth method",
                                                      "vnc auth method",
                                                      GRD_TYPE_VNC_AUTH_METHOD,
                                                      GRD_VNC_AUTH_METHOD_PROMPT,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT |
                                                      G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_AUTH_METHODS,
                                   g_param_spec_flags ("rdp-auth-methods",
                                                       "rdp auth methods",
                                                       "rdp auth methods",
                                                       GRD_TYPE_RDP_AUTH_METHODS,
                                                       GRD_RDP_AUTH_METHOD_CREDENTIALS,
                                                       G_PARAM_READWRITE |
                                                       G_PARAM_CONSTRUCT |
                                                       G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class,
                                   PROP_RDP_KERBEROS_KEYTAB,
                                   g_param_spec_string ("rdp-kerberos-keytab",
                                                        "rdp kerberos keypath",
                                                        "rdp kerberos keypath",
                                                        NULL,
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT |
                                                        G_PARAM_STATIC_STRINGS));
}
