Compare commits

...

1 Commits

Author SHA1 Message Date
Alex Murray
e8fc4c4c56 sharing: check status of both sshd service and socket
Check the status of both the sshd service and socket
since either could be in use. Also when enabling remote access,
enable this via the socket rather than the service.

CVE-2023-5616
https://launchpad.net/bugs/2039577
2023-12-13 16:42:20 -05:00
2 changed files with 200 additions and 18 deletions

View File

@@ -25,6 +25,10 @@
#define SSHD_SERVICE "sshd.service"
#endif
#ifndef SSHD_SOCKET
#define SSHD_SOCKET "sshd.socket"
#endif
int
main (int argc,
char **argv)
@@ -39,11 +43,18 @@ main (int argc,
{
g_autoptr(GError) error = NULL;
if (!cc_enable_service (SSHD_SERVICE, G_BUS_TYPE_SYSTEM, &error))
/* on lunar+ we want to ensure the service is disabled and enable the
socket to match the default behaviour */
if (!cc_disable_service (SSHD_SERVICE, G_BUS_TYPE_SYSTEM, &error))
{
g_critical ("Failed to enable %s: %s", SSHD_SERVICE, error->message);
return EXIT_FAILURE;
}
else if (!cc_enable_service (SSHD_SOCKET, G_BUS_TYPE_SYSTEM, &error))
{
g_critical ("Failed to enable %s: %s", SSHD_SOCKET, error->message);
return EXIT_FAILURE;
}
else
{
return EXIT_SUCCESS;
@@ -55,7 +66,12 @@ main (int argc,
if (!cc_disable_service (SSHD_SERVICE, G_BUS_TYPE_SYSTEM, &error))
{
g_critical ("Failed to enable %s: %s", SSHD_SERVICE, error->message);
g_critical ("Failed to disable %s: %s", SSHD_SERVICE, error->message);
return EXIT_FAILURE;
}
else if (!cc_disable_service (SSHD_SOCKET, G_BUS_TYPE_SYSTEM, &error))
{
g_critical ("Failed to disable %s: %s", SSHD_SOCKET, error->message);
return EXIT_FAILURE;
}
else

View File

@@ -25,15 +25,80 @@
#define SSHD_SERVICE "sshd.service"
#endif
#ifndef SSHD_SOCKET
#define SSHD_SOCKET "sshd.socket"
#endif
typedef enum {
SYSTEMD_UNIT_UNKNOWN,
SYSTEMD_UNIT_SSHD_SERVICE,
SYSTEMD_UNIT_SSHD_SOCKET,
} SystemdUnit;
typedef enum {
SYSTEMD_SERVICE_STATE_UNKNOWN,
SYSTEMD_SERVICE_STATE_DISABLED,
SYSTEMD_SERVICE_STATE_ENABLED_AND_ACTIVE,
} SystemdServiceState;
typedef struct
{
SystemdUnit unit;
SystemdServiceState state;
} SystemdService;
#define CONTAINER_OF(ptr, type, member) \
((type *) ((guint8 *) (ptr) - G_STRUCT_OFFSET (type, member)))
#define SYSTEMD_SERVICE_UNIT_NAME(service) \
((service)->unit == SYSTEMD_UNIT_SSHD_SERVICE ? SSHD_SERVICE : \
(service)->unit == SYSTEMD_UNIT_SSHD_SOCKET ? SSHD_SOCKET : "UNKNOWN")
typedef struct
{
AdwSwitchRow *widget;
GtkWidget *row;
GCancellable *cancellable;
SystemdService sshd_service;
SystemdService sshd_socket;
} CallbackData;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (CallbackData, g_free)
static void
systemd_service_cleanup (SystemdService *service)
{
CallbackData *callback_data;
if (service->unit == SYSTEMD_UNIT_SSHD_SERVICE)
{
callback_data = CONTAINER_OF (service, CallbackData, sshd_service);
}
else if (service->unit == SYSTEMD_UNIT_SSHD_SOCKET)
{
callback_data = CONTAINER_OF (service, CallbackData, sshd_socket);
}
else
{
g_assert_not_reached ();
}
service->unit = SYSTEMD_UNIT_UNKNOWN;
if (callback_data->sshd_service.unit == SYSTEMD_UNIT_UNKNOWN &&
callback_data->sshd_socket.unit == SYSTEMD_UNIT_UNKNOWN)
{
g_free(callback_data);
}
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SystemdService, systemd_service_cleanup)
static void
state_ready_callback (GObject *source_object,
GAsyncResult *result,
gpointer user_data);
static void
set_switch_state (AdwSwitchRow *widget,
gboolean active)
@@ -52,7 +117,8 @@ active_state_ready_callback (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(CallbackData) callback_data = user_data;
CallbackData *callback_data;
g_autoptr(SystemdService) service = user_data;
g_autoptr(GVariant) active_variant = NULL;
g_autoptr(GVariant) child_variant = NULL;
g_autoptr(GVariant) tmp_variant = NULL;
@@ -75,15 +141,51 @@ active_state_ready_callback (GObject *source_object,
return;
}
if (service->unit == SYSTEMD_UNIT_SSHD_SERVICE)
{
callback_data = CONTAINER_OF (service, CallbackData, sshd_service);
}
else if (service->unit == SYSTEMD_UNIT_SSHD_SOCKET)
{
callback_data = CONTAINER_OF (service, CallbackData, sshd_socket);
}
else
{
g_assert_not_reached ();
}
child_variant = g_variant_get_child_value (active_variant, 0);
tmp_variant = g_variant_get_variant (child_variant);
active_state = g_variant_get_string (tmp_variant, NULL);
active = g_str_equal (active_state, "active");
/* set the switch to the correct state */
if (callback_data->widget)
set_switch_state (callback_data->widget, active);
if (active)
{
g_debug ("%s is active...", SYSTEMD_SERVICE_UNIT_NAME (service));
service->state = SYSTEMD_SERVICE_STATE_ENABLED_AND_ACTIVE;
}
else
{
g_debug ("%s is not active...", SYSTEMD_SERVICE_UNIT_NAME (service));
service->state = SYSTEMD_SERVICE_STATE_DISABLED;
}
/* if we now have states for both the service and the socket, then we can
* set the switch state */
if (callback_data->sshd_service.state != SYSTEMD_SERVICE_STATE_UNKNOWN &&
callback_data->sshd_socket.state != SYSTEMD_SERVICE_STATE_UNKNOWN)
{
gboolean active = (callback_data->sshd_service.state == SYSTEMD_SERVICE_STATE_ENABLED_AND_ACTIVE ||
callback_data->sshd_socket.state == SYSTEMD_SERVICE_STATE_ENABLED_AND_ACTIVE);
/* set the switch to the correct state */
if (callback_data->widget)
{
g_debug ("Setting switch state for %s: %d", SYSTEMD_SERVICE_UNIT_NAME (service), active);
set_switch_state (callback_data->widget, active);
}
}
}
static void
@@ -91,12 +193,26 @@ path_ready_callback (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(CallbackData) callback_data = user_data;
CallbackData *callback_data;
g_autoptr(SystemdService) service = user_data;
g_autoptr(GVariant) path_variant = NULL;
g_autoptr(GVariant) child_variant = NULL;
const gchar *object_path;
g_autoptr(GError) error = NULL;
if (service->unit == SYSTEMD_UNIT_SSHD_SERVICE)
{
callback_data = CONTAINER_OF (service, CallbackData, sshd_service);
}
else if (service->unit == SYSTEMD_UNIT_SSHD_SOCKET)
{
callback_data = CONTAINER_OF (service, CallbackData, sshd_socket);
}
else
{
g_assert_not_reached ();
}
path_variant = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
result, &error);
@@ -131,8 +247,8 @@ path_ready_callback (GObject *source_object,
-1,
callback_data->cancellable,
active_state_ready_callback,
callback_data);
g_steal_pointer (&callback_data);
service);
g_steal_pointer (&service);
}
static void
@@ -140,12 +256,26 @@ state_ready_callback (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(CallbackData) callback_data = user_data;
CallbackData *callback_data;
g_autoptr(SystemdService) service = user_data;
g_autoptr(GVariant) state_variant = NULL;
g_autoptr(GVariant) child_variant = NULL;
const gchar *state_string;
g_autoptr(GError) error = NULL;
if (service->unit == SYSTEMD_UNIT_SSHD_SERVICE)
{
callback_data = CONTAINER_OF (service, CallbackData, sshd_service);
}
else if (service->unit == SYSTEMD_UNIT_SSHD_SOCKET)
{
callback_data = CONTAINER_OF (service, CallbackData, sshd_socket);
}
else
{
g_assert_not_reached ();
}
state_variant = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
result, &error);
if (!state_variant)
@@ -156,9 +286,13 @@ state_ready_callback (GObject *source_object,
/* this may fail if systemd or remote login service is not available */
g_debug ("Error getting remote login state: %s", error->message);
/* hide the remote login row, since the service is not available */
if (callback_data->row)
gtk_widget_set_visible (callback_data->row, FALSE);
{
g_debug ("Setting widget visibility FALSE for %s", SYSTEMD_SERVICE_UNIT_NAME (service));
gtk_widget_set_visible (callback_data->row, FALSE);
}
return;
}
@@ -168,30 +302,46 @@ state_ready_callback (GObject *source_object,
if (g_str_equal (state_string, "enabled"))
{
g_debug ("%s is enabled - checking if running...", SYSTEMD_SERVICE_UNIT_NAME (service));
/* service is enabled, so check whether it is running or not */
g_dbus_connection_call (G_DBUS_CONNECTION (source_object),
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"GetUnit",
g_variant_new ("(s)", SSHD_SERVICE),
g_variant_new ("(s)", SYSTEMD_SERVICE_UNIT_NAME (service)),
(GVariantType*) "(o)",
G_DBUS_CALL_FLAGS_NONE,
-1,
callback_data->cancellable,
path_ready_callback,
callback_data);
g_steal_pointer (&callback_data);
service);
g_steal_pointer (&service);
}
else if (g_str_equal (state_string, "disabled"))
{
/* service is available, but is currently disabled */
set_switch_state (callback_data->widget, FALSE);
g_debug ("%s is disabled...", SYSTEMD_SERVICE_UNIT_NAME (service));
service->state = SYSTEMD_SERVICE_STATE_DISABLED;
/* if we now have states for both the service and the socket, then we can
* set the switch state */
if (callback_data->sshd_service.state != SYSTEMD_SERVICE_STATE_UNKNOWN &&
callback_data->sshd_socket.state != SYSTEMD_SERVICE_STATE_UNKNOWN)
{
gboolean active = (callback_data->sshd_service.state == SYSTEMD_SERVICE_STATE_ENABLED_AND_ACTIVE ||
callback_data->sshd_socket.state == SYSTEMD_SERVICE_STATE_ENABLED_AND_ACTIVE);
/* set the switch to the correct state */
if (callback_data->widget)
{
g_debug ("Setting switch state for %s: %d", SYSTEMD_SERVICE_UNIT_NAME (service), active);
set_switch_state (callback_data->widget, active);
}
}
}
else
{
/* unknown state */
g_warning ("Unknown state %s for %s", state_string, SSHD_SERVICE);
g_warning ("Unknown state %s for %s", state_string, SYSTEMD_SERVICE_UNIT_NAME (service));
}
}
@@ -225,7 +375,19 @@ bus_ready_callback (GObject *source_object,
-1,
callback_data->cancellable,
state_ready_callback,
callback_data);
&callback_data->sshd_service);
g_dbus_connection_call (connection,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"GetUnitFileState",
g_variant_new ("(s)", SSHD_SOCKET),
(GVariantType*) "(s)",
G_DBUS_CALL_FLAGS_NONE,
-1,
callback_data->cancellable,
state_ready_callback,
&callback_data->sshd_socket);
g_steal_pointer (&callback_data);
}
@@ -243,6 +405,10 @@ cc_remote_login_get_enabled (GCancellable *cancellable,
callback_data->widget = widget;
callback_data->row = row;
callback_data->cancellable = cancellable;
callback_data->sshd_service.unit = SYSTEMD_UNIT_SSHD_SERVICE;
callback_data->sshd_service.state = SYSTEMD_SERVICE_STATE_UNKNOWN;
callback_data->sshd_socket.unit = SYSTEMD_UNIT_SSHD_SOCKET;
callback_data->sshd_socket.state = SYSTEMD_SERVICE_STATE_UNKNOWN;
g_bus_get (G_BUS_TYPE_SYSTEM, callback_data->cancellable,
bus_ready_callback, callback_data);