Thunderbolt devices need to be approved before they can be used. This is done via the boltd system daemon and gnome-shell. The new panel enables the user to manage thunderbolt devices, i.e.: - forget devices that have previously been authorized - authorize currently unauthorize devices Additionally authorization of devices an be temporarily disabled to ensure no evil device will gain access to the computers resources. File starting with "bolt-" are copied from bolt's source tree and currently correspond to the bolt upstream commit with the id f22b1cd6104bdc2b33a95d9896b50f29a141b8d8 They can be updated from bolt via the update-from-bolt.sh script.
395 lines
9.3 KiB
C
395 lines
9.3 KiB
C
/*
|
|
* Copyright © 2017 Red Hat, Inc
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Authors:
|
|
* Christian J. Kellner <christian@kellner.me>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "bolt-enums.h"
|
|
#include "bolt-error.h"
|
|
|
|
#include <gio/gio.h>
|
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GFlagsClass, g_type_class_unref);
|
|
|
|
gboolean
|
|
bolt_enum_class_validate (GEnumClass *enum_class,
|
|
gint value,
|
|
GError **error)
|
|
{
|
|
const char *name;
|
|
gboolean oob;
|
|
|
|
if (enum_class == NULL)
|
|
{
|
|
name = g_type_name_from_class ((GTypeClass *) enum_class);
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"could not determine enum class for '%s'",
|
|
name);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
oob = value < enum_class->minimum || value > enum_class->maximum;
|
|
|
|
if (oob)
|
|
{
|
|
name = g_type_name_from_class ((GTypeClass *) enum_class);
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"enum value '%d' is out of bounds for '%s'",
|
|
value, name);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
bolt_enum_validate (GType enum_type,
|
|
gint value,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GEnumClass) klass = g_type_class_ref (enum_type);
|
|
return bolt_enum_class_validate (klass, value, error);
|
|
}
|
|
|
|
const char *
|
|
bolt_enum_to_string (GType enum_type,
|
|
gint value,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GEnumClass) klass = NULL;
|
|
GEnumValue *ev;
|
|
|
|
klass = g_type_class_ref (enum_type);
|
|
|
|
if (!bolt_enum_class_validate (klass, value, error))
|
|
return NULL;
|
|
|
|
ev = g_enum_get_value (klass, value);
|
|
return ev->value_nick;
|
|
}
|
|
|
|
gint
|
|
bolt_enum_from_string (GType enum_type,
|
|
const char *string,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GEnumClass) klass = NULL;
|
|
const char *name;
|
|
GEnumValue *ev;
|
|
|
|
klass = g_type_class_ref (enum_type);
|
|
|
|
if (klass == NULL)
|
|
{
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"could not determine enum class");
|
|
return -1;
|
|
}
|
|
|
|
if (string == NULL)
|
|
{
|
|
name = g_type_name_from_class ((GTypeClass *) klass);
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"empty string passed for enum class for '%s'",
|
|
name);
|
|
return -1;
|
|
}
|
|
|
|
ev = g_enum_get_value_by_nick (klass, string);
|
|
|
|
if (ev == NULL)
|
|
{
|
|
name = g_type_name (enum_type);
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"invalid string '%s' for enum '%s'", string, name);
|
|
return -1;
|
|
}
|
|
|
|
return ev->value;
|
|
}
|
|
|
|
char *
|
|
bolt_flags_class_to_string (GFlagsClass *flags_class,
|
|
guint value,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GString) str = NULL;
|
|
const char *name;
|
|
GFlagsValue *fv;
|
|
|
|
if (flags_class == NULL)
|
|
{
|
|
name = g_type_name_from_class ((GTypeClass *) flags_class);
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"could not determine flags class for '%s'",
|
|
name);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
fv = g_flags_get_first_value (flags_class, value);
|
|
if (fv == NULL)
|
|
{
|
|
if (value == 0)
|
|
return g_strdup ("");
|
|
|
|
name = g_type_name_from_class ((GTypeClass *) flags_class);
|
|
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"invalid value '%u' for flags '%s'", value, name);
|
|
return NULL;
|
|
}
|
|
|
|
value &= ~fv->value;
|
|
str = g_string_new (fv->value_nick);
|
|
|
|
while (value != 0 &&
|
|
(fv = g_flags_get_first_value (flags_class, value)) != NULL)
|
|
{
|
|
g_string_append (str, " | ");
|
|
g_string_append (str, fv->value_nick);
|
|
|
|
value &= ~fv->value;
|
|
}
|
|
|
|
if (value != 0)
|
|
{
|
|
name = g_type_name_from_class ((GTypeClass *) flags_class);
|
|
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"unhandled value '%u' for flags '%s'", value, name);
|
|
return NULL;
|
|
}
|
|
|
|
return g_string_free (g_steal_pointer (&str), FALSE);
|
|
}
|
|
|
|
gboolean
|
|
bolt_flags_class_from_string (GFlagsClass *flags_class,
|
|
const char *string,
|
|
guint *flags_out,
|
|
GError **error)
|
|
{
|
|
g_auto(GStrv) vals = NULL;
|
|
const char *name;
|
|
guint flags = 0;
|
|
|
|
if (flags_class == NULL)
|
|
{
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"could not determine flags class");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (string == NULL)
|
|
{
|
|
name = g_type_name_from_class ((GTypeClass *) flags_class);
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"empty string passed for flags class for '%s'",
|
|
name);
|
|
return FALSE;
|
|
}
|
|
|
|
vals = g_strsplit (string, "|", -1);
|
|
|
|
for (guint i = 0; vals[i]; i++)
|
|
{
|
|
GFlagsValue *fv;
|
|
char *nick;
|
|
|
|
nick = g_strstrip (vals[i]);
|
|
fv = g_flags_get_value_by_nick (flags_class, nick);
|
|
|
|
if (fv == NULL)
|
|
{
|
|
name = g_type_name_from_class ((GTypeClass *) flags_class);
|
|
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
|
"invalid flag '%s' for flags '%s'", string, name);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
flags |= fv->value;
|
|
}
|
|
|
|
if (flags_out != NULL)
|
|
*flags_out = flags;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
char *
|
|
bolt_flags_to_string (GType flags_type,
|
|
guint value,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GFlagsClass) klass = NULL;
|
|
|
|
klass = g_type_class_ref (flags_type);
|
|
return bolt_flags_class_to_string (klass, value, error);
|
|
}
|
|
|
|
gboolean
|
|
bolt_flags_from_string (GType flags_type,
|
|
const char *string,
|
|
guint *flags_out,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GFlagsClass) klass = NULL;
|
|
|
|
klass = g_type_class_ref (flags_type);
|
|
return bolt_flags_class_from_string (klass, string, flags_out, error);
|
|
}
|
|
|
|
gboolean
|
|
bolt_flags_update (guint from,
|
|
guint *to,
|
|
guint mask)
|
|
{
|
|
guint val;
|
|
gboolean chg;
|
|
|
|
g_return_val_if_fail (to != NULL, FALSE);
|
|
|
|
val = *to & ~mask; /* clear all bits in mask */
|
|
val = val | (from & mask); /* set all bits in from and mask */
|
|
chg = *to != val;
|
|
*to = val;
|
|
|
|
return chg;
|
|
}
|
|
|
|
const char *
|
|
bolt_status_to_string (BoltStatus status)
|
|
{
|
|
return bolt_enum_to_string (BOLT_TYPE_STATUS, status, NULL);
|
|
}
|
|
|
|
gboolean
|
|
bolt_status_is_authorized (BoltStatus status)
|
|
{
|
|
return status == BOLT_STATUS_AUTHORIZED ||
|
|
status == BOLT_STATUS_AUTHORIZED_SECURE ||
|
|
status == BOLT_STATUS_AUTHORIZED_NEWKEY;
|
|
}
|
|
|
|
gboolean
|
|
bolt_status_is_pending (BoltStatus status)
|
|
{
|
|
return status == BOLT_STATUS_AUTH_ERROR ||
|
|
status == BOLT_STATUS_CONNECTED;
|
|
}
|
|
|
|
gboolean
|
|
bolt_status_validate (BoltStatus status)
|
|
{
|
|
return bolt_enum_validate (BOLT_TYPE_STATUS, status, NULL);
|
|
}
|
|
|
|
gboolean
|
|
bolt_status_is_connected (BoltStatus status)
|
|
{
|
|
return status > BOLT_STATUS_DISCONNECTED;
|
|
}
|
|
|
|
BoltSecurity
|
|
bolt_security_from_string (const char *str)
|
|
{
|
|
return bolt_enum_from_string (BOLT_TYPE_SECURITY, str, NULL);
|
|
}
|
|
|
|
const char *
|
|
bolt_security_to_string (BoltSecurity security)
|
|
{
|
|
return bolt_enum_to_string (BOLT_TYPE_SECURITY, security, NULL);
|
|
}
|
|
|
|
gboolean
|
|
bolt_security_validate (BoltSecurity security)
|
|
{
|
|
return bolt_enum_validate (BOLT_TYPE_SECURITY, security, NULL);
|
|
}
|
|
|
|
gboolean
|
|
bolt_security_allows_pcie (BoltSecurity security)
|
|
{
|
|
gboolean pcie = FALSE;
|
|
|
|
switch (security)
|
|
{
|
|
case BOLT_SECURITY_NONE:
|
|
case BOLT_SECURITY_USER:
|
|
case BOLT_SECURITY_SECURE:
|
|
pcie = TRUE;
|
|
break;
|
|
|
|
case BOLT_SECURITY_DPONLY:
|
|
case BOLT_SECURITY_USBONLY:
|
|
case BOLT_SECURITY_UNKNOWN:
|
|
pcie = FALSE;
|
|
break;
|
|
}
|
|
|
|
return pcie;
|
|
}
|
|
|
|
BoltPolicy
|
|
bolt_policy_from_string (const char *str)
|
|
{
|
|
return bolt_enum_from_string (BOLT_TYPE_POLICY, str, NULL);
|
|
}
|
|
|
|
const char *
|
|
bolt_policy_to_string (BoltPolicy policy)
|
|
{
|
|
return bolt_enum_to_string (BOLT_TYPE_POLICY, policy, NULL);
|
|
}
|
|
|
|
gboolean
|
|
bolt_policy_validate (BoltPolicy policy)
|
|
{
|
|
return bolt_enum_validate (BOLT_TYPE_POLICY, policy, NULL);
|
|
}
|
|
|
|
BoltDeviceType
|
|
bolt_device_type_from_string (const char *str)
|
|
{
|
|
return bolt_enum_from_string (BOLT_TYPE_DEVICE_TYPE, str, NULL);
|
|
}
|
|
|
|
const char *
|
|
bolt_device_type_to_string (BoltDeviceType type)
|
|
{
|
|
return bolt_enum_to_string (BOLT_TYPE_DEVICE_TYPE, type, NULL);
|
|
}
|
|
|
|
gboolean
|
|
bolt_device_type_validate (BoltDeviceType type)
|
|
{
|
|
return bolt_enum_validate (BOLT_TYPE_DEVICE_TYPE, type, NULL);
|
|
}
|
|
|
|
gboolean
|
|
bolt_device_type_is_host (BoltDeviceType type)
|
|
{
|
|
return type == BOLT_DEVICE_HOST;
|
|
}
|