mirror of
https://github.com/morgan9e/grd
synced 2026-04-14 00:14:18 +09:00
1200 lines
34 KiB
C
1200 lines
34 KiB
C
/*
|
|
* Copyright (C) 2021-2022 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 <ctype.h>
|
|
#include <gio/gio.h>
|
|
#include <gio/gunixinputstream.h>
|
|
#include <gio/gunixoutputstream.h>
|
|
#include <glib/gi18n.h>
|
|
#include <pwd.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <sysexits.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
#include "grd-enums.h"
|
|
#include "grd-settings-headless.h"
|
|
#include "grd-settings-system.h"
|
|
#include "grd-settings-user.h"
|
|
#include "grd-utils.h"
|
|
|
|
#define GRD_SYSTEMD_SERVICE "gnome-remote-desktop.service"
|
|
#define GRD_SYSTEMD_HEADLESS_SERVICE "gnome-remote-desktop-headless.service"
|
|
|
|
typedef enum
|
|
{
|
|
PROMPT_TYPE_VISIBLE_TEXT,
|
|
PROMPT_TYPE_HIDDEN_TEXT
|
|
} PromptType;
|
|
|
|
typedef struct _SubCommand
|
|
{
|
|
const char *subcommand;
|
|
gboolean (* process) (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error);
|
|
int n_args;
|
|
} SubCommand;
|
|
|
|
static void
|
|
log_handler (const char *log_domain,
|
|
GLogLevelFlags log_level,
|
|
const char *message,
|
|
gpointer user_data)
|
|
{
|
|
fprintf (stderr, "%s.\n", message);
|
|
}
|
|
|
|
static void
|
|
print_usage (void)
|
|
{
|
|
printf (_("Usage: %s [OPTIONS...] COMMAND [SUBCOMMAND]...\n"),
|
|
g_get_prgname ());
|
|
}
|
|
|
|
static int
|
|
process_options (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
const SubCommand *subcommands,
|
|
int n_subcommands)
|
|
{
|
|
gboolean subcommand_exists = FALSE;
|
|
int i;
|
|
|
|
if (argc <= 0)
|
|
return EX_USAGE;
|
|
|
|
for (i = 0; i < n_subcommands; i++)
|
|
{
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
if (g_strcmp0 (argv[0], subcommands[i].subcommand) != 0)
|
|
continue;
|
|
|
|
subcommand_exists = TRUE;
|
|
|
|
if (subcommands[i].n_args != argc - 1)
|
|
continue;
|
|
|
|
if (!subcommands[i].process (settings,
|
|
argc - 1, argv + 1, &error))
|
|
{
|
|
g_printerr ("%s\n", error->message);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (!GRD_IS_SETTINGS_SYSTEM (settings))
|
|
g_settings_sync ();
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
if (subcommand_exists)
|
|
g_printerr ("Wrong number of arguments for subcommand '%s'\n", argv[0]);
|
|
else
|
|
g_printerr ("Unknown subcommand '%s'\n", argv[0]);
|
|
|
|
return EX_USAGE;
|
|
}
|
|
|
|
static gboolean
|
|
is_numeric (const char *s)
|
|
{
|
|
while (*s)
|
|
{
|
|
if (isdigit (*s++) == 0)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static char *
|
|
prompt_for_input (const char *prompt,
|
|
PromptType prompt_type,
|
|
GError **error)
|
|
{
|
|
g_autoptr (GInputStream) input_stream = NULL;
|
|
g_autoptr (GOutputStream) output_stream = NULL;
|
|
g_autoptr (GDataInputStream) data_input_stream = NULL;
|
|
gboolean terminal_attributes_changed = FALSE;
|
|
struct termios terminal_attributes;
|
|
g_autofree char *input = NULL;
|
|
gboolean success;
|
|
int output_fd;
|
|
int input_fd;
|
|
|
|
input_fd = STDIN_FILENO;
|
|
output_fd = STDOUT_FILENO;
|
|
|
|
input_stream = g_unix_input_stream_new (input_fd, FALSE);
|
|
data_input_stream = g_data_input_stream_new (input_stream);
|
|
|
|
if (isatty (output_fd))
|
|
output_stream = g_unix_output_stream_new (output_fd, FALSE);
|
|
|
|
if (output_stream)
|
|
{
|
|
success = g_output_stream_write_all (output_stream, prompt, strlen (prompt), NULL, NULL, error);
|
|
if (!success)
|
|
return NULL;
|
|
|
|
if (prompt_type == PROMPT_TYPE_HIDDEN_TEXT && isatty (input_fd))
|
|
{
|
|
struct termios updated_terminal_attributes;
|
|
int ret;
|
|
|
|
ret = tcgetattr (input_fd, &terminal_attributes);
|
|
if (ret < 0)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
"Could not query terminal attributes");
|
|
return NULL;
|
|
}
|
|
|
|
updated_terminal_attributes = terminal_attributes;
|
|
updated_terminal_attributes.c_lflag &= ~ECHO;
|
|
|
|
ret = tcsetattr (input_fd, TCSANOW, &updated_terminal_attributes);
|
|
if (ret < 0)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
"Could not disable input echo in terminal");
|
|
return NULL;
|
|
}
|
|
|
|
terminal_attributes_changed = TRUE;
|
|
}
|
|
}
|
|
|
|
input = g_data_input_stream_read_line_utf8 (data_input_stream, NULL, NULL, error);
|
|
|
|
if (terminal_attributes_changed)
|
|
{
|
|
g_output_stream_write_all (output_stream, "\n", strlen ("\n"), NULL, NULL, NULL);
|
|
tcsetattr (input_fd, TCSANOW, &terminal_attributes);
|
|
}
|
|
|
|
return g_steal_pointer (&input);
|
|
}
|
|
|
|
#ifdef HAVE_RDP
|
|
static gboolean
|
|
rdp_set_port (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
int port;
|
|
|
|
if (!is_numeric (argv[0]))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"The port must be an integer");
|
|
return FALSE;
|
|
}
|
|
|
|
port = strtol (argv[0], NULL, 10);
|
|
g_object_set (G_OBJECT (settings), "rdp-port", port, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_enable (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
GrdRuntimeMode runtime_mode = grd_settings_get_runtime_mode (settings);
|
|
|
|
if (!grd_toggle_systemd_unit (runtime_mode, TRUE, error))
|
|
return FALSE;
|
|
|
|
g_object_set (G_OBJECT (settings), "rdp-enabled", TRUE, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_disable (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
GrdRuntimeMode runtime_mode = grd_settings_get_runtime_mode (settings);
|
|
gboolean vnc_enabled;
|
|
|
|
g_object_set (G_OBJECT (settings), "rdp-enabled", FALSE, NULL);
|
|
|
|
g_object_get (G_OBJECT (settings), "vnc-enabled", &vnc_enabled, NULL);
|
|
if (!vnc_enabled)
|
|
return grd_toggle_systemd_unit (runtime_mode, FALSE, error);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_set_auth_methods (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
char *auth_methods_string = argv[0];
|
|
g_auto (GStrv) auth_method_strings = NULL;
|
|
char **auth_method;
|
|
GrdRdpAuthMethods auth_methods = 0;
|
|
|
|
auth_method_strings = g_strsplit (auth_methods_string, ",", -1);
|
|
for (auth_method = auth_method_strings; *auth_method; auth_method++)
|
|
{
|
|
if (g_strcmp0 (*auth_method, "credentials") == 0)
|
|
{
|
|
auth_methods |= GRD_RDP_AUTH_METHOD_CREDENTIALS;
|
|
}
|
|
else if (g_strcmp0 (*auth_method, "kerberos") == 0)
|
|
{
|
|
auth_methods |= GRD_RDP_AUTH_METHOD_KERBEROS;
|
|
}
|
|
else
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Invalid auth method '%s'", *auth_method);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!auth_methods)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"No auth method selected");
|
|
return FALSE;
|
|
}
|
|
|
|
if ((auth_methods & GRD_RDP_AUTH_METHOD_KERBEROS) &&
|
|
GRD_IS_SETTINGS_SYSTEM (settings))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Kerberos not supported in the system daemon");
|
|
return FALSE;
|
|
}
|
|
|
|
g_object_set (G_OBJECT (settings), "rdp-auth-methods", auth_methods, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_set_tls_cert (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
char *path = argv[0];
|
|
|
|
if (!g_path_is_absolute (path))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Path to certificate file not absolute");
|
|
return FALSE;
|
|
}
|
|
|
|
g_object_set (G_OBJECT (settings), "rdp-server-cert-path", argv[0], NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_set_tls_key (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
char *path = argv[0];
|
|
|
|
if (!g_path_is_absolute (path))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Path to certificate file not absolute");
|
|
return FALSE;
|
|
}
|
|
|
|
g_object_set (G_OBJECT (settings), "rdp-server-key-path", argv[0], NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_set_kerberos_keytab (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
char *path = argv[0];
|
|
|
|
if (GRD_IS_SETTINGS_SYSTEM (settings))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Kerberos not supported in the system daemon");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!g_path_is_absolute (path))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Path to certificate file not absolute");
|
|
return FALSE;
|
|
}
|
|
|
|
g_object_set (G_OBJECT (settings), "rdp-kerberos-keytab", argv[0], NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_set_credentials (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_autofree char *username = NULL;
|
|
g_autofree char *password = NULL;
|
|
|
|
if (argc < 1)
|
|
{
|
|
username = prompt_for_input (_("Username: "), PROMPT_TYPE_VISIBLE_TEXT,
|
|
error);
|
|
if (!username)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
username = g_strdup (argv[0]);
|
|
}
|
|
|
|
if (argc < 2)
|
|
{
|
|
password = prompt_for_input (_("Password: "), PROMPT_TYPE_HIDDEN_TEXT,
|
|
error);
|
|
if (!password)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
password = g_strdup (argv[1]);
|
|
}
|
|
|
|
return grd_settings_set_rdp_credentials (settings, username, password, error);
|
|
}
|
|
|
|
static gboolean
|
|
rdp_clear_credentials (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
return grd_settings_clear_rdp_credentials (settings, error);
|
|
}
|
|
|
|
static gboolean
|
|
rdp_enable_view_only (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_object_set (G_OBJECT (settings), "rdp-view-only", TRUE, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_disable_view_only (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_object_set (G_OBJECT (settings), "rdp-view-only", FALSE, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_enable_port_negotiation (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_object_set (G_OBJECT (settings), "rdp-negotiate-port", TRUE, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
rdp_disable_port_negotiation (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_object_set (G_OBJECT (settings), "rdp-negotiate-port", FALSE, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static const SubCommand rdp_subcommands[] = {
|
|
{ "set-port", rdp_set_port, 1 },
|
|
{ "enable", rdp_enable, 0 },
|
|
{ "disable", rdp_disable, 0 },
|
|
{ "set-auth-methods", rdp_set_auth_methods, 1 },
|
|
{ "set-tls-cert", rdp_set_tls_cert, 1 },
|
|
{ "set-tls-key", rdp_set_tls_key, 1 },
|
|
{ "set-kerberos-keytab", rdp_set_kerberos_keytab, 1 },
|
|
{ "set-credentials", rdp_set_credentials, 0 },
|
|
{ "set-credentials", rdp_set_credentials, 1 },
|
|
{ "set-credentials", rdp_set_credentials, 2 },
|
|
{ "clear-credentials", rdp_clear_credentials, 0 },
|
|
{ "enable-view-only", rdp_enable_view_only, 0 },
|
|
{ "disable-view-only", rdp_disable_view_only, 0 },
|
|
{ "enable-port-negotiation", rdp_enable_port_negotiation, 0 },
|
|
{ "disable-port-negotiation", rdp_disable_port_negotiation, 0 },
|
|
};
|
|
|
|
static int
|
|
process_rdp_options (GrdSettings *settings,
|
|
int argc,
|
|
char **argv)
|
|
{
|
|
return process_options (settings,
|
|
argc, argv,
|
|
rdp_subcommands,
|
|
G_N_ELEMENTS (rdp_subcommands));
|
|
}
|
|
#endif /* HAVE_RDP */
|
|
|
|
#ifdef HAVE_VNC
|
|
static gboolean
|
|
vnc_set_port (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
int port;
|
|
|
|
if (!is_numeric (argv[0]))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"The port must be an integer");
|
|
return FALSE;
|
|
}
|
|
|
|
port = strtol (argv[0], NULL, 10);
|
|
g_object_set (G_OBJECT (settings), "vnc-port", port, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
vnc_enable (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
GrdRuntimeMode runtime_mode = grd_settings_get_runtime_mode (settings);
|
|
|
|
if (!grd_toggle_systemd_unit (runtime_mode, TRUE, error))
|
|
return FALSE;
|
|
|
|
g_object_set (G_OBJECT (settings), "vnc-enabled", TRUE, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
vnc_disable (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
GrdRuntimeMode runtime_mode = grd_settings_get_runtime_mode (settings);
|
|
gboolean rdp_enabled;
|
|
|
|
g_object_set (G_OBJECT (settings), "vnc-enabled", FALSE, NULL);
|
|
|
|
g_object_get (G_OBJECT (settings), "rdp-enabled", &rdp_enabled, NULL);
|
|
if (!rdp_enabled)
|
|
return grd_toggle_systemd_unit (runtime_mode, FALSE, error);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#define MAX_VNC_PASSWORD_SIZE 8
|
|
|
|
static gboolean
|
|
vnc_set_credentials (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_autofree char *password = NULL;
|
|
|
|
if (argc < 1)
|
|
{
|
|
password = prompt_for_input (_("Password: "), PROMPT_TYPE_HIDDEN_TEXT,
|
|
error);
|
|
if (!password)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
password = g_strdup (argv[0]);
|
|
}
|
|
|
|
if (strlen (password) > MAX_VNC_PASSWORD_SIZE)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
|
"Password is too long");
|
|
return FALSE;
|
|
}
|
|
|
|
return grd_settings_set_vnc_password (settings, password, error);
|
|
}
|
|
|
|
static gboolean
|
|
vnc_clear_credentials (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
return grd_settings_clear_vnc_password (settings, error);
|
|
}
|
|
|
|
static gboolean
|
|
vnc_set_auth_method (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
char *auth_method = argv[0];
|
|
|
|
if (strcmp (auth_method, "prompt") == 0)
|
|
{
|
|
g_object_set (G_OBJECT (settings),
|
|
"vnc-auth-method", GRD_VNC_AUTH_METHOD_PROMPT,
|
|
NULL);
|
|
return TRUE;
|
|
}
|
|
else if (strcmp (auth_method, "password") == 0)
|
|
{
|
|
g_object_set (G_OBJECT (settings),
|
|
"vnc-auth-method", GRD_VNC_AUTH_METHOD_PASSWORD,
|
|
NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
|
"Invalid auth method '%s'", auth_method);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
vnc_enable_view_only (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_object_set (G_OBJECT (settings), "vnc-view-only", TRUE, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
vnc_disable_view_only (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_object_set (G_OBJECT (settings), "vnc-view-only", FALSE, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
vnc_enable_port_negotiation (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_object_set (G_OBJECT (settings), "vnc-negotiate-port", TRUE, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
vnc_disable_port_negotiation (GrdSettings *settings,
|
|
int argc,
|
|
char **argv,
|
|
GError **error)
|
|
{
|
|
g_object_set (G_OBJECT (settings), "vnc-negotiate-port", FALSE, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static const SubCommand vnc_subcommands[] = {
|
|
{ "set-port", vnc_set_port, 1 },
|
|
{ "enable", vnc_enable, 0 },
|
|
{ "disable", vnc_disable, 0 },
|
|
{ "set-password", vnc_set_credentials, 0 },
|
|
{ "set-password", vnc_set_credentials, 1 },
|
|
{ "clear-password", vnc_clear_credentials, 0 },
|
|
{ "set-auth-method", vnc_set_auth_method, 1 },
|
|
{ "enable-view-only", vnc_enable_view_only, 0 },
|
|
{ "disable-view-only", vnc_disable_view_only, 0 },
|
|
{ "enable-port-negotiation", vnc_enable_port_negotiation, 0 },
|
|
{ "disable-port-negotiation", vnc_disable_port_negotiation, 0 },
|
|
};
|
|
|
|
static int
|
|
process_vnc_options (GrdSettings *settings,
|
|
int argc,
|
|
char **argv)
|
|
{
|
|
return process_options (settings,
|
|
argc, argv,
|
|
vnc_subcommands,
|
|
G_N_ELEMENTS (vnc_subcommands));
|
|
}
|
|
#endif /* HAVE_VNC */
|
|
|
|
static void
|
|
print_help (void)
|
|
{
|
|
/* For translators: First line of --help after usage line */
|
|
const char *help_header =
|
|
_("Commands:\n");
|
|
#ifdef HAVE_RDP
|
|
/* For translators: This first words on each line is the command;
|
|
* don't translate. Try to fit each line within 80 characters. */
|
|
const char *help_rdp =
|
|
_(" rdp - RDP subcommands:\n"
|
|
" set-port - Set port the server binds to\n"
|
|
" enable - Enable the RDP backend\n"
|
|
" disable - Disable the RDP backend\n"
|
|
" set-auth-methods <list-of-methods> - Set a comma separated list of\n"
|
|
" allowed authentication methods\n"
|
|
" (credentials, kerberos)\n"
|
|
" set-tls-cert <path-to-cert> - Set path to TLS certificate\n"
|
|
" set-tls-key <path-to-key> - Set path to TLS key\n"
|
|
" set-kerberos-keytab <path-to-keytab> - Set path to a Kerberos keytab\n"
|
|
" set-credentials [<username> [<password>]] - Set username and password\n"
|
|
" credentials\n"
|
|
" clear-credentials - Clear username and password\n"
|
|
" credentials\n"
|
|
" enable-view-only - Disable remote control of input\n"
|
|
" devices\n"
|
|
" disable-view-only - Enable remote control of input\n"
|
|
" devices\n"
|
|
" enable-port-negotiation - If unavailable, listen to\n"
|
|
" a different port\n"
|
|
" disable-port-negotiation - If unavailable, don't listen\n"
|
|
" to a different port\n"
|
|
"\n");
|
|
#endif /* HAVE_RDP */
|
|
#ifdef HAVE_VNC
|
|
/* For translators: This first words on each line is the command;
|
|
* don't translate. Try to fit each line within 80 characters. */
|
|
const char *help_vnc =
|
|
_(" vnc - VNC subcommands:\n"
|
|
" set-port - Set port the server binds to\n"
|
|
" enable - Enable the VNC backend\n"
|
|
" disable - Disable the VNC backend\n"
|
|
" set-password [<password>] - Set the VNC password\n"
|
|
" clear-password - Clear the VNC password\n"
|
|
" set-auth-method password|prompt - Set the authorization method\n"
|
|
" enable-view-only - Disable remote control of input\n"
|
|
" devices\n"
|
|
" disable-view-only - Enable remote control of input\n"
|
|
" devices\n"
|
|
" enable-port-negotiation - If unavailable, listen to\n"
|
|
" a different port\n"
|
|
" disable-port-negotiation - If unavailable, don't listen\n"
|
|
" to a different port\n"
|
|
"\n");
|
|
#endif /* HAVE_VNC */
|
|
/* For translators: This first words on each line is the command;
|
|
* don't translate. Try to fit each line within 80 characters. */
|
|
const char *help_other =
|
|
_(" status [--show-credentials] - Show current status\n"
|
|
"\n"
|
|
"Options:\n"
|
|
" --headless - Configure headless daemon\n"
|
|
" running on a user session\n"
|
|
" --system - Configure system daemon\n"
|
|
" for remote login\n"
|
|
" --help - Print this help text\n");
|
|
|
|
print_usage ();
|
|
printf ("%s"
|
|
#ifdef HAVE_RDP
|
|
"%s"
|
|
#endif
|
|
#ifdef HAVE_VNC
|
|
"%s"
|
|
#endif
|
|
"%s",
|
|
help_header,
|
|
#ifdef HAVE_RDP
|
|
help_rdp,
|
|
#endif
|
|
#ifdef HAVE_VNC
|
|
help_vnc,
|
|
#endif
|
|
help_other);
|
|
}
|
|
|
|
static GrdSettings *
|
|
create_settings (GrdRuntimeMode runtime_mode)
|
|
{
|
|
switch (runtime_mode)
|
|
{
|
|
case GRD_RUNTIME_MODE_SCREEN_SHARE:
|
|
return GRD_SETTINGS (grd_settings_user_new ());
|
|
case GRD_RUNTIME_MODE_HEADLESS:
|
|
return GRD_SETTINGS (grd_settings_headless_new ());
|
|
case GRD_RUNTIME_MODE_SYSTEM:
|
|
return GRD_SETTINGS (grd_settings_system_new ());
|
|
case GRD_RUNTIME_MODE_HANDOVER:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
static const char *
|
|
status_to_string (gboolean enabled,
|
|
gboolean use_colors)
|
|
{
|
|
if (use_colors)
|
|
{
|
|
if (enabled)
|
|
return "\x1b[1menabled\033[m";
|
|
else
|
|
return "\x1b[1mdisabled\033[m";
|
|
}
|
|
else
|
|
{
|
|
if (enabled)
|
|
return "enabled";
|
|
else
|
|
return "disabled";
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_RDP
|
|
|
|
static char *
|
|
generate_auth_methods_string (GrdRdpAuthMethods auth_methods)
|
|
{
|
|
g_autoptr (GStrvBuilder) builder = NULL;
|
|
g_auto (GStrv) auth_method_strings = NULL;
|
|
|
|
builder = g_strv_builder_new ();
|
|
if (auth_methods & GRD_RDP_AUTH_METHOD_CREDENTIALS)
|
|
g_strv_builder_add (builder, "credentials");
|
|
if (auth_methods & GRD_RDP_AUTH_METHOD_KERBEROS)
|
|
g_strv_builder_add (builder, "kerberos");
|
|
|
|
auth_method_strings = g_strv_builder_end (builder);
|
|
|
|
return g_strjoinv (", ", auth_method_strings);
|
|
}
|
|
|
|
static void
|
|
print_rdp_status (GrdSettings *settings,
|
|
gboolean use_colors,
|
|
gboolean show_credentials)
|
|
{
|
|
GrdRdpAuthMethods auth_methods = 0;
|
|
g_autofree char *auth_methods_string = NULL;
|
|
g_autofree char *tls_fingerprint = NULL;
|
|
g_autofree char *tls_cert = NULL;
|
|
g_autofree char *tls_key = NULL;
|
|
g_autofree char *kerberos_keytab = NULL;
|
|
g_autofree char *username = NULL;
|
|
g_autofree char *password = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
gboolean negotiate_port;
|
|
gboolean view_only;
|
|
gboolean enabled;
|
|
int port;
|
|
|
|
g_object_get (G_OBJECT (settings),
|
|
"rdp-auth-methods", &auth_methods,
|
|
"rdp-server-fingerprint", &tls_fingerprint,
|
|
"rdp-server-cert-path", &tls_cert,
|
|
"rdp-server-key-path", &tls_key,
|
|
"rdp-kerberos-keytab", &kerberos_keytab,
|
|
"rdp-negotiate-port", &negotiate_port,
|
|
"rdp-view-only", &view_only,
|
|
"rdp-enabled", &enabled,
|
|
"rdp-port", &port,
|
|
NULL);
|
|
|
|
auth_methods_string = generate_auth_methods_string (auth_methods);
|
|
|
|
printf ("RDP:\n");
|
|
printf ("\tStatus: %s\n", status_to_string (enabled, use_colors));
|
|
printf ("\tPort: %d\n", port);
|
|
printf ("\tAuthentication methods: %s\n", auth_methods_string);
|
|
printf ("\tTLS certificate: %s\n", tls_cert);
|
|
printf ("\tTLS fingerprint: %s\n", tls_fingerprint);
|
|
printf ("\tTLS key: %s\n", tls_key);
|
|
printf ("\tKerberos keytab: %s\n", kerberos_keytab);
|
|
if (!GRD_IS_SETTINGS_SYSTEM (settings) && !GRD_IS_SETTINGS_HEADLESS (settings))
|
|
printf ("\tView-only: %s\n", view_only ? "yes" : "no");
|
|
if (!GRD_IS_SETTINGS_SYSTEM (settings))
|
|
printf ("\tNegotiate port: %s\n", negotiate_port ? "yes" : "no");
|
|
|
|
grd_settings_get_rdp_credentials (settings,
|
|
&username, &password,
|
|
&error);
|
|
if (error)
|
|
{
|
|
fprintf (stderr, "Failed to read credentials: %s.\n", error->message);
|
|
return;
|
|
}
|
|
|
|
if (show_credentials)
|
|
{
|
|
printf ("\tUsername: %s\n", username);
|
|
printf ("\tPassword: %s\n", password);
|
|
}
|
|
else
|
|
{
|
|
printf ("\tUsername: %s\n",
|
|
(username && strlen (username) > 1) ? "(hidden)" : "(empty)");
|
|
printf ("\tPassword: %s\n",
|
|
(password && strlen (password) > 1) ? "(hidden)" : "(empty)");
|
|
}
|
|
}
|
|
#endif /* HAVE_RDP */
|
|
|
|
#ifdef HAVE_VNC
|
|
static void
|
|
print_vnc_status (GrdSettings *settings,
|
|
gboolean use_colors,
|
|
gboolean show_credentials)
|
|
{
|
|
int port;
|
|
gboolean enabled;
|
|
gboolean view_only;
|
|
gboolean negotiate_port;
|
|
GrdVncAuthMethod auth_method;
|
|
g_autofree char *password = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
g_object_get (G_OBJECT (settings),
|
|
"vnc-port", &port,
|
|
"vnc-enabled", &enabled,
|
|
"vnc-view-only", &view_only,
|
|
"vnc-auth-method", &auth_method,
|
|
"vnc-negotiate-port", &negotiate_port,
|
|
NULL);
|
|
|
|
password = grd_settings_get_vnc_password (settings, &error);
|
|
if (error)
|
|
{
|
|
fprintf (stderr, "Failed to lookup VNC credentials: %s\n", error->message);
|
|
return;
|
|
}
|
|
|
|
printf ("VNC:\n");
|
|
printf ("\tStatus: %s\n", status_to_string (enabled, use_colors));
|
|
|
|
printf ("\tPort: %d\n", port);
|
|
if (!GRD_IS_SETTINGS_HEADLESS (settings))
|
|
{
|
|
if (auth_method == GRD_VNC_AUTH_METHOD_PROMPT)
|
|
printf ("\tAuth method: prompt\n");
|
|
else if (auth_method == GRD_VNC_AUTH_METHOD_PASSWORD)
|
|
printf ("\tAuth method: password\n");
|
|
}
|
|
if (!GRD_IS_SETTINGS_HEADLESS (settings))
|
|
printf ("\tView-only: %s\n", view_only ? "yes" : "no");
|
|
printf ("\tNegotiate port: %s\n", negotiate_port ? "yes" : "no");
|
|
if (show_credentials)
|
|
{
|
|
printf ("\tPassword: %s\n", password);
|
|
}
|
|
else
|
|
{
|
|
printf ("\tPassword: %s\n",
|
|
(password && strlen (password) > 1) ? "(hidden)" : "(empty)");
|
|
}
|
|
}
|
|
#endif /* HAVE_VNC */
|
|
|
|
static char *
|
|
unit_active_state_to_string (GrdSystemdUnitActiveState active_state,
|
|
gboolean use_colors)
|
|
{
|
|
char *state = "";
|
|
|
|
switch (active_state)
|
|
{
|
|
case GRD_SYSTEMD_UNIT_ACTIVE_STATE_ACTIVE:
|
|
state = "active";
|
|
break;
|
|
case GRD_SYSTEMD_UNIT_ACTIVE_STATE_RELOADING:
|
|
state = "reloading";
|
|
break;
|
|
case GRD_SYSTEMD_UNIT_ACTIVE_STATE_INACTIVE:
|
|
state = "inactive";
|
|
break;
|
|
case GRD_SYSTEMD_UNIT_ACTIVE_STATE_FAILED:
|
|
state = "failed";
|
|
break;
|
|
case GRD_SYSTEMD_UNIT_ACTIVE_STATE_ACTIVATING:
|
|
state = "activating";
|
|
break;
|
|
case GRD_SYSTEMD_UNIT_ACTIVE_STATE_DEACTIVATING:
|
|
state = "deactivating";
|
|
break;
|
|
case GRD_SYSTEMD_UNIT_ACTIVE_STATE_UNKNOWN:
|
|
state = "unknown";
|
|
break;
|
|
}
|
|
|
|
if (use_colors)
|
|
return g_strdup_printf ("\x1b[1m%s\033[m", state);
|
|
else
|
|
return g_strdup (state);
|
|
}
|
|
|
|
static void
|
|
print_service_status (GrdSettings *settings,
|
|
gboolean use_colors)
|
|
{
|
|
GBusType bus_type;
|
|
GrdSystemdUnitActiveState active_state;
|
|
g_autofree char *active_state_str = NULL;
|
|
g_autoptr (GDBusProxy) unit_proxy = NULL;
|
|
const char *unit;
|
|
|
|
switch (grd_settings_get_runtime_mode (settings))
|
|
{
|
|
case GRD_RUNTIME_MODE_HEADLESS:
|
|
bus_type = G_BUS_TYPE_SESSION;
|
|
unit = GRD_SYSTEMD_HEADLESS_SERVICE;
|
|
break;
|
|
case GRD_RUNTIME_MODE_SYSTEM:
|
|
bus_type = G_BUS_TYPE_SYSTEM;
|
|
unit = GRD_SYSTEMD_SERVICE;
|
|
break;
|
|
case GRD_RUNTIME_MODE_SCREEN_SHARE:
|
|
bus_type = G_BUS_TYPE_SESSION;
|
|
unit = GRD_SYSTEMD_SERVICE;
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
if (!grd_systemd_get_unit (bus_type,
|
|
unit,
|
|
&unit_proxy,
|
|
NULL))
|
|
return;
|
|
|
|
if (!grd_systemd_unit_get_active_state (unit_proxy,
|
|
&active_state,
|
|
NULL))
|
|
return;
|
|
|
|
active_state_str = unit_active_state_to_string (active_state, use_colors);
|
|
|
|
printf ("Overall:\n");
|
|
printf ("\tUnit status: %s\n", active_state_str);
|
|
}
|
|
|
|
static int
|
|
print_status (GrdSettings *settings,
|
|
int argc,
|
|
char **argv)
|
|
{
|
|
gboolean use_colors;
|
|
gboolean show_credentials = FALSE;
|
|
|
|
if (argc > 1)
|
|
{
|
|
return EX_USAGE;
|
|
}
|
|
else if (argc == 1)
|
|
{
|
|
if (strcmp (argv[0], "--show-credentials") == 0)
|
|
{
|
|
show_credentials = TRUE;
|
|
}
|
|
else
|
|
{
|
|
return EX_USAGE;
|
|
}
|
|
}
|
|
|
|
use_colors = isatty (fileno (stdout));
|
|
|
|
print_service_status (settings, use_colors);
|
|
|
|
#ifdef HAVE_RDP
|
|
print_rdp_status (settings, use_colors, show_credentials);
|
|
#endif /* HAVE_RDP */
|
|
#ifdef HAVE_VNC
|
|
if (!GRD_IS_SETTINGS_SYSTEM (settings))
|
|
print_vnc_status (settings, use_colors, show_credentials);
|
|
#endif /* HAVE_VNC */
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int
|
|
main (int argc,
|
|
char *argv[])
|
|
{
|
|
g_autoptr (GrdSettings) settings = NULL;
|
|
GrdRuntimeMode runtime_mode;
|
|
int i;
|
|
int arg_shift;
|
|
int exit_code = EX_USAGE;
|
|
struct passwd *pw;
|
|
|
|
g_set_prgname (argv[0]);
|
|
g_log_set_handler (NULL, G_LOG_LEVEL_WARNING, log_handler, NULL);
|
|
|
|
if (argc < 2)
|
|
goto done;
|
|
|
|
if (argc == 2 && strcmp (argv[1], "--help") == 0)
|
|
{
|
|
print_help ();
|
|
exit_code = EXIT_SUCCESS;
|
|
goto done;
|
|
}
|
|
|
|
if (argc > 2 && strcmp (argv[1], "--headless") == 0)
|
|
{
|
|
runtime_mode = GRD_RUNTIME_MODE_HEADLESS;
|
|
i = 2;
|
|
}
|
|
else if (argc > 1 && strcmp (argv[1], "--system") == 0)
|
|
{
|
|
runtime_mode = GRD_RUNTIME_MODE_SYSTEM;
|
|
i = 2;
|
|
}
|
|
else
|
|
{
|
|
runtime_mode = GRD_RUNTIME_MODE_SCREEN_SHARE;
|
|
i = 1;
|
|
}
|
|
|
|
arg_shift = i + 1;
|
|
|
|
if (runtime_mode == GRD_RUNTIME_MODE_SYSTEM)
|
|
{
|
|
g_autoptr (GStrvBuilder) builder = NULL;
|
|
g_auto (GStrv) new_argv = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
int wait_status;
|
|
int j;
|
|
|
|
builder = g_strv_builder_new ();
|
|
|
|
g_strv_builder_add (builder, "pkexec");
|
|
g_strv_builder_add (builder, "--user");
|
|
g_strv_builder_add (builder, GRD_USERNAME);
|
|
g_strv_builder_add (builder, argv[0]);
|
|
|
|
for (j = 2; j < argc; j++)
|
|
g_strv_builder_add (builder, argv[j]);
|
|
|
|
new_argv = g_strv_builder_end (builder);
|
|
|
|
g_spawn_sync (NULL,
|
|
new_argv,
|
|
NULL,
|
|
G_SPAWN_SEARCH_PATH
|
|
| G_SPAWN_CHILD_INHERITS_STDIN
|
|
| G_SPAWN_CHILD_INHERITS_STDOUT,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&wait_status,
|
|
&error);
|
|
if (error)
|
|
{
|
|
fprintf (stderr, "Failed to start the configuration of the system daemon: %s\n",
|
|
error->message);
|
|
|
|
if (WIFEXITED (wait_status))
|
|
exit_code = WEXITSTATUS (wait_status);
|
|
else
|
|
exit_code = EX_SOFTWARE;
|
|
}
|
|
else
|
|
{
|
|
exit_code = EXIT_SUCCESS;
|
|
}
|
|
|
|
goto done;
|
|
}
|
|
|
|
pw = getpwnam (GRD_USERNAME);
|
|
if (geteuid () == pw->pw_uid)
|
|
runtime_mode = GRD_RUNTIME_MODE_SYSTEM;
|
|
|
|
settings = create_settings (runtime_mode);
|
|
if (!settings)
|
|
{
|
|
fprintf (stderr, "Failed to initialize settings.\n");
|
|
exit_code = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
#ifdef HAVE_RDP
|
|
if (strcmp (argv[i], "rdp") == 0)
|
|
{
|
|
exit_code = process_rdp_options (settings,
|
|
argc - arg_shift, argv + arg_shift);
|
|
goto done;
|
|
}
|
|
#endif
|
|
#ifdef HAVE_VNC
|
|
if (strcmp (argv[i], "vnc") == 0)
|
|
{
|
|
exit_code = process_vnc_options (settings,
|
|
argc - arg_shift, argv + arg_shift);
|
|
goto done;
|
|
}
|
|
#endif
|
|
|
|
if (strcmp (argv[i], "status") == 0)
|
|
{
|
|
exit_code = print_status (settings,
|
|
argc - arg_shift, argv + arg_shift);
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if (exit_code == EX_USAGE)
|
|
print_usage ();
|
|
|
|
return exit_code;
|
|
}
|