When opening files for write, ensure they aren't symbolic links

Issue #1048 identified that if, for example, a non privileged user
created a symbolic link from /etc/keepalvied.data to /etc/passwd,
writing to /etc/keepalived.data (which could be invoked via DBus)
would cause /etc/passwd to be overwritten.

This commit stops keepalived writing to pathnames where the ultimate
component is a symbolic link, by setting O_NOFOLLOW whenever opening
a file for writing.

This might break some setups, where, for example, /etc/keepalived.data
was a symbolic link to /home/fred/keepalived.data. If this was the case,
instead create a symbolic link from /home/fred/keepalived.data to
/tmp/keepalived.data, so that the file is still accessible via
/home/fred/keepalived.data.

There doesn't appear to be a way around this backward incompatibility,
since even checking if the pathname is a symbolic link prior to opening
for writing would create a race condition.

Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
get_interface_ids(const gchar *object_path, gchar *interface, uint8_t *vrid, uint8_t *family)
{
	int path_length = DBUS_VRRP_INSTANCE_PATH_DEFAULT_LENGTH;
	gchar **dirs;
	char *endptr;

#if HAVE_DECL_CLONE_NEWNET
	if(global_data->network_namespace)
		path_length++;
#endif
	if(global_data->instance_name)
		path_length++;

	/* object_path will have interface, vrid and family as
	 * the third to last, second to last and last levels */
	dirs = g_strsplit(object_path, "/", path_length);
	strcpy(interface, dirs[path_length-3]);
	*vrid = (uint8_t)strtoul(dirs[path_length-2], &endptr, 10);
	if (*endptr)
		log_message(LOG_INFO, "Dbus unexpected characters '%s' at end of number '%s'", endptr, dirs[path_length-2]);
	*family = !g_strcmp0(dirs[path_length-1], "IPv4") ? AF_INET : !g_strcmp0(dirs[path_length-1], "IPv6") ? AF_INET6 : AF_UNSPEC;

	/* We are finished with all the object_path strings now */
	g_strfreev(dirs);
}

get_interface_ids(const gchar *object_path, gchar *interface, uint8_t *vrid, uint8_t *family)
{
	int path_length = DBUS_VRRP_INSTANCE_PATH_DEFAULT_LENGTH;
	gchar **dirs;
	char *endptr;

#if HAVE_DECL_CLONE_NEWNET
	if(global_data->network_namespace)
		path_length++;
#endif
	if(global_data->instance_name)
		path_length++;

	/* object_path will have interface, vrid and family as
	 * the third to last, second to last and last levels */
	dirs = g_strsplit(object_path, "/", path_length);
	strcpy(interface, dirs[path_length-3]);
	*vrid = (uint8_t)strtoul(dirs[path_length-2], &endptr, 10);
	if (*endptr)
		log_message(LOG_INFO, "Dbus unexpected characters '%s' at end of number '%s'", endptr, dirs[path_length-2]);
	*family = !g_strcmp0(dirs[path_length-1], "IPv4") ? AF_INET : !g_strcmp0(dirs[path_length-1], "IPv6") ? AF_INET6 : AF_UNSPEC;

	/* We are finished with all the object_path strings now */
	g_strfreev(dirs);
}
