mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-07 04:00:32 +01:00
ifcfg-rh: use single quotes when quoting WPA passphrases (WPA_PSK) (rh #798102)
Single quotes ensure we don't break initscripts (bash processing) when the string contains special characters. Special handling is necessary for single quotes characters. They have to be escaped and the whole string has to be prepended with '$' character so that bash is happy. This change also filters out CR and LF characters as they break WPA_PSK variable and could pose security issues.
This commit is contained in:
parent
49214066a4
commit
79757f10f3
7 changed files with 235 additions and 19 deletions
|
|
@ -1957,6 +1957,7 @@ parse_wpa_psk (shvarFile *ifcfg,
|
|||
{
|
||||
shvarFile *keys_ifcfg;
|
||||
char *psk = NULL, *p, *hashed = NULL;
|
||||
size_t plen;
|
||||
gboolean quoted = FALSE;
|
||||
|
||||
/* Passphrase must be between 10 and 66 characters in length because WPA
|
||||
|
|
@ -1980,8 +1981,10 @@ parse_wpa_psk (shvarFile *ifcfg,
|
|||
return NULL;
|
||||
|
||||
p = psk;
|
||||
plen = strlen (p);
|
||||
|
||||
if (p[0] == '"' && psk[strlen (psk) - 1] == '"')
|
||||
if ( (plen >= 2 && (p[0] == '"' || p[0] == '\'') && p[0] == p[plen - 1])
|
||||
|| (plen >= 3 && p[0] == '$' && p[1] == '\'' && p[1] == p[plen - 1]))
|
||||
quoted = TRUE;
|
||||
|
||||
if (!quoted && (strlen (psk) == 64)) {
|
||||
|
|
@ -2001,21 +2004,18 @@ parse_wpa_psk (shvarFile *ifcfg,
|
|||
* and between 8 and 63 characters as a passphrase.
|
||||
*/
|
||||
|
||||
if (quoted) {
|
||||
/* Get rid of the quotes */
|
||||
p++;
|
||||
p[strlen (p) - 1] = '\0';
|
||||
}
|
||||
/* Get rid of the quotes */
|
||||
hashed = utils_single_unquote_string (p);
|
||||
|
||||
/* Length check */
|
||||
if (strlen (p) < 8 || strlen (p) > 63) {
|
||||
if (strlen (hashed) < 8 || strlen (hashed) > 63) {
|
||||
g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
|
||||
"Invalid WPA_PSK (passphrases must be between "
|
||||
"8 and 63 characters long (inclusive))");
|
||||
g_free (hashed);
|
||||
hashed = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hashed = g_strdup (p);
|
||||
}
|
||||
|
||||
if (!hashed) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
TYPE=Wireless
|
||||
DEVICE=eth2
|
||||
HWADDR=00:16:41:11:22:33
|
||||
NM_CONTROLLED=yes
|
||||
BOOTPROTO=dhcp
|
||||
ESSID=ipsum
|
||||
CHANNEL=6
|
||||
MODE=Managed
|
||||
RATE=auto
|
||||
ONBOOT=yes
|
||||
USERCTL=yes
|
||||
PEERDNS=yes
|
||||
IPV6INIT=no
|
||||
CIPHER_PAIRWISE="TKIP CCMP"
|
||||
CIPHER_GROUP="TKIP CCMP WEP40 WEP104"
|
||||
KEY_MGMT=WPA-PSK
|
||||
WPA_ALLOW_WPA=yes
|
||||
WPA_ALLOW_WPA2=yes
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
WPA_PSK=$'They\'re really saying I love you. >>`<<'
|
||||
|
||||
|
|
@ -4910,6 +4910,111 @@ test_read_wifi_wpa_psk (void)
|
|||
g_object_unref (connection);
|
||||
}
|
||||
|
||||
#define TEST_IFCFG_WIFI_WPA_PSK_2 TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-wpa-psk-2"
|
||||
|
||||
static void
|
||||
test_read_wifi_wpa_psk_2 (void)
|
||||
{
|
||||
NMConnection *connection;
|
||||
NMSettingConnection *s_con;
|
||||
NMSettingWireless *s_wireless;
|
||||
NMSettingWirelessSecurity *s_wsec;
|
||||
char *unmanaged = NULL;
|
||||
char *keyfile = NULL;
|
||||
char *routefile = NULL;
|
||||
char *route6file = NULL;
|
||||
gboolean ignore_error = FALSE;
|
||||
GError *error = NULL;
|
||||
const char *tmp;
|
||||
const char *expected_id = "System ipsum (test-wifi-wpa-psk-2)";
|
||||
const char *expected_psk = "They're really saying I love you. >>`<<";
|
||||
|
||||
connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NULL,
|
||||
TYPE_WIRELESS,
|
||||
NULL,
|
||||
&unmanaged,
|
||||
&keyfile,
|
||||
&routefile,
|
||||
&route6file,
|
||||
&error,
|
||||
&ignore_error);
|
||||
ASSERT (connection != NULL,
|
||||
"wifi-wpa-psk-2-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WPA_PSK_2, error->message);
|
||||
|
||||
ASSERT (nm_connection_verify (connection, &error),
|
||||
"wifi-wpa-psk-2-verify", "failed to verify %s: %s", TEST_IFCFG_WIFI_WPA_PSK_2, error->message);
|
||||
|
||||
/* ===== CONNECTION SETTING ===== */
|
||||
|
||||
s_con = nm_connection_get_setting_connection (connection);
|
||||
ASSERT (s_con != NULL,
|
||||
"wifi-wpa-psk-2-verify-connection", "failed to verify %s: missing %s setting",
|
||||
TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NM_SETTING_CONNECTION_SETTING_NAME);
|
||||
|
||||
/* ID */
|
||||
tmp = nm_setting_connection_get_id (s_con);
|
||||
ASSERT (tmp != NULL,
|
||||
"wifi-wpa-psk-2-verify-connection", "failed to verify %s: missing %s / %s key",
|
||||
TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NM_SETTING_CONNECTION_SETTING_NAME,
|
||||
NM_SETTING_CONNECTION_ID);
|
||||
ASSERT (strcmp (tmp, expected_id) == 0,
|
||||
"wifi-wpa-psk-2-verify-connection", "failed to verify %s: unexpected %s / %s key value",
|
||||
TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NM_SETTING_CONNECTION_SETTING_NAME,
|
||||
NM_SETTING_CONNECTION_ID);
|
||||
|
||||
/* ===== WIRELESS SETTING ===== */
|
||||
|
||||
s_wireless = nm_connection_get_setting_wireless (connection);
|
||||
ASSERT (s_wireless != NULL,
|
||||
"wifi-wpa-psk-2-verify-wireless", "failed to verify %s: missing %s setting",
|
||||
TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NM_SETTING_WIRELESS_SETTING_NAME);
|
||||
|
||||
/* Security */
|
||||
tmp = nm_setting_wireless_get_security (s_wireless);
|
||||
ASSERT (tmp != NULL,
|
||||
"wifi-wpa-psk-2-verify-wireless", "failed to verify %s: missing %s / %s key",
|
||||
TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NM_SETTING_WIRELESS_SETTING_NAME,
|
||||
NM_SETTING_WIRELESS_SEC);
|
||||
ASSERT (strcmp (tmp, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) == 0,
|
||||
"wifi-wpa-psk-2-verify-wireless", "failed to verify %s: unexpected %s / %s key value",
|
||||
TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NM_SETTING_WIRELESS_SETTING_NAME,
|
||||
NM_SETTING_WIRELESS_SEC);
|
||||
|
||||
/* ===== WIRELESS SECURITY SETTING ===== */
|
||||
|
||||
s_wsec = nm_connection_get_setting_wireless_security (connection);
|
||||
ASSERT (s_wsec != NULL,
|
||||
"wifi-wpa-psk-2-verify-wireless", "failed to verify %s: missing %s setting",
|
||||
TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
|
||||
|
||||
/* PSK */
|
||||
tmp = nm_setting_wireless_security_get_psk (s_wsec);
|
||||
ASSERT (tmp != NULL,
|
||||
"wifi-wpa-psk-2-verify-wireless", "failed to verify %s: missing %s / %s key",
|
||||
TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
|
||||
NM_SETTING_WIRELESS_SECURITY_PSK);
|
||||
ASSERT (strcmp (tmp, expected_psk) == 0,
|
||||
"wifi-wpa-psk-2-verify-wireless", "failed to verify %s: unexpected %s / %s key value",
|
||||
TEST_IFCFG_WIFI_WPA_PSK_2,
|
||||
NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
|
||||
NM_SETTING_WIRELESS_SECURITY_PSK);
|
||||
|
||||
g_free (unmanaged);
|
||||
g_free (keyfile);
|
||||
g_free (routefile);
|
||||
g_free (route6file);
|
||||
g_object_unref (connection);
|
||||
}
|
||||
|
||||
#define TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-wpa-psk-unquoted"
|
||||
|
||||
static void
|
||||
|
|
@ -12678,6 +12783,7 @@ int main (int argc, char **argv)
|
|||
test_read_wifi_leap_secret_flags (TEST_IFCFG_WIFI_LEAP_ALWAYS,
|
||||
NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED);
|
||||
test_read_wifi_wpa_psk ();
|
||||
test_read_wifi_wpa_psk_2 ();
|
||||
test_read_wifi_wpa_psk_unquoted ();
|
||||
test_read_wifi_wpa_psk_unquoted2 ();
|
||||
test_read_wifi_wpa_psk_adhoc ();
|
||||
|
|
@ -12747,6 +12853,12 @@ int main (int argc, char **argv)
|
|||
TRUE,
|
||||
TRUE,
|
||||
"really insecure passphrase04!");
|
||||
test_write_wifi_wpa_psk ("Test Write Wifi WPA WPA2 PSK Passphrase Special Chars",
|
||||
"wifi-wpa-wpa2-psk-passphrase-write-spec-chars",
|
||||
FALSE,
|
||||
TRUE,
|
||||
TRUE,
|
||||
"blah`oops\"grr'$*@~!%");
|
||||
test_write_wifi_wpa_psk_adhoc ();
|
||||
test_write_wifi_wpa_eap_tls ();
|
||||
test_write_wifi_wpa_eap_ttls_tls ();
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* (C) Copyright 2008 - 2010 Red Hat, Inc.
|
||||
* (C) Copyright 2008 - 2012 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
|
@ -115,6 +115,89 @@ utils_hexstr2bin (const char *hex, size_t len)
|
|||
|
||||
/* End from hostap */
|
||||
|
||||
/*
|
||||
* utils_single_quote_string
|
||||
*
|
||||
* Put string inside single quotes and remove CR, LF characters. If single quote
|
||||
* is present, escape it with a backslash and prepend the whole string with $
|
||||
* in order to have $'string'. That allows us to use single quote inside
|
||||
* single quotes without breaking bash syntax. (man bash, section QUOTING).
|
||||
*
|
||||
* Caller is responsible for freeing the returned string.
|
||||
*/
|
||||
char *
|
||||
utils_single_quote_string (const char *str)
|
||||
{
|
||||
static const char const drop_chars[] = "\r\n"; /* drop CR and LF */
|
||||
static const char escape_char = '\\'; /* escape char is backslash */
|
||||
static const char quote_char = '\''; /* quote char is single quote */
|
||||
size_t i, slen, j = 0;
|
||||
size_t drop = 0, extra = 0;
|
||||
char *new_str;
|
||||
|
||||
slen = strlen (str);
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (str[i] == quote_char)
|
||||
extra++;
|
||||
if (strchr (drop_chars, str[i]))
|
||||
drop++;
|
||||
}
|
||||
new_str = g_malloc0 (slen + extra - drop + 4); /* 4 is for $''\0*/
|
||||
if (!new_str) return NULL;
|
||||
|
||||
if (extra > 0)
|
||||
new_str[j++] = '$';
|
||||
new_str[j++] = quote_char;
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (strchr (drop_chars, str[i]))
|
||||
continue;
|
||||
if (str[i] == quote_char)
|
||||
new_str[j++] = escape_char;
|
||||
new_str[j++] = str[i];
|
||||
}
|
||||
new_str[j] = quote_char;
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
/*
|
||||
* utils_single_unquote_string
|
||||
*
|
||||
* Remove string from single (or double) quotes, and remove escaping of '.
|
||||
* Also remove first $ if the string is in the form of $'string'.
|
||||
*
|
||||
* Caller is responsible for freeing the returned string.
|
||||
*/
|
||||
char *
|
||||
utils_single_unquote_string (const char *str)
|
||||
{
|
||||
static const char escape_char = '\\'; /* escape char is backslash */
|
||||
static const char q_char = '\''; /* quote char is single quote */
|
||||
static const char dq_char = '"'; /* double quote char */
|
||||
size_t i, slen, j = 0, quote = 0, dollar = 0;
|
||||
char *new_str;
|
||||
|
||||
slen = strlen (str);
|
||||
new_str = g_malloc0 (slen + 1);
|
||||
if (!new_str) return NULL;
|
||||
|
||||
if ( (slen >= 2 && (str[0] == dq_char || str[0] == q_char) && str[0] == str[slen-1])
|
||||
|| (slen >= 3 && str[0] == '$' && str[1] == q_char && str[1] == str[slen-1])) {
|
||||
quote = 1;
|
||||
if (str[0] == '$') dollar = 1;
|
||||
}
|
||||
|
||||
i = quote + dollar;
|
||||
while (i < slen - quote) {
|
||||
if (str[i] == escape_char && str[i+1] == q_char)
|
||||
i++;
|
||||
new_str[j++] = str[i++];
|
||||
}
|
||||
new_str[j] = '\0';
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check ';[a-fA-F0-9]{8}' file suffix used for temporary files by rpm when
|
||||
* installing packages.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* (C) Copyright 2008 - 2009 Red Hat, Inc.
|
||||
* (C) Copyright 2008 - 2012 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_H_
|
||||
|
|
@ -30,6 +30,10 @@ char *utils_bin2hexstr (const char *bytes, int len, int final_len);
|
|||
|
||||
char *utils_hexstr2bin (const char *hex, size_t len);
|
||||
|
||||
char *utils_single_quote_string (const char *str);
|
||||
|
||||
char *utils_single_unquote_string (const char *str);
|
||||
|
||||
char *utils_cert_path (const char *parent, const char *suffix);
|
||||
|
||||
const char *utils_get_ifcfg_name (const char *file, gboolean only_ifcfg);
|
||||
|
|
|
|||
|
|
@ -736,24 +736,20 @@ write_wireless_security_setting (NMConnection *connection,
|
|||
|
||||
/* WPA Passphrase */
|
||||
if (wpa) {
|
||||
GString *quoted = NULL;
|
||||
char *quoted = NULL;
|
||||
|
||||
psk = nm_setting_wireless_security_get_psk (s_wsec);
|
||||
if (psk && (strlen (psk) != 64)) {
|
||||
/* Quote the PSK since it's a passphrase */
|
||||
quoted = g_string_sized_new (strlen (psk) + 2); /* 2 for quotes */
|
||||
g_string_append_c (quoted, '"');
|
||||
g_string_append (quoted, psk);
|
||||
g_string_append_c (quoted, '"');
|
||||
quoted = utils_single_quote_string (psk);
|
||||
}
|
||||
set_secret (ifcfg,
|
||||
"WPA_PSK",
|
||||
quoted ? quoted->str : psk,
|
||||
quoted ? quoted : psk,
|
||||
"WPA_PSK_FLAGS",
|
||||
nm_setting_wireless_security_get_psk_flags (s_wsec),
|
||||
TRUE);
|
||||
if (quoted)
|
||||
g_string_free (quoted, TRUE);
|
||||
g_free (quoted);
|
||||
} else {
|
||||
set_secret (ifcfg,
|
||||
"WPA_PSK",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue