summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-05-24 22:43:30 +0200
committerThomas Haller <thaller@redhat.com>2016-05-24 22:43:30 +0200
commit9cf1dbcaefd6128cf8c77cb4960cd57f972c6da0 (patch)
tree43c8698b6054eb1bba2c4b517a4b4109f516337d
parent4c7fbcc941d5aba8b1d7858080fe7818c064104c (diff)
parentacbdc30f90ab0cb68f227ca377b6543ef05e21f7 (diff)
downloadNetworkManager-9cf1dbcaefd6128cf8c77cb4960cd57f972c6da0.tar.gz
logging,vpn: merge branch 'th/vpn-plugin-debug-bgo766816'
https://bugzilla.gnome.org/show_bug.cgi?id=766816
-rw-r--r--man/NetworkManager.conf.xml9
-rw-r--r--src/nm-logging.c44
-rw-r--r--src/nm-logging.h9
-rw-r--r--src/vpn-manager/nm-vpn-connection.c75
4 files changed, 129 insertions, 8 deletions
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index 036f41d003..fd6d7cef59 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -460,7 +460,7 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
WIFI_SCAN, IP4, IP6, AUTOIP4, DNS, VPN, SHARING, SUPPLICANT,
AGENTS, SETTINGS, SUSPEND, CORE, DEVICE, OLPC, WIMAX,
INFINIBAND, FIREWALL, ADSL, BOND, VLAN, BRIDGE, DBUS_PROPS,
- TEAM, CONCHECK, DCB, DISPATCH, AUDIT, SYSTEMD.</para>
+ TEAM, CONCHECK, DCB, DISPATCH, AUDIT, SYSTEMD, VPN_PLUGIN.</para>
<para>In addition, these special domains can be used: NONE,
ALL, DEFAULT, DHCP, IP.</para>
<para>You can specify per-domain log level overrides by
@@ -507,6 +507,7 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
<member>DISPATCH : Dispatcher scripts</member>
<member>AUDIT : Audit records</member>
<member>SYSTEMD : Messages from internal libsystemd</member>
+ <member>VPN_PLUGIN : logging messages from VPN plugins</member>
<member> </member>
<member>NONE : when given by itself logging is disabled</member>
<member>ALL : all log domains</member>
@@ -517,6 +518,12 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
<member>HW : deprecated alias for "PLATFORM"</member>
</simplelist>
</para>
+ <para>
+ In general, the logfile should not contain passwords or private data. However,
+ you are always advised to check the file before posting it online or attaching
+ to a bug report. <literal>VPN_PLUGIN</literal> is special in that it might
+ reveal private information from the VPN plugins and thus this level is excluded
+ from <literal>ALL</literal></para>
</varlistentry>
<varlistentry>
<term><varname>backend</varname></term>
diff --git a/src/nm-logging.c b/src/nm-logging.c
index a2581add24..4d9b3fbd45 100644
--- a/src/nm-logging.c
+++ b/src/nm-logging.c
@@ -93,7 +93,16 @@ typedef struct {
typedef struct {
const char *name;
const char *level_str;
+
+ /* nm-logging uses syslog internally. Note that the three most-verbose syslog levels
+ * are LOG_DEBUG, LOG_INFO and LOG_NOTICE. Journal already highlights LOG_NOTICE
+ * as special.
+ *
+ * On the other hand, we have three levels LOGL_TRACE, LOGL_DEBUG and LOGL_INFO,
+ * which are regular messages not to be highlighted. For that reason, we must map
+ * LOGL_TRACE and LOGL_DEBUG both to syslog level LOG_DEBUG. */
int syslog_level;
+
GLogLevelFlags g_log_level;
LogFormatFlags log_format_level;
} LogLevelDesc;
@@ -108,6 +117,7 @@ NMLogDomain _nm_logging_enabled_state[_LOGL_N_REAL] = {
static struct {
NMLogLevel log_level;
LogFormatFlags log_format_flags;
+ bool uses_syslog:1;
enum {
LOG_BACKEND_GLIB,
LOG_BACKEND_SYSLOG,
@@ -116,7 +126,7 @@ static struct {
char *logging_domains_to_string;
const LogLevelDesc level_desc[_LOGL_N];
-#define _DOMAIN_DESC_LEN 37
+#define _DOMAIN_DESC_LEN 38
/* Would be nice to use C99 flexible array member here,
* but that feature doesn't seem well supported. */
const LogDesc domain_desc[_DOMAIN_DESC_LEN];
@@ -127,7 +137,7 @@ static struct {
.log_format_flags = _LOG_FORMAT_FLAG_DEFAULT,
.level_desc = {
[LOGL_TRACE] = { "TRACE", "<trace>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, _LOG_FORMAT_FLAG_LEVEL_DEBUG },
- [LOGL_DEBUG] = { "DEBUG", "<debug>", LOG_INFO, G_LOG_LEVEL_DEBUG, _LOG_FORMAT_FLAG_LEVEL_DEBUG },
+ [LOGL_DEBUG] = { "DEBUG", "<debug>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, _LOG_FORMAT_FLAG_LEVEL_DEBUG },
[LOGL_INFO] = { "INFO", "<info>", LOG_INFO, G_LOG_LEVEL_INFO, _LOG_FORMAT_FLAG_LEVEL_INFO },
[LOGL_WARN] = { "WARN", "<warn>", LOG_WARNING, G_LOG_LEVEL_MESSAGE, _LOG_FORMAT_FLAG_LEVEL_INFO },
[LOGL_ERR] = { "ERR", "<error>", LOG_ERR, G_LOG_LEVEL_MESSAGE, _LOG_FORMAT_FLAG_LEVEL_ERROR },
@@ -171,6 +181,7 @@ static struct {
{ LOGD_DISPATCH, "DISPATCH" },
{ LOGD_AUDIT, "AUDIT" },
{ LOGD_SYSTEMD, "SYSTEMD" },
+ { LOGD_VPN_PLUGIN,"VPN_PLUGIN" },
{ 0, NULL }
/* keep _DOMAIN_DESC_LEN in sync */
},
@@ -445,6 +456,27 @@ nm_logging_all_domains_to_string (void)
return str->str;
}
+/**
+ * nm_logging_get_level:
+ * @domain: find the lowest enabled logging level for the
+ * given domain. If this is a set of multiple
+ * domains, the most verbose level will be returned.
+ *
+ * Returns: the lowest (most verbose) logging level for the
+ * give @domain, or %_LOGL_OFF if it is disabled.
+ **/
+NMLogLevel
+nm_logging_get_level (NMLogDomain domain)
+{
+ NMLogLevel sl = _LOGL_OFF;
+
+ G_STATIC_ASSERT (LOGL_TRACE == 0);
+ while ( sl > LOGL_TRACE
+ && nm_logging_enabled (sl - 1, domain))
+ sl--;
+ return sl;
+}
+
#if SYSTEMD_JOURNAL
__attribute__((__format__ (__printf__, 4, 5)))
static void
@@ -716,6 +748,12 @@ nm_log_handler (const gchar *log_domain,
}
}
+gboolean
+nm_logging_syslog_enabled (void)
+{
+ return global.uses_syslog;
+}
+
void
nm_logging_syslog_openlog (const char *logging_backend)
{
@@ -735,6 +773,7 @@ nm_logging_syslog_openlog (const char *logging_backend)
#if SYSTEMD_JOURNAL
} else if (strcmp (logging_backend, "syslog") != 0) {
global.log_backend = LOG_BACKEND_JOURNAL;
+ global.uses_syslog = TRUE;
/* ensure we read a monotonic timestamp. Reading the timestamp the first
* time causes a logging message. We don't want to do that during _nm_log_impl. */
@@ -742,6 +781,7 @@ nm_logging_syslog_openlog (const char *logging_backend)
#endif
} else {
global.log_backend = LOG_BACKEND_SYSLOG;
+ global.uses_syslog = TRUE;
openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON);
}
diff --git a/src/nm-logging.h b/src/nm-logging.h
index 1cb5a5a5d9..f49f6ec67b 100644
--- a/src/nm-logging.h
+++ b/src/nm-logging.h
@@ -65,12 +65,16 @@ typedef enum { /*< skip >*/
LOGD_DISPATCH = (1LL << 33),
LOGD_AUDIT = (1LL << 34),
LOGD_SYSTEMD = (1LL << 35),
+ LOGD_VPN_PLUGIN = (1LL << 36),
__LOGD_MAX,
- LOGD_ALL = ((__LOGD_MAX - 1LL) << 1) - 1LL,
+ LOGD_ALL = (((__LOGD_MAX - 1LL) << 1) - 1LL) & ~(
+ LOGD_VPN_PLUGIN | /*not even part of ALL, because it might expose sensitive information. */
+ 0),
LOGD_DEFAULT = LOGD_ALL & ~(
LOGD_DBUS_PROPS |
LOGD_WIFI_SCAN |
+ LOGD_VPN_PLUGIN |
0),
/* aliases: */
@@ -168,6 +172,8 @@ nm_logging_enabled (NMLogLevel level, NMLogDomain domain)
&& !!(_nm_logging_enabled_state[level] & domain);
}
+NMLogLevel nm_logging_get_level (NMLogDomain domain);
+
const char *nm_logging_all_levels_to_string (void);
const char *nm_logging_all_domains_to_string (void);
@@ -176,6 +182,7 @@ gboolean nm_logging_setup (const char *level,
char **bad_domains,
GError **error);
void nm_logging_syslog_openlog (const char *logging_backend);
+gboolean nm_logging_syslog_enabled (void);
/*****************************************************************************/
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index c235748741..410256027f 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -27,6 +27,8 @@
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
#include "nm-vpn-connection.h"
#include "nm-ip4-config.h"
@@ -1922,6 +1924,41 @@ _daemon_exec_timeout (gpointer data)
return G_SOURCE_REMOVE;
}
+static int
+_get_log_level (void)
+{
+ NMLogLevel level;
+
+ /* curiously enough, nm-logging also uses syslog. But it
+ * maps NMLogLevel differently to the syslog levels then we
+ * do here.
+ *
+ * The reason is, that LOG_NOTICE is already something worth
+ * highlighting in the journal, but we have 3 levels that are
+ * lower then LOG_NOTICE (LOGL_TRACE, LOGL_DEBUG, LOGL_INFO),
+ * On the other hand, syslog only defines LOG_DEBUG and LOG_INFO.
+ * Thus, we must map them differently.
+ *
+ * Inside the VPN plugin, you might want to treat LOG_NOTICE as
+ * as low severity, not worthy to be highlighted (like NM does). */
+
+ level = nm_logging_get_level (LOGD_VPN_PLUGIN);
+ if (level != _LOGL_OFF) {
+ if (level <= LOGL_TRACE)
+ return LOG_DEBUG;
+ if (level <= LOGL_DEBUG)
+ return LOG_INFO;
+ if (level <= LOGL_INFO)
+ return LOG_NOTICE;
+ if (level <= LOGL_WARN)
+ return LOG_WARNING;
+ if (level <= LOGL_ERR)
+ return LOG_ERR;
+ }
+
+ return LOG_EMERG;
+}
+
static gboolean
nm_vpn_service_daemon_exec (NMVpnConnection *self, GError **error)
{
@@ -1930,20 +1967,50 @@ nm_vpn_service_daemon_exec (NMVpnConnection *self, GError **error)
char *vpn_argv[4];
gboolean success = FALSE;
GError *spawn_error = NULL;
- int i = 0;
+ guint i, j, n_environ;
+ gs_free char **envp = NULL;
+ char env_log_level[NM_STRLEN ("NM_VPN_LOG_LEVEL=") + 100];
+ char env_log_syslog[NM_STRLEN ("NM_VPN_LOG_SYSLOG=") + 10];
+ const int N_ENVIRON_EXTRA = 3;
+ char **p_environ;
g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), FALSE);
+
priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
+ i = 0;
vpn_argv[i++] = (char *) nm_vpn_plugin_info_get_program (priv->plugin_info);
+ g_return_val_if_fail (vpn_argv[0], FALSE);
if (nm_vpn_plugin_info_supports_multiple (priv->plugin_info)) {
vpn_argv[i++] = "--bus-name";
vpn_argv[i++] = priv->bus_name;
}
- vpn_argv[i] = NULL;
- g_assert (vpn_argv[0]);
+ vpn_argv[i++] = NULL;
+
+ /* we include <unistd.h> and "config.h" defines _GNU_SOURCE for us. So, we have @environ. */
+ p_environ = environ;
+ n_environ = p_environ ? g_strv_length (p_environ) : 0;
+ envp = g_new (char *, n_environ + N_ENVIRON_EXTRA);
+ for (i = 0, j = 0; j < n_environ; j++) {
+ if ( g_str_has_prefix (p_environ[j], "NM_VPN_LOG_LEVEL=")
+ || g_str_has_prefix (p_environ[j], "NM_VPN_LOG_SYSLOG="))
+ continue;
+ envp[i++] = p_environ[j];
+ }
+
+ /* NM_VPN_LOG_LEVEL: the syslog logging level for the plugin. */
+ envp[i++] = nm_sprintf_buf (env_log_level, "NM_VPN_LOG_LEVEL=%d", _get_log_level ());
+
+ /* NM_VPN_LOG_SYSLOG: whether to log to stdout or syslog. If NetworkManager itself runs in
+ * foreground, we also want the plugin to log to stdout.
+ * If the plugin runs in background, the plugin should prefer logging to syslog. Otherwise
+ * logging messages will be lost (unless using journald, in which case it wouldn't matter). */
+ envp[i++] = nm_sprintf_buf (env_log_syslog, "NM_VPN_LOG_SYSLOG=%c", nm_logging_syslog_enabled () ? '1' : '0');
+
+ envp[i++] = NULL;
+ nm_assert (i <= n_environ + N_ENVIRON_EXTRA);
- success = g_spawn_async (NULL, vpn_argv, NULL, 0, nm_utils_setpgid, NULL, &pid, &spawn_error);
+ success = g_spawn_async (NULL, vpn_argv, envp, 0, nm_utils_setpgid, NULL, &pid, &spawn_error);
if (success) {
_LOGI ("Started the VPN service, PID %ld", (long int) pid);