iwd: handle new secret request types from IWD agent

The IWD DBus interface currently
(https://git.kernel.org/pub/scm/network/wireless/iwd.git/tree/doc/agent-api.txt?id=38952813dddd776f66d2ed5e88eca9a892964c06)
knows about 3 secret types related to 802.1x authentication in addition
to the PSK secret request.  Add support for the new methods and the new
secret types in NM's implementation of the IWD secret agent.  Note that
the secret types are mapped to NMSetting8021x property keys and they are
then sent to the NM Secret Agent in the hints parameter to GetSecrets,
this will need support in the NM clients as the exact usage of the
hints parameter is specified a little ambiguously, but this seems to be
one of the permitted usages.

Rework the IWD agent interface info initialization to use NM convenience
macros.
This commit is contained in:
Andrew Zaborowski 2018-06-15 06:36:35 +02:00 committed by Thomas Haller
parent ffd96edf76
commit 74d9e04a66
3 changed files with 224 additions and 97 deletions

View file

@ -992,6 +992,127 @@ scanning_prohibited (NMDeviceIwd *self, gboolean periodic)
return !priv->can_scan;
}
/*
* try_reply_agent_request
*
* Check if the connection settings already have the secrets corresponding
* to the IWD agent method that was invoked. If they do, send the method reply
* with the appropriate secrets. Otherwise return the missing secret's setting
* name and key so the caller can send a NM secrets request with this data.
* Return TRUE in either case, return FALSE if an error is detected.
*/
static gboolean
try_reply_agent_request (NMDeviceIwd *self,
NMConnection *connection,
GDBusMethodInvocation *invocation,
const gchar **setting_name,
const gchar **setting_key,
gboolean *replied)
{
const gchar *method_name = g_dbus_method_invocation_get_method_name (invocation);
NMSettingWirelessSecurity *s_wireless_sec;
NMSetting8021x *s_8021x;
s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
s_8021x = nm_connection_get_setting_802_1x (connection);
*replied = FALSE;
if (!strcmp (method_name, "RequestPassphrase")) {
const gchar *psk;
if (!s_wireless_sec)
return FALSE;
psk = nm_setting_wireless_security_get_psk (s_wireless_sec);
if (psk) {
_LOGD (LOGD_DEVICE | LOGD_WIFI,
"Returning the PSK to the IWD Agent");
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(s)", psk));
*replied = TRUE;
return TRUE;
}
*setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
*setting_key = NM_SETTING_WIRELESS_SECURITY_PSK;
return TRUE;
} else if (!strcmp (method_name, "RequestPrivateKeyPassphrase")) {
const gchar *password;
if (!s_8021x)
return FALSE;
password = nm_setting_802_1x_get_private_key_password (s_8021x);
if (password) {
_LOGD (LOGD_DEVICE | LOGD_WIFI,
"Returning the private key password to the IWD Agent");
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(s)", password));
*replied = TRUE;
return TRUE;
}
*setting_name = NM_SETTING_802_1X_SETTING_NAME;
*setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD;
return TRUE;
} else if (!strcmp (method_name, "RequestUserNameAndPassword")) {
const gchar *identity, *password;
if (!s_8021x)
return FALSE;
identity = nm_setting_802_1x_get_identity (s_8021x);
password = nm_setting_802_1x_get_password (s_8021x);
if (identity && password) {
_LOGD (LOGD_DEVICE | LOGD_WIFI,
"Returning the username and password to the IWD Agent");
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(ss)", identity, password));
*replied = TRUE;
return TRUE;
}
*setting_name = NM_SETTING_802_1X_SETTING_NAME;
if (!identity)
*setting_key = NM_SETTING_802_1X_IDENTITY;
else
*setting_key = NM_SETTING_802_1X_PASSWORD;
return TRUE;
} else if (!strcmp (method_name, "RequestUserPassword")) {
const gchar *password;
if (!s_8021x)
return FALSE;
password = nm_setting_802_1x_get_password (s_8021x);
if (password) {
_LOGD (LOGD_DEVICE | LOGD_WIFI,
"Returning the user password to the IWD Agent");
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(s)", password));
*replied = TRUE;
return TRUE;
}
*setting_name = NM_SETTING_802_1X_SETTING_NAME;
*setting_key = NM_SETTING_802_1X_PASSWORD;
return TRUE;
} else
return FALSE;
}
static void
wifi_secrets_get_one (NMDeviceIwd *self,
const char *setting_name,
NMSecretAgentGetSecretsFlags flags,
const char *setting_key,
GDBusMethodInvocation *invocation);
static void
wifi_secrets_cb (NMActRequest *req,
NMActRequestGetSecretsCallId *call_id,
@ -1002,9 +1123,10 @@ wifi_secrets_cb (NMActRequest *req,
NMDeviceIwd *self;
NMDeviceIwdPrivate *priv;
NMDevice *device;
NMSettingWirelessSecurity *s_wireless_sec;
const gchar *psk;
GDBusMethodInvocation *invocation;
const gchar *setting_name;
const gchar *setting_key;
gboolean replied;
nm_utils_user_data_unpack (user_data, &self, &invocation);
@ -1035,22 +1157,24 @@ wifi_secrets_cb (NMActRequest *req,
goto secrets_error;
}
s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req));
if (!s_wireless_sec)
if (!try_reply_agent_request (self, nm_act_request_get_applied_connection (req),
invocation, &setting_name, &setting_key,
&replied))
goto secrets_error;
psk = nm_setting_wireless_security_get_psk (s_wireless_sec);
if (!psk)
goto secrets_error;
if (replied) {
/* Change state back to what it was before NEED_AUTH */
nm_device_state_changed (device, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE);
return;
}
_LOGD (LOGD_DEVICE | LOGD_WIFI,
"Returning a new PSK to the IWD Agent");
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(s)", psk));
/* Change state back to what it was before NEED_AUTH */
nm_device_state_changed (device, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE);
/* Request further secrets if we still need something */
wifi_secrets_get_one (self,
setting_name,
NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION
| NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW,
setting_key,
invocation);
return;
secrets_error:
@ -1066,10 +1190,11 @@ secrets_error:
}
static void
wifi_secrets_get_secrets (NMDeviceIwd *self,
const char *setting_name,
NMSecretAgentGetSecretsFlags flags,
GDBusMethodInvocation *invocation)
wifi_secrets_get_one (NMDeviceIwd *self,
const char *setting_name,
NMSecretAgentGetSecretsFlags flags,
const char *setting_key,
GDBusMethodInvocation *invocation)
{
NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self);
NMActRequest *req;
@ -1083,7 +1208,7 @@ wifi_secrets_get_secrets (NMDeviceIwd *self,
TRUE,
setting_name,
flags,
NULL,
setting_key,
wifi_secrets_cb,
nm_utils_user_data_pack (self, invocation));
}
@ -1722,38 +1847,34 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object)
}
gboolean
nm_device_iwd_agent_psk_query (NMDeviceIwd *self,
GDBusMethodInvocation *invocation)
nm_device_iwd_agent_query (NMDeviceIwd *self,
GDBusMethodInvocation *invocation)
{
NMActRequest *req;
NMSettingWirelessSecurity *s_wireless_sec;
const gchar *psk;
const gchar *setting_name;
const gchar *setting_key;
gboolean replied;
req = nm_device_get_act_request (NM_DEVICE (self));
if (!req)
return FALSE;
s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req));
if (!s_wireless_sec)
if (!try_reply_agent_request (self, nm_act_request_get_applied_connection (req),
invocation, &setting_name, &setting_key,
&replied))
return FALSE;
psk = nm_setting_wireless_security_get_psk (s_wireless_sec);
if (psk) {
_LOGD (LOGD_DEVICE | LOGD_WIFI,
"Returning the PSK to the IWD Agent");
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(s)", psk));
if (replied)
return TRUE;
}
nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH,
NM_DEVICE_STATE_REASON_NO_SECRETS);
wifi_secrets_get_secrets (self,
NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION
| NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW,
invocation);
wifi_secrets_get_one (self,
setting_name,
NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION
| NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW,
setting_key,
invocation);
return TRUE;
}

View file

@ -51,8 +51,8 @@ NMDevice *nm_device_iwd_new (const char *iface, NMDeviceWifiCapabilities capabil
void nm_device_iwd_set_dbus_object (NMDeviceIwd *device, GDBusObject *object);
gboolean nm_device_iwd_agent_psk_query (NMDeviceIwd *device,
GDBusMethodInvocation *invocation);
gboolean nm_device_iwd_agent_query (NMDeviceIwd *device,
GDBusMethodInvocation *invocation);
const CList *_nm_device_iwd_get_aps (NMDeviceIwd *self);

View file

@ -84,12 +84,12 @@ G_DEFINE_TYPE (NMIwdManager, nm_iwd_manager, G_TYPE_OBJECT)
/*****************************************************************************/
static void
psk_agent_dbus_method_cb (GDBusConnection *connection,
const gchar *sender, const gchar *object_path,
const gchar *interface_name, const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
agent_dbus_method_cb (GDBusConnection *connection,
const gchar *sender, const gchar *object_path,
const gchar *interface_name, const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
NMIwdManager *self = user_data;
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
@ -104,7 +104,10 @@ psk_agent_dbus_method_cb (GDBusConnection *connection,
if (!nm_streq0 (g_dbus_object_manager_client_get_name_owner (omc), sender))
goto return_error;
g_variant_get (parameters, "(&o)", &network_path);
if (!strcmp (method_name, "RequestUserPassword"))
g_variant_get (parameters, "(&os)", &network_path, NULL);
else
g_variant_get (parameters, "(&o)", &network_path);
network = g_dbus_object_manager_get_interface (priv->object_manager,
network_path,
@ -145,7 +148,7 @@ psk_agent_dbus_method_cb (GDBusConnection *connection,
goto return_error;
}
if (nm_device_iwd_agent_psk_query (NM_DEVICE_IWD (device), invocation))
if (nm_device_iwd_agent_query (NM_DEVICE_IWD (device), invocation))
return;
_LOGE ("Device %s did not handle the IWD Agent request", ifname);
@ -154,56 +157,59 @@ return_error:
/* IWD doesn't look at the specific error */
g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR,
NM_DEVICE_ERROR_INVALID_CONNECTION,
"No PSK available for this connection");
"Secrets not available for this connection");
}
static const GDBusInterfaceInfo iwd_agent_iface_info = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (
"net.connman.iwd.Agent",
.methods = NM_DEFINE_GDBUS_METHOD_INFOS (
NM_DEFINE_GDBUS_METHOD_INFO (
"RequestPassphrase",
.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("network", "o"),
),
.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("passphrase", "s"),
),
),
NM_DEFINE_GDBUS_METHOD_INFO (
"RequestPrivateKeyPassphrase",
.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("network", "o"),
),
.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("passphrase", "s"),
),
),
NM_DEFINE_GDBUS_METHOD_INFO (
"RequestUserNameAndPassword",
.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("network", "o"),
),
.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("user", "s"),
NM_DEFINE_GDBUS_ARG_INFO ("password", "s"),
),
),
NM_DEFINE_GDBUS_METHOD_INFO (
"RequestUserPassword",
.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("network", "o"),
NM_DEFINE_GDBUS_ARG_INFO ("user", "s"),
),
.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
NM_DEFINE_GDBUS_ARG_INFO ("password", "s"),
),
),
),
);
static guint
psk_agent_export (GDBusConnection *connection, gpointer user_data,
iwd_agent_export (GDBusConnection *connection, gpointer user_data,
gchar **agent_path, GError **error)
{
static const GDBusArgInfo request_passphrase_arg_network = {
-1,
(gchar *) "network",
(gchar *) "o",
NULL,
};
static const GDBusArgInfo *const request_passphrase_in_args[] = {
&request_passphrase_arg_network,
NULL,
};
static const GDBusArgInfo request_passphrase_arg_passphrase = {
-1,
(gchar *) "passphrase",
(gchar *) "s",
NULL,
};
static const GDBusArgInfo *const request_passphrase_out_args[] = {
&request_passphrase_arg_passphrase,
NULL,
};
static const GDBusMethodInfo request_passphrase_info = {
-1,
(gchar *) "RequestPassphrase",
(GDBusArgInfo **) &request_passphrase_in_args,
(GDBusArgInfo **) &request_passphrase_out_args,
NULL,
};
static const GDBusMethodInfo *const method_info[] = {
&request_passphrase_info,
NULL,
};
static GDBusInterfaceInfo interface_info = {
-1,
(gchar *) "net.connman.iwd.Agent",
(GDBusMethodInfo **) &method_info,
NULL,
NULL,
NULL,
};
static GDBusInterfaceVTable vtable = {
psk_agent_dbus_method_cb,
NULL,
NULL,
static const GDBusInterfaceVTable vtable = {
.method_call = agent_dbus_method_cb,
};
gchar path[50];
@ -221,8 +227,8 @@ psk_agent_export (GDBusConnection *connection, gpointer user_data,
nm_sprintf_buf (path, "/agent/%u", rnd);
id = g_dbus_connection_register_object (connection, path,
&interface_info, &vtable,
user_data, NULL, error);
NM_UNCONST_PTR (GDBusInterfaceInfo, &iwd_agent_iface_info),
&vtable, user_data, NULL, error);
if (id)
*agent_path = g_strdup (path);
@ -549,7 +555,7 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data)
connection = g_dbus_object_manager_client_get_connection (G_DBUS_OBJECT_MANAGER_CLIENT (object_manager));
priv->agent_id = psk_agent_export (connection, self,
priv->agent_id = iwd_agent_export (connection, self,
&priv->agent_path, &error);
if (!priv->agent_id) {
_LOGE ("failed to export the IWD Agent: PSK/8021x WiFi networks will not work: %s",