diff options
Diffstat (limited to 'libnm-core/nm-setting-8021x.c')
| -rw-r--r-- | libnm-core/nm-setting-8021x.c | 3864 |
1 files changed, 3864 insertions, 0 deletions
diff --git a/libnm-core/nm-setting-8021x.c b/libnm-core/nm-setting-8021x.c new file mode 100644 index 00000000..f739f2c7 --- /dev/null +++ b/libnm-core/nm-setting-8021x.c @@ -0,0 +1,3864 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * This library 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 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, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2007 - 2013 Red Hat, Inc. + * Copyright 2007 - 2008 Novell, Inc. + */ + +#include "config.h" + +#include <string.h> +#include <glib/gi18n-lib.h> + +#include "nm-setting-8021x.h" +#include "nm-utils.h" +#include "crypto.h" +#include "nm-utils-private.h" +#include "nm-setting-private.h" +#include "nm-core-enum-types.h" + +/** + * SECTION:nm-setting-8021x + * @short_description: Describes 802.1x-authenticated connection properties + * + * The #NMSetting8021x object is a #NMSetting subclass that describes + * properties necessary for connection to 802.1x-authenticated networks, such as + * WPA and WPA2 Enterprise Wi-Fi networks and wired 802.1x networks. 802.1x + * connections typically use certificates and/or EAP authentication methods to + * securely verify, identify, and authenticate the client to the network itself, + * instead of simply relying on a widely shared static key. + * + * It's a good idea to read up on wpa_supplicant configuration before using this + * setting extensively, since most of the options here correspond closely with + * the relevant wpa_supplicant configuration options. + * + * Furthermore, to get a good idea of 802.1x, EAP, TLS, TTLS, etc and their + * applications to Wi-Fi and wired networks, you'll want to get copies of the + * following books. + * + * 802.11 Wireless Networks: The Definitive Guide, Second Edition + * Author: Matthew Gast + * ISBN: 978-0596100520 + * + * Cisco Wireless LAN Security + * Authors: Krishna Sankar, Sri Sundaralingam, Darrin Miller, and Andrew Balinsky + * ISBN: 978-1587051548 + **/ + +#define SCHEME_PATH "file://" + +G_DEFINE_TYPE_WITH_CODE (NMSetting8021x, nm_setting_802_1x, NM_TYPE_SETTING, + _nm_register_setting (802_1X, 2)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_802_1X) + +#define NM_SETTING_802_1X_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_802_1X, NMSetting8021xPrivate)) + +G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_UNKNOWN == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_UNKNOWN) ); +G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_X509 == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_X509) ); +G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_RAW_KEY == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_RAW_KEY) ); +G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_PKCS12 == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_PKCS12) ); + +typedef struct { + GSList *eap; /* GSList of strings */ + char *identity; + char *anonymous_identity; + char *pac_file; + GBytes *ca_cert; + char *ca_path; + char *subject_match; + GSList *altsubject_matches; + GBytes *client_cert; + char *phase1_peapver; + char *phase1_peaplabel; + char *phase1_fast_provisioning; + char *phase2_auth; + char *phase2_autheap; + GBytes *phase2_ca_cert; + char *phase2_ca_path; + char *phase2_subject_match; + GSList *phase2_altsubject_matches; + GBytes *phase2_client_cert; + char *password; + NMSettingSecretFlags password_flags; + GBytes *password_raw; + NMSettingSecretFlags password_raw_flags; + char *pin; + NMSettingSecretFlags pin_flags; + GBytes *private_key; + char *private_key_password; + NMSettingSecretFlags private_key_password_flags; + GBytes *phase2_private_key; + char *phase2_private_key_password; + NMSettingSecretFlags phase2_private_key_password_flags; + gboolean system_ca_certs; +} NMSetting8021xPrivate; + +enum { + PROP_0, + PROP_EAP, + PROP_IDENTITY, + PROP_ANONYMOUS_IDENTITY, + PROP_PAC_FILE, + PROP_CA_CERT, + PROP_CA_PATH, + PROP_SUBJECT_MATCH, + PROP_ALTSUBJECT_MATCHES, + PROP_CLIENT_CERT, + PROP_PHASE1_PEAPVER, + PROP_PHASE1_PEAPLABEL, + PROP_PHASE1_FAST_PROVISIONING, + PROP_PHASE2_AUTH, + PROP_PHASE2_AUTHEAP, + PROP_PHASE2_CA_CERT, + PROP_PHASE2_CA_PATH, + PROP_PHASE2_SUBJECT_MATCH, + PROP_PHASE2_ALTSUBJECT_MATCHES, + PROP_PHASE2_CLIENT_CERT, + PROP_PASSWORD, + PROP_PASSWORD_FLAGS, + PROP_PASSWORD_RAW, + PROP_PASSWORD_RAW_FLAGS, + PROP_PRIVATE_KEY, + PROP_PRIVATE_KEY_PASSWORD, + PROP_PRIVATE_KEY_PASSWORD_FLAGS, + PROP_PHASE2_PRIVATE_KEY, + PROP_PHASE2_PRIVATE_KEY_PASSWORD, + PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, + PROP_PIN, + PROP_PIN_FLAGS, + PROP_SYSTEM_CA_CERTS, + + LAST_PROP +}; + +/** + * nm_setting_802_1x_new: + * + * Creates a new #NMSetting8021x object with default values. + * + * Returns: the new empty #NMSetting8021x object + **/ +NMSetting * +nm_setting_802_1x_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_802_1X, NULL); +} + +/** + * nm_setting_802_1x_get_num_eap_methods: + * @setting: the #NMSetting8021x + * + * Returns the number of eap methods allowed for use when connecting to the + * network. Generally only one EAP method is used. Use the functions + * nm_setting_802_1x_get_eap_method(), nm_setting_802_1x_add_eap_method(), + * and nm_setting_802_1x_remove_eap_method() for adding, removing, and retrieving + * allowed EAP methods. + * + * Returns: the number of allowed EAP methods + **/ +guint32 +nm_setting_802_1x_get_num_eap_methods (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), 0); + + return g_slist_length (NM_SETTING_802_1X_GET_PRIVATE (setting)->eap); +} + +/** + * nm_setting_802_1x_get_eap_method: + * @setting: the #NMSetting8021x + * @i: the index of the EAP method name to return + * + * Returns the name of the allowed EAP method at index @i. + * + * Returns: the name of the allowed EAP method at index @i + **/ +const char * +nm_setting_802_1x_get_eap_method (NMSetting8021x *setting, guint32 i) +{ + NMSetting8021xPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + g_return_val_if_fail (i <= g_slist_length (priv->eap), NULL); + + return (const char *) g_slist_nth_data (priv->eap, i); +} + +/** + * nm_setting_802_1x_add_eap_method: + * @setting: the #NMSetting8021x + * @eap: the name of the EAP method to allow for this connection + * + * Adds an allowed EAP method. The setting is not valid until at least one + * EAP method has been added. See #NMSetting8021x:eap property for a list of + * allowed EAP methods. + * + * Returns: %TRUE if the EAP method was successfully added, %FALSE if it was + * not a valid method or if it was already allowed. + **/ +gboolean +nm_setting_802_1x_add_eap_method (NMSetting8021x *setting, const char *eap) +{ + NMSetting8021xPrivate *priv; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + g_return_val_if_fail (eap != NULL, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + for (iter = priv->eap; iter; iter = g_slist_next (iter)) { + if (!strcmp (eap, (char *) iter->data)) + return FALSE; + } + + priv->eap = g_slist_append (priv->eap, g_ascii_strdown (eap, -1)); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_EAP); + return TRUE; +} + +/** + * nm_setting_802_1x_remove_eap_method: + * @setting: the #NMSetting8021x + * @i: the index of the EAP method to remove + * + * Removes the allowed EAP method at the specified index. + **/ +void +nm_setting_802_1x_remove_eap_method (NMSetting8021x *setting, guint32 i) +{ + NMSetting8021xPrivate *priv; + GSList *elt; + + g_return_if_fail (NM_IS_SETTING_802_1X (setting)); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + elt = g_slist_nth (priv->eap, i); + g_return_if_fail (elt != NULL); + + g_free (elt->data); + priv->eap = g_slist_delete_link (priv->eap, elt); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_EAP); +} + +/** + * nm_setting_802_1x_remove_eap_method_by_value: + * @setting: the #NMSetting8021x + * @eap: the name of the EAP method to remove + * + * Removes the allowed EAP method @method. + * + * Returns: %TRUE if the EAP method was founs and removed, %FALSE if it was not. + **/ +gboolean +nm_setting_802_1x_remove_eap_method_by_value (NMSetting8021x *setting, + const char *eap) +{ + NMSetting8021xPrivate *priv; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + g_return_val_if_fail (eap != NULL, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + for (iter = priv->eap; iter; iter = g_slist_next (iter)) { + if (!strcmp (eap, (char *) iter->data)) { + priv->eap = g_slist_delete_link (priv->eap, iter); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_EAP); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_802_1x_clear_eap_methods: + * @setting: the #NMSetting8021x + * + * Clears all allowed EAP methods. + **/ +void +nm_setting_802_1x_clear_eap_methods (NMSetting8021x *setting) +{ + NMSetting8021xPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_802_1X (setting)); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + g_slist_free_full (priv->eap, g_free); + priv->eap = NULL; + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_EAP); +} + +/** + * nm_setting_802_1x_get_identity: + * @setting: the #NMSetting8021x + * + * Returns the identifier used by some EAP methods (like TLS) to + * authenticate the user. Often this is a username or login name. + * + * Returns: the user identifier + **/ +const char * +nm_setting_802_1x_get_identity (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->identity; +} + +/** + * nm_setting_802_1x_get_anonymous_identity: + * @setting: the #NMSetting8021x + * + * Returns the anonymous identifier used by some EAP methods (like TTLS) to + * authenticate the user in the outer unencrypted "phase 1" authentication. The + * inner "phase 2" authentication will use the #NMSetting8021x:identity in + * a secure form, if applicable for that EAP method. + * + * Returns: the anonymous identifier + **/ +const char * +nm_setting_802_1x_get_anonymous_identity (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->anonymous_identity; +} + +/** + * nm_setting_802_1x_get_pac_file: + * @setting: the #NMSetting8021x + * + * Returns the file containing PAC credentials used by EAP-FAST method. + * + * Returns: the PAC file + **/ +const char * +nm_setting_802_1x_get_pac_file (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->pac_file; +} + +/** + * nm_setting_802_1x_get_ca_path: + * @setting: the #NMSetting8021x + * + * Returns the path of the CA certificate directory if previously set. Systems + * will often have a directory that contains multiple individual CA certificates + * which the supplicant can then add to the verification chain. This may be + * used in addition to the #NMSetting8021x:ca-cert property to add more CA + * certificates for verifying the network to client. + * + * Returns: the CA certificate directory path + **/ +const char * +nm_setting_802_1x_get_ca_path (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_path; +} + +/** + * nm_setting_802_1x_get_system_ca_certs: + * @setting: the #NMSetting8021x + * + * Sets the #NMSetting8021x:system-ca-certs property. The + * #NMSetting8021x:ca-path and #NMSetting8021x:phase2-ca-path + * properties are ignored if the #NMSetting8021x:system-ca-certs property is + * %TRUE, in which case a system-wide CA certificate directory specified at + * compile time (using the --system-ca-path configure option) is used in place + * of these properties. + * + * Returns: %TRUE if a system CA certificate path should be used, %FALSE if not + **/ +gboolean +nm_setting_802_1x_get_system_ca_certs (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->system_ca_certs; +} + +static NMSetting8021xCKScheme +get_cert_scheme (GBytes *bytes) +{ + gconstpointer data; + gsize length; + + if (!bytes) + return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN; + + data = g_bytes_get_data (bytes, &length); + if (!length) + return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN; + + if ( (length > strlen (SCHEME_PATH)) + && !memcmp (data, SCHEME_PATH, strlen (SCHEME_PATH))) + return NM_SETTING_802_1X_CK_SCHEME_PATH; + + return NM_SETTING_802_1X_CK_SCHEME_BLOB; +} + +/** + * nm_setting_802_1x_get_ca_cert_scheme: + * @setting: the #NMSetting8021x + * + * Returns the scheme used to store the CA certificate. If the returned scheme + * is %NM_SETTING_802_1X_CK_SCHEME_BLOB, use nm_setting_802_1x_get_ca_cert_blob(); + * if %NM_SETTING_802_1X_CK_SCHEME_PATH, use nm_setting_802_1x_get_ca_cert_path(). + * + * Returns: scheme used to store the CA certificate (blob or path) + **/ +NMSetting8021xCKScheme +nm_setting_802_1x_get_ca_cert_scheme (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN); + + return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert); +} + +/** + * nm_setting_802_1x_get_ca_cert_blob: + * @setting: the #NMSetting8021x + * + * Returns the CA certificate blob if the CA certificate is stored using the + * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. Not all EAP methods use a + * CA certificate (LEAP for example), and those that can take advantage of the + * CA certificate allow it to be unset. Note that lack of a CA certificate + * reduces security by allowing man-in-the-middle attacks, because the identity + * of the network cannot be confirmed by the client. + * + * Returns: (transfer none): the CA certificate data + **/ +GBytes * +nm_setting_802_1x_get_ca_cert_blob (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_ca_cert_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert; +} + +/** + * nm_setting_802_1x_get_ca_cert_path: + * @setting: the #NMSetting8021x + * + * Returns the CA certificate path if the CA certificate is stored using the + * %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. Not all EAP methods use a + * CA certificate (LEAP for example), and those that can take advantage of the + * CA certificate allow it to be unset. Note that lack of a CA certificate + * reduces security by allowing man-in-the-middle attacks, because the identity + * of the network cannot be confirmed by the client. + * + * Returns: path to the CA certificate file + **/ +const char * +nm_setting_802_1x_get_ca_cert_path (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + gconstpointer data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_ca_cert_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL); + + data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert, NULL); + return (const char *)data + strlen (SCHEME_PATH); +} + +static GBytes * +path_to_scheme_value (const char *path) +{ + GByteArray *array; + + g_return_val_if_fail (path != NULL, NULL); + + /* Add the path scheme tag to the front, then the fielname */ + array = g_byte_array_sized_new (strlen (path) + strlen (SCHEME_PATH) + 1); + g_byte_array_append (array, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); + g_byte_array_append (array, (const guint8 *) path, strlen (path)); + g_byte_array_append (array, (const guint8 *) "\0", 1); + + return g_byte_array_free_to_bytes (array); +} + +/** + * nm_setting_802_1x_set_ca_cert: + * @setting: the #NMSetting8021x + * @cert_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH + * or %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the CA certificate + * file (PEM or DER format). The path must be UTF-8 encoded; use + * g_filename_to_utf8() to convert if needed. Passing %NULL with any @scheme + * clears the CA certificate. + * @scheme: desired storage scheme for the certificate + * @out_format: on successful return, the type of the certificate added + * @error: on unsuccessful return, an error + * + * Reads a certificate from disk and sets the #NMSetting8021x:ca-cert property + * with the raw certificate data if using the %NM_SETTING_802_1X_CK_SCHEME_BLOB + * scheme, or with the path to the certificate file if using the + * %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. + * + * Returns: %TRUE if the operation succeeded, %FALSE if it was unsuccessful + **/ +gboolean +nm_setting_802_1x_set_ca_cert (NMSetting8021x *setting, + const char *cert_path, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError **error) +{ + NMSetting8021xPrivate *priv; + NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; + GByteArray *data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + + if (cert_path) { + g_return_val_if_fail (g_utf8_validate (cert_path, -1, NULL), FALSE); + g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB + || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, + FALSE); + } + + if (out_format) + g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + + g_clear_pointer (&priv->ca_cert, g_bytes_unref); + + if (!cert_path) { + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CA_CERT); + return TRUE; + } + + data = crypto_load_and_verify_certificate (cert_path, &format, error); + if (data) { + /* wpa_supplicant can only use raw x509 CA certs */ + if (format == NM_CRYPTO_FILE_FORMAT_X509) { + if (out_format) + *out_format = NM_SETTING_802_1X_CK_FORMAT_X509; + + if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + priv->ca_cert = g_byte_array_free_to_bytes (data); + data = NULL; + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->ca_cert = path_to_scheme_value (cert_path); + else + g_assert_not_reached (); + } else { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("CA certificate must be in X.509 format")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CA_CERT); + } + if (data) + g_byte_array_unref (data); + } + + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CA_CERT); + return priv->ca_cert != NULL; +} + +/** + * nm_setting_802_1x_get_subject_match: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSetting8021x:subject-match property. This is the + * substring to be matched against the subject of the authentication + * server certificate, or %NULL no subject verification is to be + * performed. + **/ +const char * +nm_setting_802_1x_get_subject_match (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->subject_match; +} + +/** + * nm_setting_802_1x_get_num_altsubject_matches: + * @setting: the #NMSetting8021x + * + * Returns the number of entries in the + * #NMSetting8021x:altsubject-matches property of this setting. + * + * Returns: the number of altsubject-matches entries. + **/ +guint32 +nm_setting_802_1x_get_num_altsubject_matches (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), 0); + + return g_slist_length (NM_SETTING_802_1X_GET_PRIVATE (setting)->altsubject_matches); +} + +/** + * nm_setting_802_1x_get_altsubject_match: + * @setting: the #NMSettingConnection + * @i: the zero-based index of the array of altSubjectName matches + * + * Returns the altSubjectName match at index @i. + * + * Returns: the altSubjectName match at index @i + **/ +const char * +nm_setting_802_1x_get_altsubject_match (NMSetting8021x *setting, guint32 i) +{ + NMSetting8021xPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + g_return_val_if_fail (i <= g_slist_length (priv->altsubject_matches), NULL); + + return (const char *) g_slist_nth_data (priv->altsubject_matches, i); +} + +/** + * nm_setting_802_1x_add_altsubject_match: + * @setting: the #NMSetting8021x + * @altsubject_match: the altSubjectName to allow for this connection + * + * Adds an allowed alternate subject name match. Until at least one + * match is added, the altSubjectName of the remote authentication + * server is not verified. + * + * Returns: %TRUE if the alternative subject name match was + * successfully added, %FALSE if it was already allowed. + **/ +gboolean +nm_setting_802_1x_add_altsubject_match (NMSetting8021x *setting, + const char *altsubject_match) +{ + NMSetting8021xPrivate *priv; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + g_return_val_if_fail (altsubject_match != NULL, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + for (iter = priv->altsubject_matches; iter; iter = g_slist_next (iter)) { + if (!strcmp (altsubject_match, (char *) iter->data)) + return FALSE; + } + + priv->altsubject_matches = g_slist_append (priv->altsubject_matches, + g_strdup (altsubject_match)); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_ALTSUBJECT_MATCHES); + return TRUE; +} + +/** + * nm_setting_802_1x_remove_altsubject_match: + * @setting: the #NMSetting8021x + * @i: the index of the altSubjectName match to remove + * + * Removes the allowed altSubjectName at the specified index. + **/ +void +nm_setting_802_1x_remove_altsubject_match (NMSetting8021x *setting, guint32 i) +{ + NMSetting8021xPrivate *priv; + GSList *elt; + + g_return_if_fail (NM_IS_SETTING_802_1X (setting)); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + elt = g_slist_nth (priv->altsubject_matches, i); + g_return_if_fail (elt != NULL); + + g_free (elt->data); + priv->altsubject_matches = g_slist_delete_link (priv->altsubject_matches, elt); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_ALTSUBJECT_MATCHES); +} + +/** + * nm_setting_802_1x_remove_altsubject_match_by_value: + * @setting: the #NMSetting8021x + * @altsubject_match: the altSubjectName to remove + * + * Removes the allowed altSubjectName @altsubject_match. + * + * Returns: %TRUE if the alternative subject name match was found and removed, + * %FALSE if it was not. + **/ +gboolean +nm_setting_802_1x_remove_altsubject_match_by_value (NMSetting8021x *setting, + const char *altsubject_match) +{ + NMSetting8021xPrivate *priv; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + g_return_val_if_fail (altsubject_match != NULL, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + for (iter = priv->altsubject_matches; iter; iter = g_slist_next (iter)) { + if (!strcmp (altsubject_match, (char *) iter->data)) { + priv->altsubject_matches = g_slist_delete_link (priv->altsubject_matches, iter); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_ALTSUBJECT_MATCHES); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_802_1x_clear_altsubject_matches: + * @setting: the #NMSetting8021x + * + * Clears all altSubjectName matches. + **/ +void +nm_setting_802_1x_clear_altsubject_matches (NMSetting8021x *setting) +{ + NMSetting8021xPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_802_1X (setting)); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + g_slist_free_full (priv->altsubject_matches, g_free); + priv->altsubject_matches = NULL; + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_ALTSUBJECT_MATCHES); +} + +/** + * nm_setting_802_1x_get_client_cert_scheme: + * @setting: the #NMSetting8021x + * + * Returns the scheme used to store the client certificate. If the returned scheme + * is %NM_SETTING_802_1X_CK_SCHEME_BLOB, use nm_setting_802_1x_get_client_cert_blob(); + * if %NM_SETTING_802_1X_CK_SCHEME_PATH, use nm_setting_802_1x_get_client_cert_path(). + * + * Returns: scheme used to store the client certificate (blob or path) + **/ +NMSetting8021xCKScheme +nm_setting_802_1x_get_client_cert_scheme (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN); + + return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert); +} + +/** + * nm_setting_802_1x_get_client_cert_blob: + * @setting: the #NMSetting8021x + * + * Client certificates are used to identify the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * Returns: (transfer none): the client certificate data + **/ +GBytes * +nm_setting_802_1x_get_client_cert_blob (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_client_cert_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert; +} + +/** + * nm_setting_802_1x_get_client_cert_path: + * @setting: the #NMSetting8021x + * + * Client certificates are used to identify the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * Returns: path to the client certificate file + **/ +const char * +nm_setting_802_1x_get_client_cert_path (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + gconstpointer data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_client_cert_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL); + + data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert, NULL); + return (const char *)data + strlen (SCHEME_PATH); +} + +/** + * nm_setting_802_1x_set_client_cert: + * @setting: the #NMSetting8021x + * @cert_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH + * or %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the client + * certificate file (PEM, DER, or PKCS#<!-- -->12 format). The path must be UTF-8 + * encoded; use g_filename_to_utf8() to convert if needed. Passing %NULL with + * any @scheme clears the client certificate. + * @scheme: desired storage scheme for the certificate + * @out_format: on successful return, the type of the certificate added + * @error: on unsuccessful return, an error + * + * Reads a certificate from disk and sets the #NMSetting8021x:client-cert + * property with the raw certificate data if using the + * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme, or with the path to the certificate + * file if using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. + * + * Client certificates are used to identify the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * Returns: %TRUE if the operation succeeded, %FALSE if it was unsuccessful + **/ +gboolean +nm_setting_802_1x_set_client_cert (NMSetting8021x *setting, + const char *cert_path, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError **error) +{ + NMSetting8021xPrivate *priv; + NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; + GByteArray *data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + + if (cert_path) { + g_return_val_if_fail (g_utf8_validate (cert_path, -1, NULL), FALSE); + g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB + || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, + FALSE); + } + + if (out_format) + g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + + g_clear_pointer (&priv->client_cert, g_bytes_unref); + + if (!cert_path) { + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CLIENT_CERT); + return TRUE; + } + + data = crypto_load_and_verify_certificate (cert_path, &format, error); + if (data) { + gboolean valid = FALSE; + + switch (format) { + case NM_CRYPTO_FILE_FORMAT_X509: + if (out_format) + *out_format = NM_SETTING_802_1X_CK_FORMAT_X509; + valid = TRUE; + break; + case NM_CRYPTO_FILE_FORMAT_PKCS12: + if (out_format) + *out_format = NM_SETTING_802_1X_CK_FORMAT_PKCS12; + valid = TRUE; + break; + default: + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("invalid certificate format")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT); + break; + } + + if (valid) { + if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + priv->client_cert = g_byte_array_free_to_bytes (data); + data = NULL; + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->client_cert = path_to_scheme_value (cert_path); + else + g_assert_not_reached (); + } + if (data) + g_byte_array_unref (data); + } + + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CLIENT_CERT); + return priv->client_cert != NULL; +} + +/** + * nm_setting_802_1x_get_phase1_peapver: + * @setting: the #NMSetting8021x + * + * Returns: the "phase 1" PEAP version to be used when authenticating with + * EAP-PEAP as contained in the #NMSetting8021x:phase1-peapver property. Valid + * values are %NULL (unset), "0" (PEAP version 0), and "1" (PEAP version 1). + **/ +const char * +nm_setting_802_1x_get_phase1_peapver (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase1_peapver; +} + +/** + * nm_setting_802_1x_get_phase1_peaplabel: + * @setting: the #NMSetting8021x + * + * Returns: whether the "phase 1" PEAP label is new-style or old-style, to be + * used when authenticating with EAP-PEAP, as contained in the + * #NMSetting8021x:phase1-peaplabel property. Valid values are %NULL (unset), + * "0" (use old-style label), and "1" (use new-style label). See the + * wpa_supplicant documentation for more details. + **/ +const char * +nm_setting_802_1x_get_phase1_peaplabel (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase1_peaplabel; +} + +/** + * nm_setting_802_1x_get_phase1_fast_provisioning: + * @setting: the #NMSetting8021x + * + * Returns: whether "phase 1" PEAP fast provisioning should be used, as specified + * by the #NMSetting8021x:phase1-fast-provisioning property. See the + * wpa_supplicant documentation for more details. + **/ +const char * +nm_setting_802_1x_get_phase1_fast_provisioning (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase1_fast_provisioning; +} + +/** + * nm_setting_802_1x_get_phase2_auth: + * @setting: the #NMSetting8021x + * + * Returns: the "phase 2" non-EAP (ex MD5) allowed authentication method as + * specified by the #NMSetting8021x:phase2-auth property. + **/ +const char * +nm_setting_802_1x_get_phase2_auth (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_auth; +} + +/** + * nm_setting_802_1x_get_phase2_autheap: + * @setting: the #NMSetting8021x + * + * Returns: the "phase 2" EAP-based (ex TLS) allowed authentication method as + * specified by the #NMSetting8021x:phase2-autheap property. + **/ +const char * +nm_setting_802_1x_get_phase2_autheap (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_autheap; +} + +/** + * nm_setting_802_1x_get_phase2_ca_path: + * @setting: the #NMSetting8021x + * + * Returns the path of the "phase 2" CA certificate directory if previously set. + * Systems will often have a directory that contains multiple individual CA + * certificates which the supplicant can then add to the verification chain. + * This may be used in addition to the #NMSetting8021x:phase2-ca-cert property + * to add more CA certificates for verifying the network to client. + * + * Returns: the "phase 2" CA certificate directory path + **/ +const char * +nm_setting_802_1x_get_phase2_ca_path (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_path; +} + +/** + * nm_setting_802_1x_get_phase2_ca_cert_scheme: + * @setting: the #NMSetting8021x + * + * Returns the scheme used to store the "phase 2" CA certificate. If the + * returned scheme is %NM_SETTING_802_1X_CK_SCHEME_BLOB, use + * nm_setting_802_1x_get_ca_cert_blob(); if %NM_SETTING_802_1X_CK_SCHEME_PATH, + * use nm_setting_802_1x_get_ca_cert_path(). + * + * Returns: scheme used to store the "phase 2" CA certificate (blob or path) + **/ +NMSetting8021xCKScheme +nm_setting_802_1x_get_phase2_ca_cert_scheme (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN); + + return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert); +} + +/** + * nm_setting_802_1x_get_phase2_ca_cert_blob: + * @setting: the #NMSetting8021x + * + * Returns the "phase 2" CA certificate blob if the CA certificate is stored + * using the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. Not all EAP methods use + * a CA certificate (LEAP for example), and those that can take advantage of the + * CA certificate allow it to be unset. Note that lack of a CA certificate + * reduces security by allowing man-in-the-middle attacks, because the identity + * of the network cannot be confirmed by the client. + * + * Returns: (transfer none): the "phase 2" CA certificate data + **/ +GBytes * +nm_setting_802_1x_get_phase2_ca_cert_blob (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_phase2_ca_cert_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert; +} + +/** + * nm_setting_802_1x_get_phase2_ca_cert_path: + * @setting: the #NMSetting8021x + * + * Returns the "phase 2" CA certificate path if the CA certificate is stored + * using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. Not all EAP methods use + * a CA certificate (LEAP for example), and those that can take advantage of the + * CA certificate allow it to be unset. Note that lack of a CA certificate + * reduces security by allowing man-in-the-middle attacks, because the identity + * of the network cannot be confirmed by the client. + * + * Returns: path to the "phase 2" CA certificate file + **/ +const char * +nm_setting_802_1x_get_phase2_ca_cert_path (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + gconstpointer data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_phase2_ca_cert_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL); + + data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert, NULL); + return (const char *)data + strlen (SCHEME_PATH); +} + +/** + * nm_setting_802_1x_set_phase2_ca_cert: + * @setting: the #NMSetting8021x + * @cert_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH + * or %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" CA + * certificate file (PEM or DER format). The path must be UTF-8 encoded; use + * g_filename_to_utf8() to convert if needed. Passing %NULL with any @scheme + * clears the "phase2" CA certificate. + * @scheme: desired storage scheme for the certificate + * @out_format: on successful return, the type of the certificate added + * @error: on unsuccessful return, an error + * + * Reads a certificate from disk and sets the #NMSetting8021x:phase2-ca-cert + * property with the raw certificate data if using the + * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme, or with the path to the certificate + * file if using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. + * + * Returns: %TRUE if the operation succeeded, %FALSE if it was unsuccessful + **/ +gboolean +nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *setting, + const char *cert_path, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError **error) +{ + NMSetting8021xPrivate *priv; + NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; + GByteArray *data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + + if (cert_path) { + g_return_val_if_fail (g_utf8_validate (cert_path, -1, NULL), FALSE); + g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB + || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, + FALSE); + } + + if (out_format) + g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + + g_clear_pointer (&priv->phase2_ca_cert, g_bytes_unref); + + if (!cert_path) { + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CA_CERT); + return TRUE; + } + + data = crypto_load_and_verify_certificate (cert_path, &format, error); + if (data) { + /* wpa_supplicant can only use raw x509 CA certs */ + if (format == NM_CRYPTO_FILE_FORMAT_X509) { + if (out_format) + *out_format = NM_SETTING_802_1X_CK_FORMAT_X509; + + if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + priv->phase2_ca_cert = g_byte_array_free_to_bytes (data); + data = NULL; + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->phase2_ca_cert = path_to_scheme_value (cert_path); + else + g_assert_not_reached (); + } else { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("invalid certificate format")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_CA_CERT); + } + if (data) + g_byte_array_unref (data); + } + + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CA_CERT); + return priv->phase2_ca_cert != NULL; +} + +/** + * nm_setting_802_1x_get_phase2_subject_match: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSetting8021x:phase2-subject-match property. This is + * the substring to be matched against the subject of the "phase 2" + * authentication server certificate, or %NULL no subject verification + * is to be performed. + **/ +const char * +nm_setting_802_1x_get_phase2_subject_match (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_subject_match; +} + +/** + * nm_setting_802_1x_get_num_phase2_altsubject_matches: + * @setting: the #NMSetting8021x + * + * Returns the number of entries in the + * #NMSetting8021x:phase2-altsubject-matches property of this setting. + * + * Returns: the number of phase2-altsubject-matches entries. + **/ +guint32 +nm_setting_802_1x_get_num_phase2_altsubject_matches (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), 0); + + return g_slist_length (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_altsubject_matches); +} + +/** + * nm_setting_802_1x_get_phase2_altsubject_match: + * @setting: the #NMSettingConnection + * @i: the zero-based index of the array of "phase 2" altSubjectName matches + * + * Returns the "phase 2" altSubjectName match at index @i. + * + * Returns: the "phase 2" altSubjectName match at index @i + **/ +const char * +nm_setting_802_1x_get_phase2_altsubject_match (NMSetting8021x *setting, guint32 i) +{ + NMSetting8021xPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + g_return_val_if_fail (i <= g_slist_length (priv->phase2_altsubject_matches), NULL); + + return (const char *) g_slist_nth_data (priv->phase2_altsubject_matches, i); +} + +/** + * nm_setting_802_1x_add_phase2_altsubject_match: + * @setting: the #NMSetting8021x + * @phase2_altsubject_match: the "phase 2" altSubjectName to allow for this + * connection + * + * Adds an allowed alternate subject name match for "phase 2". Until + * at least one match is added, the altSubjectName of the "phase 2" + * remote authentication server is not verified. + * + * Returns: %TRUE if the "phase 2" alternative subject name match was + * successfully added, %FALSE if it was already allowed. + **/ +gboolean +nm_setting_802_1x_add_phase2_altsubject_match (NMSetting8021x *setting, + const char *phase2_altsubject_match) +{ + NMSetting8021xPrivate *priv; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + g_return_val_if_fail (phase2_altsubject_match != NULL, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + for (iter = priv->phase2_altsubject_matches; iter; iter = g_slist_next (iter)) { + if (!strcmp (phase2_altsubject_match, (char *) iter->data)) + return FALSE; + } + + priv->phase2_altsubject_matches = g_slist_append (priv->phase2_altsubject_matches, + g_strdup (phase2_altsubject_match)); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES); + return TRUE; +} + +/** + * nm_setting_802_1x_remove_phase2_altsubject_match: + * @setting: the #NMSetting8021x + * @i: the index of the "phase 2" altSubjectName match to remove + * + * Removes the allowed "phase 2" altSubjectName at the specified index. + **/ +void +nm_setting_802_1x_remove_phase2_altsubject_match (NMSetting8021x *setting, guint32 i) +{ + NMSetting8021xPrivate *priv; + GSList *elt; + + g_return_if_fail (NM_IS_SETTING_802_1X (setting)); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + elt = g_slist_nth (priv->phase2_altsubject_matches, i); + g_return_if_fail (elt != NULL); + + g_free (elt->data); + priv->phase2_altsubject_matches = g_slist_delete_link (priv->phase2_altsubject_matches, elt); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES); +} + + +/** + * nm_setting_802_1x_remove_phase2_altsubject_match_by_value: + * @setting: the #NMSetting8021x + * @phase2_altsubject_match: the "phase 2" altSubjectName to remove + * + * Removes the allowed "phase 2" altSubjectName @phase2_altsubject_match. + * + * Returns: %TRUE if the alternative subject name match for "phase 2" was found and removed, + * %FALSE if it was not. + **/ +gboolean +nm_setting_802_1x_remove_phase2_altsubject_match_by_value (NMSetting8021x *setting, + const char *phase2_altsubject_match) +{ + NMSetting8021xPrivate *priv; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + g_return_val_if_fail (phase2_altsubject_match != NULL, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + for (iter = priv->phase2_altsubject_matches; iter; iter = g_slist_next (iter)) { + if (!strcmp (phase2_altsubject_match, (char *) iter->data)) { + priv->phase2_altsubject_matches = g_slist_delete_link (priv->phase2_altsubject_matches, iter); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_802_1x_clear_phase2_altsubject_matches: + * @setting: the #NMSetting8021x + * + * Clears all "phase 2" altSubjectName matches. + **/ +void +nm_setting_802_1x_clear_phase2_altsubject_matches (NMSetting8021x *setting) +{ + NMSetting8021xPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_802_1X (setting)); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + g_slist_free_full (priv->phase2_altsubject_matches, g_free); + priv->phase2_altsubject_matches = NULL; + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES); +} + +/** + * nm_setting_802_1x_get_phase2_client_cert_scheme: + * @setting: the #NMSetting8021x + * + * Returns the scheme used to store the "phase 2" client certificate. If the + * returned scheme is %NM_SETTING_802_1X_CK_SCHEME_BLOB, use + * nm_setting_802_1x_get_client_cert_blob(); if + * %NM_SETTING_802_1X_CK_SCHEME_PATH, use + * nm_setting_802_1x_get_client_cert_path(). + * + * Returns: scheme used to store the "phase 2" client certificate (blob or path) + **/ +NMSetting8021xCKScheme +nm_setting_802_1x_get_phase2_client_cert_scheme (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN); + + return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert); +} + +/** + * nm_setting_802_1x_get_phase2_client_cert_blob: + * @setting: the #NMSetting8021x + * + * Client certificates are used to identify the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * Returns: (transfer none): the "phase 2" client certificate data + **/ +GBytes * +nm_setting_802_1x_get_phase2_client_cert_blob (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_phase2_client_cert_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert; +} + +/** + * nm_setting_802_1x_get_phase2_client_cert_path: + * @setting: the #NMSetting8021x + * + * Client certificates are used to identify the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * Returns: path to the "phase 2" client certificate file + **/ +const char * +nm_setting_802_1x_get_phase2_client_cert_path (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + gconstpointer data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_phase2_client_cert_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL); + + data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert, NULL); + return (const char *)data + strlen (SCHEME_PATH); +} + +/** + * nm_setting_802_1x_set_phase2_client_cert: + * @setting: the #NMSetting8021x + * @cert_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH + * or %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" client + * certificate file (PEM, DER, or PKCS#<!-- -->12 format). The path must be UTF-8 + * encoded; use g_filename_to_utf8() to convert if needed. Passing %NULL with + * any @scheme clears the "phase2" client certificate. + * @scheme: desired storage scheme for the certificate + * @out_format: on successful return, the type of the certificate added + * @error: on unsuccessful return, an error + * + * Reads a certificate from disk and sets the #NMSetting8021x:phase2-client-cert + * property with the raw certificate data if using the + * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme, or with the path to the certificate + * file if using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. + * + * Client certificates are used to identify the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * Returns: %TRUE if the operation succeeded, %FALSE if it was unsuccessful + **/ +gboolean +nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *setting, + const char *cert_path, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError **error) +{ + NMSetting8021xPrivate *priv; + NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; + GByteArray *data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + + if (cert_path) { + g_return_val_if_fail (g_utf8_validate (cert_path, -1, NULL), FALSE); + g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB + || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, + FALSE); + } + + if (out_format) + g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE); + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + + g_clear_pointer (&priv->phase2_client_cert, g_bytes_unref); + + if (!cert_path) { + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CLIENT_CERT); + return TRUE; + } + + data = crypto_load_and_verify_certificate (cert_path, &format, error); + if (data) { + gboolean valid = FALSE; + + /* wpa_supplicant can only use raw x509 CA certs */ + switch (format) { + case NM_CRYPTO_FILE_FORMAT_X509: + if (out_format) + *out_format = NM_SETTING_802_1X_CK_FORMAT_X509; + valid = TRUE; + break; + case NM_CRYPTO_FILE_FORMAT_PKCS12: + if (out_format) + *out_format = NM_SETTING_802_1X_CK_FORMAT_PKCS12; + valid = TRUE; + break; + default: + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("invalid certificate format")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_CLIENT_CERT); + break; + } + + if (valid) { + if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + priv->phase2_client_cert = g_byte_array_free_to_bytes (data); + data = NULL; + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->phase2_client_cert = path_to_scheme_value (cert_path); + else + g_assert_not_reached (); + } + if (data) + g_byte_array_unref (data); + } + + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CLIENT_CERT); + return priv->phase2_client_cert != NULL; +} + +/** + * nm_setting_802_1x_get_password: + * @setting: the #NMSetting8021x + * + * Returns: the password used by the authentication method, if any, as specified + * by the #NMSetting8021x:password property + **/ +const char * +nm_setting_802_1x_get_password (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->password; +} + +/** + * nm_setting_802_1x_get_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the #NMSetting8021x:password + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->password_flags; +} + +/** + * nm_setting_802_1x_get_password_raw: + * @setting: the #NMSetting8021x + * + * Returns: (transfer none): the password used by the authentication method as a + * UTF-8-encoded array of bytes, as specified by the + * #NMSetting8021x:password-raw property + **/ +GBytes * +nm_setting_802_1x_get_password_raw (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->password_raw; +} + +/** + * nm_setting_802_1x_get_password_raw_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:password-raw + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_password_raw_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->password_raw_flags; +} + +/** + * nm_setting_802_1x_get_pin: + * @setting: the #NMSetting8021x + * + * Returns: the PIN used by the authentication method, if any, as specified + * by the #NMSetting8021x:pin property + **/ +const char * +nm_setting_802_1x_get_pin (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->pin; +} + +/** + * nm_setting_802_1x_get_pin_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:pin + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_pin_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->pin_flags; +} + +/** + * nm_setting_802_1x_get_private_key_scheme: + * @setting: the #NMSetting8021x + * + * Returns the scheme used to store the private key. If the returned scheme is + * %NM_SETTING_802_1X_CK_SCHEME_BLOB, use + * nm_setting_802_1x_get_client_cert_blob(); if + * %NM_SETTING_802_1X_CK_SCHEME_PATH, use + * nm_setting_802_1x_get_client_cert_path(). + * + * Returns: scheme used to store the private key (blob or path) + **/ +NMSetting8021xCKScheme +nm_setting_802_1x_get_private_key_scheme (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN); + + return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key); +} + +/** + * nm_setting_802_1x_get_private_key_blob: + * @setting: the #NMSetting8021x + * + * Private keys are used to authenticate the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * WARNING: the private key property is not a "secret" property, and thus + * unencrypted private key data may be readable by unprivileged users. Private + * keys should always be encrypted with a private key password. + * + * Returns: (transfer none): the private key data + **/ +GBytes * +nm_setting_802_1x_get_private_key_blob (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_private_key_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key; +} + +/** + * nm_setting_802_1x_get_private_key_path: + * @setting: the #NMSetting8021x + * + * Private keys are used to authenticate the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * Returns: path to the private key file + **/ +const char * +nm_setting_802_1x_get_private_key_path (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + gconstpointer data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_private_key_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL); + + data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key, NULL); + return (const char *)data + strlen (SCHEME_PATH); +} + +static void +free_secure_bytes (gpointer data) +{ + GByteArray *array = data; + + memset (array->data, 0, array->len); + g_byte_array_unref (array); +} + +static GBytes * +file_to_secure_bytes (const char *filename) +{ + char *contents; + GByteArray *array = NULL; + gsize length = 0; + + if (g_file_get_contents (filename, &contents, &length, NULL)) { + array = g_byte_array_sized_new (length); + g_byte_array_append (array, (guint8 *) contents, length); + g_assert (array->len == length); + g_free (contents); + return g_bytes_new_with_free_func (array->data, array->len, free_secure_bytes, array); + } + return NULL; +} + +/** + * nm_setting_802_1x_set_private_key: + * @setting: the #NMSetting8021x + * @key_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or + * %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the private key file + * (PEM, DER, or PKCS#<!-- -->12 format). The path must be UTF-8 encoded; use + * g_filename_to_utf8() to convert if needed. Passing %NULL with any @scheme + * clears the private key. + * @password: password used to decrypt the private key, or %NULL if the password + * is unknown. If the password is given but fails to decrypt the private key, + * an error is returned. + * @scheme: desired storage scheme for the private key + * @out_format: on successful return, the type of the private key added + * @error: on unsuccessful return, an error + * + * Private keys are used to authenticate the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * This function reads a private key from disk and sets the + * #NMSetting8021x:private-key property with the private key file data if using + * the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme, or with the path to the private + * key file if using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. + * + * If @password is given, this function attempts to decrypt the private key to + * verify that @password is correct, and if it is, updates the + * #NMSetting8021x:private-key-password property with the given @password. If + * the decryption is unsuccessful, %FALSE is returned, @error is set, and no + * internal data is changed. If no @password is given, the private key is + * assumed to be valid, no decryption is performed, and the password may be set + * at a later time. + * + * WARNING: the private key property is not a "secret" property, and thus + * unencrypted private key data using the BLOB scheme may be readable by + * unprivileged users. Private keys should always be encrypted with a private + * key password to prevent unauthorized access to unencrypted private key data. + * + * Returns: %TRUE if the operation succeeded, %FALSE if it was unsuccessful + **/ +gboolean +nm_setting_802_1x_set_private_key (NMSetting8021x *setting, + const char *key_path, + const char *password, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError **error) +{ + NMSetting8021xPrivate *priv; + NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; + gboolean key_cleared = FALSE, password_cleared = FALSE; + GError *local_err = NULL; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + + if (key_path) { + g_return_val_if_fail (g_utf8_validate (key_path, -1, NULL), FALSE); + g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB + || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, + FALSE); + } + + if (out_format) + g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE); + + /* Ensure the private key is a recognized format and if the password was + * given, that it decrypts the private key. + */ + if (key_path) { + format = crypto_verify_private_key (key_path, password, NULL, &local_err); + if (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + local_err ? local_err->message : _("invalid private key")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY); + g_clear_error (&local_err); + return FALSE; + } + } + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + + /* Clear out any previous private key data */ + if (priv->private_key) { + g_bytes_unref (priv->private_key); + priv->private_key = NULL; + key_cleared = TRUE; + } + + if (priv->private_key_password) { + g_free (priv->private_key_password); + priv->private_key_password = NULL; + password_cleared = TRUE; + } + + if (key_path == NULL) { + if (key_cleared) + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PRIVATE_KEY); + if (password_cleared) + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD); + return TRUE; + } + + priv->private_key_password = g_strdup (password); + if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + /* Shouldn't fail this since we just verified the private key above */ + priv->private_key = file_to_secure_bytes (key_path); + g_assert (priv->private_key); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->private_key = path_to_scheme_value (key_path); + else + g_assert_not_reached (); + + /* As required by NM and wpa_supplicant, set the client-cert + * property to the same PKCS#12 data. + */ + g_assert (format != NM_CRYPTO_FILE_FORMAT_UNKNOWN); + if (format == NM_CRYPTO_FILE_FORMAT_PKCS12) { + if (priv->client_cert) + g_bytes_unref (priv->client_cert); + priv->client_cert = g_bytes_ref (priv->private_key); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CLIENT_CERT); + } + + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PRIVATE_KEY); + if (password_cleared || password) + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD); + + if (out_format) + *out_format = (NMSetting8021xCKFormat) format; + return priv->private_key != NULL; +} + +/** + * nm_setting_802_1x_get_private_key_password: + * @setting: the #NMSetting8021x + * + * Returns: the private key password used to decrypt the private key if + * previously set with nm_setting_802_1x_set_private_key(), or the + * #NMSetting8021x:private-key-password property. + **/ +const char * +nm_setting_802_1x_get_private_key_password (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key_password; +} + +/** + * nm_setting_802_1x_get_private_key_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:private-key-password + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_private_key_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key_password_flags; +} + +/** + * nm_setting_802_1x_get_private_key_format: + * @setting: the #NMSetting8021x + * + * Returns: the data format of the private key data stored in the + * #NMSetting8021x:private-key property + **/ +NMSetting8021xCKFormat +nm_setting_802_1x_get_private_key_format (NMSetting8021x *setting) +{ + NMSetting8021xPrivate *priv; + const char *path; + GError *error = NULL; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + + if (!priv->private_key) + return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + + switch (nm_setting_802_1x_get_private_key_scheme (setting)) { + case NM_SETTING_802_1X_CK_SCHEME_BLOB: + if (crypto_is_pkcs12_data (g_bytes_get_data (priv->private_key, NULL), + g_bytes_get_size (priv->private_key), + NULL)) + return NM_SETTING_802_1X_CK_FORMAT_PKCS12; + return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; + case NM_SETTING_802_1X_CK_SCHEME_PATH: + path = nm_setting_802_1x_get_private_key_path (setting); + if (crypto_is_pkcs12_file (path, &error)) + return NM_SETTING_802_1X_CK_FORMAT_PKCS12; + if (error && error->domain == G_FILE_ERROR) { + g_error_free (error); + return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + } + return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; + default: + break; + } + + return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; +} + +/** + * nm_setting_802_1x_get_phase2_private_key_password: + * @setting: the #NMSetting8021x + * + * Returns: the private key password used to decrypt the private key if + * previously set with nm_setting_802_1x_set_phase2_private_key() or the + * #NMSetting8021x:phase2-private-key-password property. + **/ +const char * +nm_setting_802_1x_get_phase2_private_key_password (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key_password; +} + +/** + * nm_setting_802_1x_get_phase2_private_key_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:phase2-private-key-password + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_phase2_private_key_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key_password_flags; +} + +/** + * nm_setting_802_1x_get_phase2_private_key_scheme: + * @setting: the #NMSetting8021x + * + * Returns the scheme used to store the "phase 2" private key. If the returned + * scheme is %NM_SETTING_802_1X_CK_SCHEME_BLOB, use + * nm_setting_802_1x_get_client_cert_blob(); if + * %NM_SETTING_802_1X_CK_SCHEME_PATH, use + * nm_setting_802_1x_get_client_cert_path(). + * + * Returns: scheme used to store the "phase 2" private key (blob or path) + **/ +NMSetting8021xCKScheme +nm_setting_802_1x_get_phase2_private_key_scheme (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN); + + return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key); +} + +/** + * nm_setting_802_1x_get_phase2_private_key_blob: + * @setting: the #NMSetting8021x + * + * Private keys are used to authenticate the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * WARNING: the phase2 private key property is not a "secret" property, and thus + * unencrypted private key data may be readable by unprivileged users. Private + * keys should always be encrypted with a private key password. + * + * Returns: (transfer none): the "phase 2" private key data + **/ +GBytes * +nm_setting_802_1x_get_phase2_private_key_blob (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_phase2_private_key_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key; +} + +/** + * nm_setting_802_1x_get_phase2_private_key_path: + * @setting: the #NMSetting8021x + * + * Private keys are used to authenticate the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * Returns: path to the "phase 2" private key file + **/ +const char * +nm_setting_802_1x_get_phase2_private_key_path (NMSetting8021x *setting) +{ + NMSetting8021xCKScheme scheme; + gconstpointer data; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + scheme = nm_setting_802_1x_get_phase2_private_key_scheme (setting); + g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL); + + data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key, NULL); + return (const char *)data + strlen (SCHEME_PATH); +} + +/** + * nm_setting_802_1x_set_phase2_private_key: + * @setting: the #NMSetting8021x + * @key_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or + * %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" private + * key file (PEM, DER, or PKCS#<!-- -->12 format). The path must be UTF-8 encoded; + * use g_filename_to_utf8() to convert if needed. Passing %NULL with any + * @scheme clears the private key. + * @password: password used to decrypt the private key, or %NULL if the password + * is unknown. If the password is given but fails to decrypt the private key, + * an error is returned. + * @scheme: desired storage scheme for the private key + * @out_format: on successful return, the type of the private key added + * @error: on unsuccessful return, an error + * + * Private keys are used to authenticate the connecting client to the network + * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x + * authentication method. + * + * This function reads a private key from disk and sets the + * #NMSetting8021x:phase2-private-key property with the private key file data if + * using the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme, or with the path to the + * private key file if using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. + * + * If @password is given, this function attempts to decrypt the private key to + * verify that @password is correct, and if it is, updates the + * #NMSetting8021x:phase2-private-key-password property with the given + * @password. If the decryption is unsuccessful, %FALSE is returned, @error is + * set, and no internal data is changed. If no @password is given, the private + * key is assumed to be valid, no decryption is performed, and the password may + * be set at a later time. + * + * WARNING: the "phase2" private key property is not a "secret" property, and + * thus unencrypted private key data using the BLOB scheme may be readable by + * unprivileged users. Private keys should always be encrypted with a private + * key password to prevent unauthorized access to unencrypted private key data. + * + * Returns: %TRUE if the operation succeeded, %FALSE if it was unsuccessful + **/ +gboolean +nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *setting, + const char *key_path, + const char *password, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError **error) +{ + NMSetting8021xPrivate *priv; + NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; + gboolean key_cleared = FALSE, password_cleared = FALSE; + GError *local_err = NULL; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + + if (key_path) { + g_return_val_if_fail (g_utf8_validate (key_path, -1, NULL), FALSE); + g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB + || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, + FALSE); + } + + if (out_format) + g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE); + + /* Ensure the private key is a recognized format and if the password was + * given, that it decrypts the private key. + */ + if (key_path) { + format = crypto_verify_private_key (key_path, password, NULL, &local_err); + if (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + local_err ? local_err->message : _("invalid phase2 private key")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + g_clear_error (&local_err); + return FALSE; + } + } + + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + + /* Clear out any previous private key data */ + if (priv->phase2_private_key) { + g_bytes_unref (priv->phase2_private_key); + priv->phase2_private_key = NULL; + key_cleared = TRUE; + } + + if (priv->phase2_private_key_password) { + g_free (priv->phase2_private_key_password); + priv->phase2_private_key_password = NULL; + password_cleared = TRUE; + } + + if (key_path == NULL) { + if (key_cleared) + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + if (password_cleared) + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD); + return TRUE; + } + + priv->phase2_private_key_password = g_strdup (password); + if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + /* Shouldn't fail this since we just verified the private key above */ + priv->phase2_private_key = file_to_secure_bytes (key_path); + g_assert (priv->phase2_private_key); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->phase2_private_key = path_to_scheme_value (key_path); + else + g_assert_not_reached (); + + /* As required by NM and wpa_supplicant, set the client-cert + * property to the same PKCS#12 data. + */ + g_assert (format != NM_CRYPTO_FILE_FORMAT_UNKNOWN); + if (format == NM_CRYPTO_FILE_FORMAT_PKCS12) { + if (priv->phase2_client_cert) + g_bytes_unref (priv->phase2_client_cert); + + priv->phase2_client_cert = g_bytes_ref (priv->phase2_private_key); + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CLIENT_CERT); + } + + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + if (password_cleared || password) + g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD); + + if (out_format) + *out_format = (NMSetting8021xCKFormat) format; + return priv->phase2_private_key != NULL; +} + +/** + * nm_setting_802_1x_get_phase2_private_key_format: + * @setting: the #NMSetting8021x + * + * Returns: the data format of the "phase 2" private key data stored in the + * #NMSetting8021x:phase2-private-key property + **/ +NMSetting8021xCKFormat +nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting) +{ + NMSetting8021xPrivate *priv; + const char *path; + GError *error = NULL; + + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + + if (!priv->phase2_private_key) + return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + + switch (nm_setting_802_1x_get_phase2_private_key_scheme (setting)) { + case NM_SETTING_802_1X_CK_SCHEME_BLOB: + if (crypto_is_pkcs12_data (g_bytes_get_data (priv->phase2_private_key, NULL), + g_bytes_get_size (priv->phase2_private_key), + NULL)) + return NM_SETTING_802_1X_CK_FORMAT_PKCS12; + return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; + case NM_SETTING_802_1X_CK_SCHEME_PATH: + path = nm_setting_802_1x_get_phase2_private_key_path (setting); + if (crypto_is_pkcs12_file (path, &error)) + return NM_SETTING_802_1X_CK_FORMAT_PKCS12; + if (error && error->domain == G_FILE_ERROR) { + g_error_free (error); + return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + } + return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; + default: + break; + } + + return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; +} + +static void +need_secrets_password (NMSetting8021x *self, + GPtrArray *secrets, + gboolean phase2) +{ + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + + if ( (!priv->password || !strlen (priv->password)) + && (!priv->password_raw || !g_bytes_get_size (priv->password_raw))) { + g_ptr_array_add (secrets, NM_SETTING_802_1X_PASSWORD); + g_ptr_array_add (secrets, NM_SETTING_802_1X_PASSWORD_RAW); + } +} + +static void +need_secrets_sim (NMSetting8021x *self, + GPtrArray *secrets, + gboolean phase2) +{ + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + + if (!priv->pin || !strlen (priv->pin)) + g_ptr_array_add (secrets, NM_SETTING_802_1X_PIN); +} + +static gboolean +need_private_key_password (GBytes *blob, + const char *path, + const char *password) +{ + NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; + + /* Private key password is required */ + if (password) { + if (path) + format = crypto_verify_private_key (path, password, NULL, NULL); + else if (blob) + format = crypto_verify_private_key_data (g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob), + password, NULL, NULL); + else + g_warning ("%s: unknown private key password scheme", __func__); + } + + return (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN); +} + +static void +need_secrets_tls (NMSetting8021x *self, + GPtrArray *secrets, + gboolean phase2) +{ + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + NMSetting8021xCKScheme scheme; + GBytes *blob = NULL; + const char *path = NULL; + + if (phase2) { + scheme = nm_setting_802_1x_get_phase2_private_key_scheme (self); + if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + path = nm_setting_802_1x_get_phase2_private_key_path (self); + else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) + blob = nm_setting_802_1x_get_phase2_private_key_blob (self); + else { + g_warning ("%s: unknown phase2 private key scheme %d", __func__, scheme); + g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + return; + } + + if (need_private_key_password (blob, path, priv->phase2_private_key_password)) + g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD); + } else { + scheme = nm_setting_802_1x_get_private_key_scheme (self); + if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + path = nm_setting_802_1x_get_private_key_path (self); + else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) + blob = nm_setting_802_1x_get_private_key_blob (self); + else { + g_warning ("%s: unknown private key scheme %d", __func__, scheme); + g_ptr_array_add (secrets, NM_SETTING_802_1X_PRIVATE_KEY); + return; + } + + if (need_private_key_password (blob, path, priv->private_key_password)) + g_ptr_array_add (secrets, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD); + } +} + +static gboolean +verify_tls (NMSetting8021x *self, gboolean phase2, GError **error) +{ + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + + if (phase2) { + if (!priv->phase2_client_cert) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_CLIENT_CERT); + return FALSE; + } else if (!g_bytes_get_size (priv->phase2_client_cert)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_CLIENT_CERT); + return FALSE; + } + + /* Private key is required for TLS */ + if (!priv->phase2_private_key) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + return FALSE; + } else if (!g_bytes_get_size (priv->phase2_private_key)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + return FALSE; + } + + /* If the private key is PKCS#12, check that it matches the client cert */ + if (crypto_is_pkcs12_data (g_bytes_get_data (priv->phase2_private_key, NULL), + g_bytes_get_size (priv->phase2_private_key), + NULL)) { + if (!g_bytes_equal (priv->phase2_private_key, priv->phase2_client_cert)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("has to match '%s' property for PKCS#12"), + NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_CLIENT_CERT); + return FALSE; + } + } + } else { + if (!priv->client_cert) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT); + return FALSE; + } else if (!g_bytes_get_size (priv->client_cert)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT); + return FALSE; + } + + /* Private key is required for TLS */ + if (!priv->private_key) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY); + return FALSE; + } else if (!g_bytes_get_size (priv->private_key)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY); + return FALSE; + } + + /* If the private key is PKCS#12, check that it matches the client cert */ + if (crypto_is_pkcs12_data (g_bytes_get_data (priv->private_key, NULL), + g_bytes_get_size (priv->private_key), + NULL)) { + if (!g_bytes_equal (priv->private_key, priv->client_cert)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("has to match '%s' property for PKCS#12"), + NM_SETTING_802_1X_PRIVATE_KEY); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT); + return FALSE; + } + } + } + + return TRUE; +} + +static gboolean +verify_ttls (NMSetting8021x *self, gboolean phase2, GError **error) +{ + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + + if ( (!priv->identity || !strlen (priv->identity)) + && (!priv->anonymous_identity || !strlen (priv->anonymous_identity))) { + if (!priv->identity) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_IDENTITY); + } else if (!strlen (priv->identity)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_IDENTITY); + } else if (!priv->anonymous_identity) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_ANONYMOUS_IDENTITY); + } else { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_ANONYMOUS_IDENTITY); + } + return FALSE; + } + + if ( (!priv->phase2_auth || !strlen (priv->phase2_auth)) + && (!priv->phase2_autheap || !strlen (priv->phase2_autheap))) { + if (!priv->phase2_auth) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_AUTH); + } else if (!strlen (priv->phase2_auth)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_AUTH); + } else if (!priv->phase2_autheap) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_AUTHEAP); + } else { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_AUTHEAP); + } + return FALSE; + } + + return TRUE; +} + +static gboolean +verify_identity (NMSetting8021x *self, gboolean phase2, GError **error) +{ + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + + if (!priv->identity) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_IDENTITY); + return FALSE; + } else if (!strlen (priv->identity)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_IDENTITY); + return FALSE; + } + + return TRUE; +} + +/* Implemented below... */ +static void need_secrets_phase2 (NMSetting8021x *self, + GPtrArray *secrets, + gboolean phase2); + + +typedef void (*EAPMethodNeedSecretsFunc) (NMSetting8021x *self, + GPtrArray *secrets, + gboolean phase2); + +typedef gboolean (*EAPMethodValidateFunc)(NMSetting8021x *self, + gboolean phase2, + GError **error); + +typedef struct { + const char *method; + EAPMethodNeedSecretsFunc ns_func; + EAPMethodValidateFunc v_func; +} EAPMethodsTable; + +static EAPMethodsTable eap_methods_table[] = { + { "leap", need_secrets_password, verify_identity }, + { "pwd", need_secrets_password, verify_identity }, + { "md5", need_secrets_password, verify_identity }, + { "pap", need_secrets_password, verify_identity }, + { "chap", need_secrets_password, verify_identity }, + { "mschap", need_secrets_password, verify_identity }, + { "mschapv2", need_secrets_password, verify_identity }, + { "fast", need_secrets_password, verify_identity }, + { "tls", need_secrets_tls, verify_tls }, + { "peap", need_secrets_phase2, verify_ttls }, + { "ttls", need_secrets_phase2, verify_ttls }, + { "sim", need_secrets_sim, NULL }, + { "gtc", need_secrets_password, verify_identity }, + { "otp", NULL, NULL }, // FIXME: implement + { NULL, NULL, NULL } +}; + +static void +need_secrets_phase2 (NMSetting8021x *self, + GPtrArray *secrets, + gboolean phase2) +{ + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + char *method = NULL; + int i; + + g_return_if_fail (phase2 == FALSE); + + /* Check phase2_auth and phase2_autheap */ + method = priv->phase2_auth; + if (!method && priv->phase2_autheap) + method = priv->phase2_autheap; + + if (!method) { + g_warning ("Couldn't find EAP method."); + g_assert_not_reached(); + return; + } + + /* Ask the configured phase2 method if it needs secrets */ + for (i = 0; eap_methods_table[i].method; i++) { + if (eap_methods_table[i].ns_func == NULL) + continue; + if (!strcmp (eap_methods_table[i].method, method)) { + (*eap_methods_table[i].ns_func) (self, secrets, TRUE); + break; + } + } +} + + +static GPtrArray * +need_secrets (NMSetting *setting) +{ + NMSetting8021x *self = NM_SETTING_802_1X (setting); + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + GSList *iter; + GPtrArray *secrets; + gboolean eap_method_found = FALSE; + + secrets = g_ptr_array_sized_new (4); + + /* Ask each configured EAP method if it needs secrets */ + for (iter = priv->eap; iter && !eap_method_found; iter = g_slist_next (iter)) { + const char *method = (const char *) iter->data; + int i; + + for (i = 0; eap_methods_table[i].method; i++) { + if (eap_methods_table[i].ns_func == NULL) + continue; + if (!strcmp (eap_methods_table[i].method, method)) { + (*eap_methods_table[i].ns_func) (self, secrets, FALSE); + + /* Only break out of the outer loop if this EAP method + * needed secrets. + */ + if (secrets->len > 0) + eap_method_found = TRUE; + break; + } + } + } + + if (secrets->len == 0) { + g_ptr_array_free (secrets, TRUE); + secrets = NULL; + } + + return secrets; +} + +static gboolean +verify_cert (GBytes *bytes, const char *prop_name, GError **error) +{ + gconstpointer data; + gsize length; + + if (!bytes) + return TRUE; + + switch (get_cert_scheme (bytes)) { + case NM_SETTING_802_1X_CK_SCHEME_BLOB: + return TRUE; + case NM_SETTING_802_1X_CK_SCHEME_PATH: + /* For path-based schemes, verify that the path is zero-terminated */ + data = g_bytes_get_data (bytes, &length); + if (((const guchar *)data)[length - 1] == '\0') { + /* And ensure it's UTF-8 valid too so we can pass it through + * D-Bus and stuff like that. + */ + if (g_utf8_validate ((const char *)data + strlen (SCHEME_PATH), -1, NULL)) + return TRUE; + } + break; + default: + break; + } + + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is invalid")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, prop_name); + return FALSE; +} + +static gboolean +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSetting8021x *self = NM_SETTING_802_1X (setting); + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + const char *valid_eap[] = { "leap", "md5", "tls", "peap", "ttls", "sim", "fast", "pwd", NULL }; + const char *valid_phase1_peapver[] = { "0", "1", NULL }; + const char *valid_phase1_peaplabel[] = { "0", "1", NULL }; + const char *valid_phase1_fast_pac[] = { "0", "1", "2", "3", NULL }; + const char *valid_phase2_auth[] = { "pap", "chap", "mschap", "mschapv2", "gtc", "otp", "md5", "tls", NULL }; + const char *valid_phase2_autheap[] = { "md5", "mschapv2", "otp", "gtc", "tls", NULL }; + GSList *iter; + + if (error) + g_return_val_if_fail (*error == NULL, FALSE); + + if (!priv->eap) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_EAP); + return FALSE; + } + + if (!_nm_utils_string_slist_validate (priv->eap, valid_eap)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is invalid")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_EAP); + return FALSE; + } + + /* Ask each configured EAP method if its valid */ + for (iter = priv->eap; iter; iter = g_slist_next (iter)) { + const char *method = (const char *) iter->data; + int i; + + for (i = 0; eap_methods_table[i].method; i++) { + if (eap_methods_table[i].v_func == NULL) + continue; + if (!strcmp (eap_methods_table[i].method, method)) { + if (!(*eap_methods_table[i].v_func) (self, FALSE, error)) + return FALSE; + break; + } + } + } + + if (priv->phase1_peapver && !_nm_utils_string_in_list (priv->phase1_peapver, valid_phase1_peapver)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for the property"), + priv->phase1_peapver); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE1_PEAPVER); + return FALSE; + } + + if (priv->phase1_peaplabel && !_nm_utils_string_in_list (priv->phase1_peaplabel, valid_phase1_peaplabel)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for the property"), + priv->phase1_peaplabel); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE1_PEAPLABEL); + return FALSE; + } + + if (priv->phase1_fast_provisioning && !_nm_utils_string_in_list (priv->phase1_fast_provisioning, valid_phase1_fast_pac)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for the property"), + priv->phase1_fast_provisioning); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING); + return FALSE; + } + + if (priv->phase2_auth && !_nm_utils_string_in_list (priv->phase2_auth, valid_phase2_auth)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for the property"), + priv->phase2_auth); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_AUTH); + return FALSE; + } + + if (priv->phase2_autheap && !_nm_utils_string_in_list (priv->phase2_autheap, valid_phase2_autheap)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid value for the property"), + priv->phase2_autheap); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_AUTHEAP); + return FALSE; + } + + if (!verify_cert (priv->ca_cert, NM_SETTING_802_1X_CA_CERT, error)) + return FALSE; + if (!verify_cert (priv->phase2_ca_cert, NM_SETTING_802_1X_PHASE2_CA_CERT, error)) + return FALSE; + + if (!verify_cert (priv->client_cert, NM_SETTING_802_1X_CLIENT_CERT, error)) + return FALSE; + if (!verify_cert (priv->phase2_client_cert, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, error)) + return FALSE; + + if (!verify_cert (priv->private_key, NM_SETTING_802_1X_PRIVATE_KEY, error)) + return FALSE; + if (!verify_cert (priv->phase2_private_key, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, error)) + return FALSE; + + /* FIXME: finish */ + + return TRUE; +} + +static void +nm_setting_802_1x_init (NMSetting8021x *setting) +{ +} + +static void +finalize (GObject *object) +{ + NMSetting8021x *self = NM_SETTING_802_1X (object); + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self); + + /* Strings first. g_free() already checks for NULLs so we don't have to */ + + g_free (priv->identity); + g_free (priv->anonymous_identity); + g_free (priv->ca_path); + g_free (priv->subject_match); + g_free (priv->phase1_peapver); + g_free (priv->phase1_peaplabel); + g_free (priv->phase1_fast_provisioning); + g_free (priv->phase2_auth); + g_free (priv->phase2_autheap); + g_free (priv->phase2_ca_path); + g_free (priv->phase2_subject_match); + g_free (priv->password); + if (priv->password_raw) + g_bytes_unref (priv->password_raw); + g_free (priv->pin); + + g_slist_free_full (priv->eap, g_free); + g_slist_free_full (priv->altsubject_matches, g_free); + g_slist_free_full (priv->phase2_altsubject_matches, g_free); + + if (priv->ca_cert) + g_bytes_unref (priv->ca_cert); + if (priv->client_cert) + g_bytes_unref (priv->client_cert); + if (priv->private_key) + g_bytes_unref (priv->private_key); + g_free (priv->private_key_password); + if (priv->phase2_ca_cert) + g_bytes_unref (priv->phase2_ca_cert); + if (priv->phase2_client_cert) + g_bytes_unref (priv->phase2_client_cert); + if (priv->phase2_private_key) + g_bytes_unref (priv->phase2_private_key); + g_free (priv->phase2_private_key_password); + + G_OBJECT_CLASS (nm_setting_802_1x_parent_class)->finalize (object); +} + +static GBytes * +set_cert_prop_helper (const GValue *value, const char *prop_name, GError **error) +{ + gboolean valid; + GBytes *bytes = NULL; + + bytes = g_value_dup_boxed (value); + /* Verify the new data */ + if (bytes) { + valid = verify_cert (bytes, prop_name, error); + if (!valid) + g_clear_pointer (&bytes, g_bytes_unref); + } + return bytes; +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSetting8021x *setting = NM_SETTING_802_1X (object); + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + GError *error = NULL; + + switch (prop_id) { + case PROP_EAP: + g_slist_free_full (priv->eap, g_free); + priv->eap = _nm_utils_strv_to_slist (g_value_get_boxed (value)); + break; + case PROP_IDENTITY: + g_free (priv->identity); + priv->identity = g_value_dup_string (value); + break; + case PROP_ANONYMOUS_IDENTITY: + g_free (priv->anonymous_identity); + priv->anonymous_identity = g_value_dup_string (value); + break; + case PROP_PAC_FILE: + g_free (priv->pac_file); + priv->pac_file = g_value_dup_string (value); + break; + case PROP_CA_CERT: + if (priv->ca_cert) + g_bytes_unref (priv->ca_cert); + priv->ca_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_CA_CERT, &error); + if (error) { + g_warning ("Error setting certificate (invalid data): (%d) %s", + error->code, error->message); + g_error_free (error); + } + break; + case PROP_CA_PATH: + g_free (priv->ca_path); + priv->ca_path = g_value_dup_string (value); + break; + case PROP_SUBJECT_MATCH: + g_free (priv->subject_match); + priv->subject_match = g_value_dup_string (value); + break; + case PROP_ALTSUBJECT_MATCHES: + g_slist_free_full (priv->altsubject_matches, g_free); + priv->altsubject_matches = _nm_utils_strv_to_slist (g_value_get_boxed (value)); + break; + case PROP_CLIENT_CERT: + if (priv->client_cert) + g_bytes_unref (priv->client_cert); + priv->client_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_CLIENT_CERT, &error); + if (error) { + g_warning ("Error setting certificate (invalid data): (%d) %s", + error->code, error->message); + g_error_free (error); + } + break; + case PROP_PHASE1_PEAPVER: + g_free (priv->phase1_peapver); + priv->phase1_peapver = g_value_dup_string (value); + break; + case PROP_PHASE1_PEAPLABEL: + g_free (priv->phase1_peaplabel); + priv->phase1_peaplabel = g_value_dup_string (value); + break; + case PROP_PHASE1_FAST_PROVISIONING: + g_free (priv->phase1_fast_provisioning); + priv->phase1_fast_provisioning = g_value_dup_string (value); + break; + case PROP_PHASE2_AUTH: + g_free (priv->phase2_auth); + priv->phase2_auth = g_value_dup_string (value); + break; + case PROP_PHASE2_AUTHEAP: + g_free (priv->phase2_autheap); + priv->phase2_autheap = g_value_dup_string (value); + break; + case PROP_PHASE2_CA_CERT: + if (priv->phase2_ca_cert) + g_bytes_unref (priv->phase2_ca_cert); + priv->phase2_ca_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_CA_CERT, &error); + if (error) { + g_warning ("Error setting certificate (invalid data): (%d) %s", + error->code, error->message); + g_error_free (error); + } + break; + case PROP_PHASE2_CA_PATH: + g_free (priv->phase2_ca_path); + priv->phase2_ca_path = g_value_dup_string (value); + break; + case PROP_PHASE2_SUBJECT_MATCH: + g_free (priv->phase2_subject_match); + priv->phase2_subject_match = g_value_dup_string (value); + break; + case PROP_PHASE2_ALTSUBJECT_MATCHES: + g_slist_free_full (priv->phase2_altsubject_matches, g_free); + priv->phase2_altsubject_matches = _nm_utils_strv_to_slist (g_value_get_boxed (value)); + break; + case PROP_PHASE2_CLIENT_CERT: + if (priv->phase2_client_cert) + g_bytes_unref (priv->phase2_client_cert); + priv->phase2_client_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &error); + if (error) { + g_warning ("Error setting certificate (invalid data): (%d) %s", + error->code, error->message); + g_error_free (error); + } + break; + case PROP_PASSWORD: + g_free (priv->password); + priv->password = g_value_dup_string (value); + break; + case PROP_PASSWORD_FLAGS: + priv->password_flags = g_value_get_flags (value); + break; + case PROP_PASSWORD_RAW: + if (priv->password_raw) + g_bytes_unref (priv->password_raw); + priv->password_raw = g_value_dup_boxed (value); + break; + case PROP_PASSWORD_RAW_FLAGS: + priv->password_raw_flags = g_value_get_flags (value); + break; + case PROP_PRIVATE_KEY: + if (priv->private_key) + g_bytes_unref (priv->private_key); + priv->private_key = set_cert_prop_helper (value, NM_SETTING_802_1X_PRIVATE_KEY, &error); + if (error) { + g_warning ("Error setting private key (invalid data): (%d) %s", + error->code, error->message); + g_error_free (error); + } + break; + case PROP_PRIVATE_KEY_PASSWORD: + g_free (priv->private_key_password); + priv->private_key_password = g_value_dup_string (value); + break; + case PROP_PRIVATE_KEY_PASSWORD_FLAGS: + priv->private_key_password_flags = g_value_get_flags (value); + break; + case PROP_PHASE2_PRIVATE_KEY: + if (priv->phase2_private_key) + g_bytes_unref (priv->phase2_private_key); + priv->phase2_private_key = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &error); + if (error) { + g_warning ("Error setting private key (invalid data): (%d) %s", + error->code, error->message); + g_error_free (error); + } + break; + case PROP_PHASE2_PRIVATE_KEY_PASSWORD: + g_free (priv->phase2_private_key_password); + priv->phase2_private_key_password = g_value_dup_string (value); + break; + case PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS: + priv->phase2_private_key_password_flags = g_value_get_flags (value); + break; + case PROP_PIN: + g_free (priv->pin); + priv->pin = g_value_dup_string (value); + break; + case PROP_PIN_FLAGS: + priv->pin_flags = g_value_get_flags (value); + break; + case PROP_SYSTEM_CA_CERTS: + priv->system_ca_certs = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSetting8021x *setting = NM_SETTING_802_1X (object); + NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (setting); + + switch (prop_id) { + case PROP_EAP: + g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->eap)); + break; + case PROP_IDENTITY: + g_value_set_string (value, priv->identity); + break; + case PROP_ANONYMOUS_IDENTITY: + g_value_set_string (value, priv->anonymous_identity); + break; + case PROP_PAC_FILE: + g_value_set_string (value, priv->pac_file); + break; + case PROP_CA_CERT: + g_value_set_boxed (value, priv->ca_cert); + break; + case PROP_CA_PATH: + g_value_set_string (value, priv->ca_path); + break; + case PROP_SUBJECT_MATCH: + g_value_set_string (value, priv->subject_match); + break; + case PROP_ALTSUBJECT_MATCHES: + g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->altsubject_matches)); + break; + case PROP_CLIENT_CERT: + g_value_set_boxed (value, priv->client_cert); + break; + case PROP_PHASE1_PEAPVER: + g_value_set_string (value, priv->phase1_peapver); + break; + case PROP_PHASE1_PEAPLABEL: + g_value_set_string (value, priv->phase1_peaplabel); + break; + case PROP_PHASE1_FAST_PROVISIONING: + g_value_set_string (value, priv->phase1_fast_provisioning); + break; + case PROP_PHASE2_AUTH: + g_value_set_string (value, priv->phase2_auth); + break; + case PROP_PHASE2_AUTHEAP: + g_value_set_string (value, priv->phase2_autheap); + break; + case PROP_PHASE2_CA_CERT: + g_value_set_boxed (value, priv->phase2_ca_cert); + break; + case PROP_PHASE2_CA_PATH: + g_value_set_string (value, priv->phase2_ca_path); + break; + case PROP_PHASE2_SUBJECT_MATCH: + g_value_set_string (value, priv->phase2_subject_match); + break; + case PROP_PHASE2_ALTSUBJECT_MATCHES: + g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->phase2_altsubject_matches)); + break; + case PROP_PHASE2_CLIENT_CERT: + g_value_set_boxed (value, priv->phase2_client_cert); + break; + case PROP_PASSWORD: + g_value_set_string (value, priv->password); + break; + case PROP_PASSWORD_FLAGS: + g_value_set_flags (value, priv->password_flags); + break; + case PROP_PASSWORD_RAW: + g_value_set_boxed (value, priv->password_raw); + break; + case PROP_PASSWORD_RAW_FLAGS: + g_value_set_flags (value, priv->password_raw_flags); + break; + case PROP_PRIVATE_KEY: + g_value_set_boxed (value, priv->private_key); + break; + case PROP_PRIVATE_KEY_PASSWORD: + g_value_set_string (value, priv->private_key_password); + break; + case PROP_PRIVATE_KEY_PASSWORD_FLAGS: + g_value_set_flags (value, priv->private_key_password_flags); + break; + case PROP_PHASE2_PRIVATE_KEY: + g_value_set_boxed (value, priv->phase2_private_key); + break; + case PROP_PHASE2_PRIVATE_KEY_PASSWORD: + g_value_set_string (value, priv->phase2_private_key_password); + break; + case PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS: + g_value_set_flags (value, priv->phase2_private_key_password_flags); + break; + case PROP_PIN: + g_value_set_string (value, priv->pin); + break; + case PROP_PIN_FLAGS: + g_value_set_flags (value, priv->pin_flags); + break; + case PROP_SYSTEM_CA_CERTS: + g_value_set_boolean (value, priv->system_ca_certs); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + g_type_class_add_private (setting_class, sizeof (NMSetting8021xPrivate)); + + /* virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + + parent_class->verify = verify; + parent_class->need_secrets = need_secrets; + + /* Properties */ + + /** + * NMSetting8021x:eap: + * + * The allowed EAP method to be used when authenticating to the network with + * 802.1x. Valid methods are: "leap", "md5", "tls", "peap", "ttls", "pwd", + * and "fast". Each method requires different configuration using the + * properties of this setting; refer to wpa_supplicant documentation for the + * allowed combinations. + **/ + /* ---ifcfg-rh--- + * property: eap + * variable: IEEE_8021X_EAP_METHODS(+) + * values: "LEAP", "PWD", "TLS", "PEAP", "TTLS", "FAST" + * description: EAP method for 802.1X authentication. + * example: IEEE_8021X_EAP_METHODS=PEAP + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_EAP, + g_param_spec_boxed (NM_SETTING_802_1X_EAP, "", "", + G_TYPE_STRV, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:identity: + * + * Identity string for EAP authentication methods. Often the user's user or + * login name. + **/ + /* ---ifcfg-rh--- + * property: identity + * variable: IEEE_8021X_IDENTITY(+) + * description: Identity for EAP authentication methods. + * example: IEEE_8021X_IDENTITY=itsme + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_IDENTITY, + g_param_spec_string (NM_SETTING_802_1X_IDENTITY, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:anonymous-identity: + * + * Anonymous identity string for EAP authentication methods. Used as the + * unencrypted identity with EAP types that support different tunneled + * identity like EAP-TTLS. + **/ + /* ---ifcfg-rh--- + * property: anonymous-identity + * variable: IEEE_8021X_ANON_IDENTITY(+) + * description: Anonymous identity for EAP authentication methods. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_ANONYMOUS_IDENTITY, + g_param_spec_string (NM_SETTING_802_1X_ANONYMOUS_IDENTITY, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:pac-file: + * + * UTF-8 encoded file path containing PAC for EAP-FAST. + **/ + /* ---ifcfg-rh--- + * property: pac-file + * variable: IEEE_8021X_PAC_FILE(+) + * description: File with PAC (Protected Access Credential) for EAP-FAST. + * example: IEEE_8021X_PAC_FILE=/home/joe/my-fast.pac + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PAC_FILE, + g_param_spec_string (NM_SETTING_802_1X_PAC_FILE, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:ca-cert: + * + * Contains the CA certificate if used by the EAP method specified in the + * #NMSetting8021x:eap property. + * + * Certificate data is specified using a "scheme"; two are currently + * supported: blob and path. When using the blob scheme (which is backwards + * compatible with NM 0.7.x) this property should be set to the + * certificate's DER encoded data. When using the path scheme, this property + * should be set to the full UTF-8 encoded path of the certificate, prefixed + * with the string "file://" and ending with a terminating NUL byte. This + * property can be unset even if the EAP method supports CA certificates, + * but this allows man-in-the-middle attacks and is NOT recommended. + * + * Setting this property directly is discouraged; use the + * nm_setting_802_1x_set_ca_cert() function instead. + **/ + /* ---ifcfg-rh--- + * property: ca-cert + * variable: IEEE_8021X_CA_CERT(+) + * description: CA certificate for EAP. + * example: IEEE_8021X_CA_CERT=/home/joe/cacert.crt + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_CA_CERT, + g_param_spec_boxed (NM_SETTING_802_1X_CA_CERT, "", "", + G_TYPE_BYTES, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:ca-path: + * + * UTF-8 encoded path to a directory containing PEM or DER formatted + * certificates to be added to the verification chain in addition to the + * certificate specified in the #NMSetting8021x:ca-cert property. + **/ + /* ---ifcfg-rh--- + * property: ca-path + * variable: (none) + * description: The property is not handled by ifcfg-rh plugin. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_CA_PATH, + g_param_spec_string (NM_SETTING_802_1X_CA_PATH, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:subject-match: + * + * Substring to be matched against the subject of the certificate presented + * by the authentication server. When unset, no verification of the + * authentication server certificate's subject is performed. + **/ + /* ---ifcfg-rh--- + * property: subject-match + * variable: IEEE_8021X_SUBJECT_MATCH(+) + * description: Substring to match subject of server certificate against. + * example: IEEE_8021X_SUBJECT_MATCH="Red Hat" + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_SUBJECT_MATCH, + g_param_spec_string (NM_SETTING_802_1X_SUBJECT_MATCH, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:altsubject-matches: + * + * List of strings to be matched against the altSubjectName of the + * certificate presented by the authentication server. If the list is empty, + * no verification of the server certificate's altSubjectName is performed. + **/ + /* ---ifcfg-rh--- + * property: altubject-matches + * variable: IEEE_8021X_AlTSUBJECT_MATCHES(+) + * description: List of strings to be matched against the altSubjectName. + * example: IEEE_8021X_ALTSUBJECT_MATCHES="s1.domain.cc" + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_ALTSUBJECT_MATCHES, + g_param_spec_boxed (NM_SETTING_802_1X_ALTSUBJECT_MATCHES, "", "", + G_TYPE_STRV, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:client-cert: + * + * Contains the client certificate if used by the EAP method specified in + * the #NMSetting8021x:eap property. + * + * Certificate data is specified using a "scheme"; two are currently + * supported: blob and path. When using the blob scheme (which is backwards + * compatible with NM 0.7.x) this property should be set to the + * certificate's DER encoded data. When using the path scheme, this property + * should be set to the full UTF-8 encoded path of the certificate, prefixed + * with the string "file://" and ending with a terminating NUL byte. + * + * Setting this property directly is discouraged; use the + * nm_setting_802_1x_set_client_cert() function instead. + **/ + /* ---ifcfg-rh--- + * property: client-cert + * variable: IEEE_8021X_CLIENT_CERT(+) + * description: Client certificate for EAP. + * example: IEEE_8021X_CLIENT_CERT=/home/joe/mycert.crt + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_CLIENT_CERT, + g_param_spec_boxed (NM_SETTING_802_1X_CLIENT_CERT, "", "", + G_TYPE_BYTES, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase1-peapver: + * + * Forces which PEAP version is used when PEAP is set as the EAP method in + * the #NMSetting8021x:eap property. When unset, the version reported by + * the server will be used. Sometimes when using older RADIUS servers, it + * is necessary to force the client to use a particular PEAP version. To do + * so, this property may be set to "0" or "1" to force that specific PEAP + * version. + **/ + /* ---ifcfg-rh--- + * property: phase1-peapver + * variable: IEEE_8021X_PEAP_VERSION(+) + * values: 0, 1 + * description: Use to force a specific PEAP version. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE1_PEAPVER, + g_param_spec_string (NM_SETTING_802_1X_PHASE1_PEAPVER, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase1-peaplabel: + * + * Forces use of the new PEAP label during key derivation. Some RADIUS + * servers may require forcing the new PEAP label to interoperate with + * PEAPv1. Set to "1" to force use of the new PEAP label. See the + * wpa_supplicant documentation for more details. + **/ + /* ---ifcfg-rh--- + * property: phase1-peaplabel + * variable: IEEE_8021X_PEAP_FORCE_NEW_LABEL(+) + * values: yes, no + * default: no + * description: Use to force the new PEAP label during key derivation. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE1_PEAPLABEL, + g_param_spec_string (NM_SETTING_802_1X_PHASE1_PEAPLABEL, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase1-fast-provisioning: + * + * Enables or disables in-line provisioning of EAP-FAST credentials when + * FAST is specified as the EAP method in the #NMSetting8021x:eap property. + * Recognized values are "0" (disabled), "1" (allow unauthenticated + * provisioning), "2" (allow authenticated provisioning), and "3" (allow + * both authenticated and unauthenticated provisioning). See the + * wpa_supplicant documentation for more details. + **/ + /* ---ifcfg-rh--- + * property: phase1-fast-provisioning + * variable: IEEE_8021X_FAST_PROVISIONING(+) + * values: space-separated list of these values [allow-auth, allow-unauth] + * description: Enable in-line provisioning of EAP-FAST credentials. + * example: IEEE_8021X_FAST_PROVISIONING="allow-auth allow-unauth" + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE1_FAST_PROVISIONING, + g_param_spec_string (NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-auth: + * + * Specifies the allowed "phase 2" inner non-EAP authentication methods when + * an EAP method that uses an inner TLS tunnel is specified in the + * #NMSetting8021x:eap property. Recognized non-EAP "phase 2" methods are + * "pap", "chap", "mschap", "mschapv2", "gtc", "otp", "md5", and "tls". + * Each "phase 2" inner method requires specific parameters for successful + * authentication; see the wpa_supplicant documentation for more details. + **/ + /* ---ifcfg-rh--- + * property: phase2-auth + * variable: IEEE_8021X_INNER_AUTH_METHODS(+) + * values: "PAP", "CHAP", "MSCHAP", "MSCHAPV2", "GTC", "OTP", "MD5" and "TLS" + * description: Inner non-EAP authentication methods. IEEE_8021X_INNER_AUTH_METHODS + * can contain values both for 'phase2-auth' and 'phase2-autheap' properties. + * example: IEEE_8021X_INNER_AUTH_METHODS=PAP + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_AUTH, + g_param_spec_string (NM_SETTING_802_1X_PHASE2_AUTH, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-autheap: + * + * Specifies the allowed "phase 2" inner EAP-based authentication methods + * when an EAP method that uses an inner TLS tunnel is specified in the + * #NMSetting8021x:eap property. Recognized EAP-based "phase 2" methods are + * "md5", "mschapv2", "otp", "gtc", and "tls". Each "phase 2" inner method + * requires specific parameters for successful authentication; see the + * wpa_supplicant documentation for more details. + **/ + /* ---ifcfg-rh--- + * property: phase2-autheap + * variable: IEEE_8021X_INNER_AUTH_METHODS(+) + * values: "EAP-MD5", "EAP-MSCHAPV2", "EAP-GTC", "EAP-OTP" and "EAP-TLS" + * description: Inner EAP-based authentication methods. Note that + * IEEE_8021X_INNER_AUTH_METHODS is also used for 'phase2-auth' values. + * example: IEEE_8021X_INNER_AUTH_METHODS="MSCHAPV2 EAP-TLS" + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_AUTHEAP, + g_param_spec_string (NM_SETTING_802_1X_PHASE2_AUTHEAP, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-ca-cert: + * + * Contains the "phase 2" CA certificate if used by the EAP method specified + * in the #NMSetting8021x:phase2-auth or #NMSetting8021x:phase2-autheap + * properties. + * + * Certificate data is specified using a "scheme"; two are currently + * supported: blob and path. When using the blob scheme (which is backwards + * compatible with NM 0.7.x) this property should be set to the + * certificate's DER encoded data. When using the path scheme, this property + * should be set to the full UTF-8 encoded path of the certificate, prefixed + * with the string "file://" and ending with a terminating NUL byte. This + * property can be unset even if the EAP method supports CA certificates, + * but this allows man-in-the-middle attacks and is NOT recommended. + * + * Setting this property directly is discouraged; use the + * nm_setting_802_1x_set_phase2_ca_cert() function instead. + **/ + g_object_class_install_property + (object_class, PROP_PHASE2_CA_CERT, + g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_CA_CERT, "", "", + G_TYPE_BYTES, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-ca-path: + * + * UTF-8 encoded path to a directory containing PEM or DER formatted + * certificates to be added to the verification chain in addition to the + * certificate specified in the #NMSetting8021x:phase2-ca-cert property. + **/ + g_object_class_install_property + (object_class, PROP_PHASE2_CA_PATH, + g_param_spec_string (NM_SETTING_802_1X_PHASE2_CA_PATH, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-subject-match: + * + * Substring to be matched against the subject of the certificate presented + * by the authentication server during the inner "phase 2" + * authentication. When unset, no verification of the authentication server + * certificate's subject is performed. + **/ + /* ---ifcfg-rh--- + * property: phase2-subject-match + * variable: IEEE_8021X_PHASE2_SUBJECT_MATCH(+) + * description: Substring to match subject of server certificate against. + * example: IEEE_8021X_PHASE2_SUBJECT_MATCH="Red Hat" + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_SUBJECT_MATCH, + g_param_spec_string (NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-altsubject-matches: + * + * List of strings to be matched against the altSubjectName of the + * certificate presented by the authentication server during the inner + * "phase 2" authentication. If the list is empty, no verification of the + * server certificate's altSubjectName is performed. + **/ + /* ---ifcfg-rh--- + * property: phase2-altsubject-matches + * variable: IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES(+) + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_ALTSUBJECT_MATCHES, + g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES, "", "", + G_TYPE_STRV, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-client-cert: + * + * Contains the "phase 2" client certificate if used by the EAP method + * specified in the #NMSetting8021x:phase2-auth or + * #NMSetting8021x:phase2-autheap properties. + * + * Certificate data is specified using a "scheme"; two are currently + * supported: blob and path. When using the blob scheme (which is backwards + * compatible with NM 0.7.x) this property should be set to the + * certificate's DER encoded data. When using the path scheme, this property + * should be set to the full UTF-8 encoded path of the certificate, prefixed + * with the string "file://" and ending with a terminating NUL byte. This + * property can be unset even if the EAP method supports CA certificates, + * but this allows man-in-the-middle attacks and is NOT recommended. + * + * Setting this property directly is discouraged; use the + * nm_setting_802_1x_set_phase2_client_cert() function instead. + **/ + /* ---ifcfg-rh--- + * property: phase2-client-cert + * variable: IEEE_8021X_INNER_CLIENT_CERT(+) + * description: Client certificate for inner EAP method. + * example: IEEE_8021X_INNER_CLIENT_CERT=/home/joe/mycert.crt + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_CLIENT_CERT, + g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_CLIENT_CERT, "", "", + G_TYPE_BYTES, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:password: + * + * UTF-8 encoded password used for EAP authentication methods. If both the + * #NMSetting8021x:password property and the #NMSetting8021x:password-raw + * property are specified, #NMSetting8021x:password is preferred. + **/ + /* ---ifcfg-rh--- + * property: password + * variable: IEEE_8021X_PASSWORD(+) + * description: UTF-8 encoded password used for EAP. It can also go to "key-" + * lookaside file, or it can be owned by a secret agent. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PASSWORD, + g_param_spec_string (NM_SETTING_802_1X_PASSWORD, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_SECRET | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:password-flags: + * + * Flags indicating how to handle the #NMSetting8021x:password property. + **/ + /* ---ifcfg-rh--- + * property: password-flags + * variable: IEEE_8021X_PASSWORD_FLAGS(+) + * format: NMSettingSecretFlags + * description: Password flags for IEEE_8021X_PASSWORD password. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PASSWORD_FLAGS, + g_param_spec_flags (NM_SETTING_802_1X_PASSWORD_FLAGS, "", "", + NM_TYPE_SETTING_SECRET_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:password-raw: + * + * Password used for EAP authentication methods, given as a byte array to + * allow passwords in other encodings than UTF-8 to be used. If both the + * #NMSetting8021x:password property and the #NMSetting8021x:password-raw + * property are specified, #NMSetting8021x:password is preferred. + **/ + /* ---ifcfg-rh--- + * property: password-raw + * variable: (none) + * description: The property is not handled by ifcfg-rh plugin. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PASSWORD_RAW, + g_param_spec_boxed (NM_SETTING_802_1X_PASSWORD_RAW, "", "", + G_TYPE_BYTES, + G_PARAM_READWRITE | + NM_SETTING_PARAM_SECRET | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:password-raw-flags: + * + * Flags indicating how to handle the #NMSetting8021x:password-raw property. + **/ + /* ---ifcfg-rh--- + * property: password-raw-flags + * variable: (none) + * description: The property is not handled by ifcfg-rh plugin. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PASSWORD_RAW_FLAGS, + g_param_spec_flags (NM_SETTING_802_1X_PASSWORD_RAW_FLAGS, "", "", + NM_TYPE_SETTING_SECRET_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:private-key: + * + * Contains the private key when the #NMSetting8021x:eap property is set to + * "tls". + * + * Key data is specified using a "scheme"; two are currently supported: blob + * and path. When using the blob scheme and private keys, this property + * should be set to the key's encrypted PEM encoded data. When using private + * keys with the path scheme, this property should be set to the full UTF-8 + * encoded path of the key, prefixed with the string "file://" and ending + * with a terminating NUL byte. When using PKCS#<!-- -->12 format private + * keys and the blob scheme, this property should be set to the + * PKCS#<!-- -->12 data and the #NMSetting8021x:private-key-password + * property must be set to password used to decrypt the PKCS#<!-- -->12 + * certificate and key. When using PKCS#<!-- -->12 files and the path + * scheme, this property should be set to the full UTF-8 encoded path of the + * key, prefixed with the string "file://" and and ending with a terminating + * NUL byte, and as with the blob scheme the "private-key-password" property + * must be set to the password used to decode the PKCS#<!-- -->12 private + * key and certificate. + * + * Setting this property directly is discouraged; use the + * nm_setting_802_1x_set_private_key() function instead. + * + * WARNING: #NMSetting8021x:private-key is not a "secret" property, and thus + * unencrypted private key data using the BLOB scheme may be readable by + * unprivileged users. Private keys should always be encrypted with a + * private key password to prevent unauthorized access to unencrypted + * private key data. + **/ + /* ---ifcfg-rh--- + * property: private-key + * variable: IEEE_8021X_PRIVATE_KEY(+) + * description: Private key for EAP-TLS. + * example: IEEE_8021X_PRIVATE_KEY=/home/joe/mykey.p12 + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PRIVATE_KEY, + g_param_spec_boxed (NM_SETTING_802_1X_PRIVATE_KEY, "", "", + G_TYPE_BYTES, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:private-key-password: + * + * The password used to decrypt the private key specified in the + * #NMSetting8021x:private-key property when the private key either uses the + * path scheme, or if the private key is a PKCS#<!-- -->12 format key. Setting this + * property directly is not generally necessary except when returning + * secrets to NetworkManager; it is generally set automatically when setting + * the private key by the nm_setting_802_1x_set_private_key() function. + **/ + /* ---ifcfg-rh--- + * property: private-key-password + * variable: IEEE_8021X_PRIVATE_KEY_PASSWORD(+) + * description: Password for IEEE_8021X_PRIVATE_KEY. It can also go to "key-" + * lookaside file, or it can be owned by a secret agent. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PRIVATE_KEY_PASSWORD, + g_param_spec_string (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_SECRET | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:private-key-password-flags: + * + * Flags indicating how to handle the #NMSetting8021x:private-key-password + * property. + **/ + /* ---ifcfg-rh--- + * property: private-key-password-flags + * variable: IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS(+) + * format: NMSettingSecretFlags + * description: Password flags for IEEE_8021X_PRIVATE_KEY_PASSWORD password. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PRIVATE_KEY_PASSWORD_FLAGS, + g_param_spec_flags (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS, "", "", + NM_TYPE_SETTING_SECRET_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-private-key: + * + * Contains the "phase 2" inner private key when the + * #NMSetting8021x:phase2-auth or #NMSetting8021x:phase2-autheap property is + * set to "tls". + * + * Key data is specified using a "scheme"; two are currently supported: blob + * and path. When using the blob scheme and private keys, this property + * should be set to the key's encrypted PEM encoded data. When using private + * keys with the path scheme, this property should be set to the full UTF-8 + * encoded path of the key, prefixed with the string "file://" and ending + * with a terminating NUL byte. When using PKCS#<!-- -->12 format private + * keys and the blob scheme, this property should be set to the + * PKCS#<!-- -->12 data and the #NMSetting8021x:phase2-private-key-password + * property must be set to password used to decrypt the PKCS#<!-- -->12 + * certificate and key. When using PKCS#<!-- -->12 files and the path + * scheme, this property should be set to the full UTF-8 encoded path of the + * key, prefixed with the string "file://" and and ending with a terminating + * NUL byte, and as with the blob scheme the + * #NMSetting8021x:phase2-private-key-password property must be set to the + * password used to decode the PKCS#<!-- -->12 private key and certificate. + * + * Setting this property directly is discouraged; use the + * nm_setting_802_1x_set_phase2_private_key() function instead. + **/ + /* ---ifcfg-rh--- + * property: phase2-private-key + * variable: IEEE_8021X_INNER_PRIVATE_KEY(+) + * description: Private key for inner authentication method for EAP-TLS. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_PRIVATE_KEY, + g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, "", "", + G_TYPE_BYTES, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-private-key-password: + * + * The password used to decrypt the "phase 2" private key specified in the + * #NMSetting8021x:phase2-private-key property when the private key either + * uses the path scheme, or is a PKCS#<!-- -->12 format key. Setting this + * property directly is not generally necessary except when returning + * secrets to NetworkManager; it is generally set automatically when setting + * the private key by the nm_setting_802_1x_set_phase2_private_key() + * function. + **/ + /* ---ifcfg-rh--- + * property: phase2-private-key-password + * variable: IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD(+) + * description: Password for IEEE_8021X_INNER_PRIVATE_KEY. It can also go to "key-" + * lookaside file, or it can be owned by a secret agent. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_PRIVATE_KEY_PASSWORD, + g_param_spec_string (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_SECRET | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-private-key-password-flags: + * + * Flags indicating how to handle the + * #NMSetting8021x:phase2-private-key-password property. + **/ + /* ---ifcfg-rh--- + * property: phase2-private-key-password-flags + * variable: IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS(+) + * format: NMSettingSecretFlags + * description: Password flags for IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD password. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, + g_param_spec_flags (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, "", "", + NM_TYPE_SETTING_SECRET_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:pin: + * + * PIN used for EAP authentication methods. + **/ + /* ---ifcfg-rh--- + * property: pin + * variable: (none) + * description: The property is not handled by ifcfg-rh plugin. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PIN, + g_param_spec_string (NM_SETTING_802_1X_PIN, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_SECRET | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:pin-flags: + * + * Flags indicating how to handle the #NMSetting8021x:pin property. + **/ + /* ---ifcfg-rh--- + * property: pin-flags + * variable: (none) + * description: The property is not handled by ifcfg-rh plugin. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PIN_FLAGS, + g_param_spec_flags (NM_SETTING_802_1X_PIN_FLAGS, "", "", + NM_TYPE_SETTING_SECRET_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:system-ca-certs: + * + * When %TRUE, overrides the #NMSetting8021x:ca-path and + * #NMSetting8021x:phase2-ca-path properties using the system CA directory + * specified at configure time with the --system-ca-path switch. The + * certificates in this directory are added to the verification chain in + * addition to any certificates specified by the #NMSetting8021x:ca-cert and + * #NMSetting8021x:phase2-ca-cert properties. + **/ + /* ---ifcfg-rh--- + * property: system-ca-certs + * variable: (none) + * description: The property is not handled by ifcfg-rh plugin. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_SYSTEM_CA_CERTS, + g_param_spec_boolean (NM_SETTING_802_1X_SYSTEM_CA_CERTS, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); +} |