Commit f48cec9f authored by Thomas Haller's avatar Thomas Haller
Browse files

properties,service: check for errors in write_config_option()

Check for errors during write, retry on EINTR and retry on
incomplete writes.

When write() or close() fails, report an error instead of logging
a warning with g_warning(). Using g_warning() is not great when run
as a plugin (because a runtime failure should not cause messages in
stdout). And is not great for service either, because it bypasses
whatever logging we want to perform there.

By reporting errors back to the caller, we no longer need to print
a g_warning() inside the utility function.
parent 4babaef9
......@@ -5,6 +5,7 @@ auth-dialog/main.c
properties/nm-libreswan-editor-plugin.c
properties/nm-libreswan-editor.c
src/nm-libreswan-service.c
shared/utils.h
shared/nm-utils/nm-shared-utils.c
shared/nm-vpn/nm-vpn-plugin-utils.c
[type: gettext/glade]properties/nm-libreswan-dialog.ui
......@@ -140,11 +140,12 @@ export_to_file (NMVpnEditorPlugin *self,
NMSettingVpn *s_vpn;
gboolean openswan = FALSE;
int fd, errsv;
gs_free_error GError *local = NULL;
fd = g_open (path, O_WRONLY | O_CREAT, 0777);
if (fd == -1) {
errsv = errno;
g_set_error (error, NMV_EDITOR_PLUGIN_ERROR, 0,
g_set_error (error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FAILED,
_("Can't open file '%s': %s"), path, g_strerror (errsv));
return FALSE;
}
......@@ -153,7 +154,12 @@ export_to_file (NMVpnEditorPlugin *self,
if (s_vpn)
openswan = nm_streq (nm_setting_vpn_get_service_type (s_vpn), NM_VPN_SERVICE_TYPE_OPENSWAN);
nm_libreswan_config_write (fd, connection, NULL, openswan);
if (!nm_libreswan_config_write (fd, connection, NULL, openswan, &local)) {
g_close (fd, NULL);
g_set_error (error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FAILED,
_("Error writing to file '%s': %s"), path, local->message);
return FALSE;
}
if (!g_close (fd, error))
return FALSE;
......
......@@ -76,6 +76,7 @@
#define nm_simple_connection_new nm_connection_new
#define NMV_EDITOR_PLUGIN_ERROR NM_SETTING_VPN_ERROR
#define NMV_EDITOR_PLUGIN_ERROR_FAILED NM_SETTING_VPN_ERROR_UNKNOWN
#define NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY NM_SETTING_VPN_ERROR_INVALID_PROPERTY
#define NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN NM_SETTING_VPN_ERROR_UNKNOWN
......@@ -84,6 +85,7 @@
#include <NetworkManager.h>
#define NMV_EDITOR_PLUGIN_ERROR NM_CONNECTION_ERROR
#define NMV_EDITOR_PLUGIN_ERROR_FAILED NM_CONNECTION_ERROR_FAILED
#define NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY NM_CONNECTION_ERROR_INVALID_PROPERTY
#define NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN NM_CONNECTION_ERROR_FAILED
......
......@@ -30,11 +30,12 @@
gboolean debug = FALSE;
void
gboolean
nm_libreswan_config_write (gint fd,
NMConnection *connection,
const char *bus_name,
gboolean openswan)
gboolean openswan,
GError **error)
{
NMSettingVpn *s_vpn = nm_connection_get_setting_vpn (connection);
const char *con_name;
......@@ -44,6 +45,8 @@ nm_libreswan_config_write (gint fd,
const char *phase2_alg_str;
const char *leftid;
g_return_val_if_fail (!error || !*error, FALSE);
/* We abuse the presence of bus name to decide if we're exporting
* the connection or actually configuring Pluto. */
if (bus_name)
......@@ -57,56 +60,64 @@ nm_libreswan_config_write (gint fd,
leftid = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_LEFTID);
write_config_option (fd, "conn %s", con_name);
#define WRITE_CHECK_NEWLINE(fd, new_line, error, ...) \
G_STMT_START { \
if (!write_config_option_newline ((fd), (new_line), (error), __VA_ARGS__)) \
return FALSE; \
} G_STMT_END
#define WRITE_CHECK(fd, error, ...) WRITE_CHECK_NEWLINE (fd, TRUE, error, __VA_ARGS__)
WRITE_CHECK (fd, error, "conn %s", con_name);
if (leftid) {
write_config_option (fd, " aggrmode=yes");
write_config_option (fd, " leftid=@%s", leftid);
WRITE_CHECK (fd, error, " aggrmode=yes");
WRITE_CHECK (fd, error, " leftid=@%s", leftid);
}
write_config_option (fd, " authby=secret");
write_config_option (fd, " left=%%defaultroute");
write_config_option (fd, " leftxauthclient=yes");
write_config_option (fd, " leftmodecfgclient=yes");
WRITE_CHECK (fd, error, " authby=secret");
WRITE_CHECK (fd, error, " left=%%defaultroute");
WRITE_CHECK (fd, error, " leftxauthclient=yes");
WRITE_CHECK (fd, error, " leftmodecfgclient=yes");
if (bus_name)
write_config_option (fd, " leftupdown=\"" NM_LIBRESWAN_HELPER_PATH " --bus-name %s\"", bus_name);
WRITE_CHECK (fd, error, " leftupdown=\"" NM_LIBRESWAN_HELPER_PATH " --bus-name %s\"", bus_name);
default_username = nm_setting_vpn_get_user_name (s_vpn);
props_username = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_LEFTXAUTHUSER);
if (props_username && strlen (props_username))
write_config_option (fd, " leftxauthusername=%s", props_username);
WRITE_CHECK (fd, error, " leftxauthusername=%s", props_username);
else if (default_username && strlen (default_username))
write_config_option (fd, " leftxauthusername=%s", default_username);
WRITE_CHECK (fd, error, " leftxauthusername=%s", default_username);
write_config_option (fd, " right=%s", nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_RIGHT));
write_config_option (fd, " remote_peer_type=cisco");
write_config_option (fd, " rightxauthserver=yes");
write_config_option (fd, " rightmodecfgserver=yes");
write_config_option (fd, " modecfgpull=yes");
write_config_option (fd, " rightsubnet=0.0.0.0/0");
WRITE_CHECK (fd, error, " right=%s", nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_RIGHT));
WRITE_CHECK (fd, error, " remote_peer_type=cisco");
WRITE_CHECK (fd, error, " rightxauthserver=yes");
WRITE_CHECK (fd, error, " rightmodecfgserver=yes");
WRITE_CHECK (fd, error, " modecfgpull=yes");
WRITE_CHECK (fd, error, " rightsubnet=0.0.0.0/0");
phase1_alg_str = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_IKE);
if (!phase1_alg_str || !strlen (phase1_alg_str))
write_config_option (fd, " ike=aes-sha1");
WRITE_CHECK (fd, error, " ike=aes-sha1");
else
write_config_option (fd, " ike=%s", phase1_alg_str);
WRITE_CHECK (fd, error, " ike=%s", phase1_alg_str);
phase2_alg_str = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_ESP);
if (!phase2_alg_str || !strlen (phase2_alg_str))
write_config_option (fd, " esp=aes-sha1;modp1024");
WRITE_CHECK (fd, error, " esp=aes-sha1;modp1024");
else
write_config_option (fd, " esp=%s", phase2_alg_str);
WRITE_CHECK (fd, error, " esp=%s", phase2_alg_str);
write_config_option (fd, " rekey=yes");
write_config_option (fd, " salifetime=24h");
write_config_option (fd, " ikelifetime=24h");
write_config_option (fd, " keyingtries=1");
WRITE_CHECK (fd, error, " rekey=yes");
WRITE_CHECK (fd, error, " salifetime=24h");
WRITE_CHECK (fd, error, " ikelifetime=24h");
WRITE_CHECK (fd, error, " keyingtries=1");
if (!openswan && g_strcmp0 (nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_VENDOR), "Cisco") == 0)
write_config_option (fd, " cisco-unity=yes");
WRITE_CHECK (fd, error, " cisco-unity=yes");
/* openswan requires a terminating \n (otherwise it segfaults) while
* libreswan fails parsing the configuration if you include the \n.
* WTF?
*/
write_config_option_newline (fd, (openswan || !bus_name), " auto=add");
WRITE_CHECK_NEWLINE (fd, (openswan || !bus_name), error, " auto=add");
return TRUE;
}
......@@ -24,15 +24,20 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#include <errno.h>
extern gboolean debug;
__attribute__((__format__ (__printf__, 3, 4)))
static inline void
write_config_option_newline (int fd, gboolean new_line, const char *format, ...)
__attribute__((__format__ (__printf__, 4, 5)))
static inline gboolean
write_config_option_newline (int fd, gboolean new_line, GError **error, const char *format, ...)
{
gs_free char *string = NULL;
const char *p;
va_list args;
gsize l;
int errsv;
gssize w;
va_start (args, format);
string = g_strdup_vprintf (format, args);
......@@ -52,15 +57,37 @@ write_config_option_newline (int fd, gboolean new_line, const char *format, ...)
l++;
}
if (write (fd, string, l) <= 0)
g_warning ("nm-libreswan: error in write_config_option");
p = string;
while (true) {
w = write (fd, p, l);
if (w == l)
return TRUE;
if (w > 0) {
g_assert (w < l);
p += w;
l -= w;
continue;
}
if (w == 0) {
errno = EIO;
break;
}
errsv = errno;
if (errsv == EINTR)
continue;
break;
}
g_set_error (error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR,
_("Error writing config: %s"), g_strerror (errsv));
return FALSE;
}
#define write_config_option(fd, ...) write_config_option_newline((fd), TRUE, __VA_ARGS__)
#define write_config_option(fd, error, ...) write_config_option_newline((fd), TRUE, error, __VA_ARGS__)
void
gboolean
nm_libreswan_config_write (gint fd,
NMConnection *connection,
const char *bus_name,
gboolean openswan);
gboolean openswan,
GError **error);
#endif /* __UTILS_H__ */
......@@ -49,6 +49,7 @@
#include <stdarg.h>
#include <pty.h>
#include <sys/types.h>
#include <glib/gstdio.h>
#include "nm-libreswan-helper-service-dbus.h"
#include "utils.h"
......@@ -654,6 +655,7 @@ nm_libreswan_config_psk_write (NMSettingVpn *s_vpn,
const char *pw_type, *psk, *leftid, *right;
int fd;
int errsv;
gboolean success;
/* Check for ignored group password */
pw_type = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_PSK_INPUT_MODES);
......@@ -693,15 +695,18 @@ nm_libreswan_config_psk_write (NMSettingVpn *s_vpn,
leftid = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_LEFTID);
if (leftid) {
write_config_option (fd, "@%s: PSK \"%s\"", leftid, psk);
success = write_config_option (fd, error, "@%s: PSK \"%s\"", leftid, psk);
} else {
right = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_RIGHT);
g_assert (right);
write_config_option (fd, "%s %%any: PSK \"%s\"", right, psk);
success = write_config_option (fd, error, "%s %%any: PSK \"%s\"", right, psk);
}
close (fd);
return TRUE;
if (!success) {
g_close (fd, NULL);
return FALSE;
}
return g_close (fd, error);
}
/****************************************************************/
......@@ -1598,10 +1603,13 @@ connect_step (NMLibreswanPlugin *self, GError **error)
return FALSE;
priv->watch_id = g_child_watch_add (priv->pid, child_watch_cb, self);
g_object_get (self, NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, &bus_name, NULL);
nm_libreswan_config_write (fd, priv->connection, bus_name, priv->openswan);
if (!nm_libreswan_config_write (fd, priv->connection, bus_name, priv->openswan, error)) {
g_close (fd, NULL);
g_free (bus_name);
return FALSE;
}
g_free (bus_name);
close (fd);
return TRUE;
return g_close (fd, error);
case CONNECT_STEP_CONNECT:
g_assert (uuid);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment