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>
dbus_reload(list o, list n)
{
	element e1, e2, e3;
	vrrp_t *vrrp_n, *vrrp_o, *vrrp_n3;

	if (!LIST_ISEMPTY(n)) {
		for (e1 = LIST_HEAD(n); e1; ELEMENT_NEXT(e1)) {
			char *n_name;
			bool match_found;

			vrrp_n = ELEMENT_DATA(e1);

			if (LIST_ISEMPTY(o)) {
				dbus_create_object(vrrp_n);
				continue;
			}

			n_name = IF_BASE_IFP(vrrp_n->ifp)->ifname;

			/* Try an find an instance with same vrid/family/interface that existed before and now */
			for (e2 = LIST_HEAD(o), match_found = false; e2 && !match_found; ELEMENT_NEXT(e2)) {
				vrrp_o = ELEMENT_DATA(e2);

				if (vrrp_n->vrid == vrrp_o->vrid &&
				    vrrp_n->family == vrrp_o->family &&
				    !strcmp(n_name, IF_BASE_IFP(vrrp_o->ifp)->ifname)) {
					/* If the old instance exists in the new config,
					 * then the dbus object will exist */
					if (!strcmp(vrrp_n->iname, vrrp_o->iname)) {
						match_found = true;
						break;
					}

					/* Check if the old instance name we found still exists
					 * (but has a different vrid/family/interface) */
					for (e3 = LIST_HEAD(n); e3; ELEMENT_NEXT(e3)) {
						vrrp_n3 = ELEMENT_DATA(e3);
						if (!strcmp(vrrp_o->iname, vrrp_n3->iname)) {
							match_found = true;
							break;
						}
					}
				}
			}

			if (match_found)
				continue;

			dbus_create_object(vrrp_n);
		}
	}

	/* Signal we have reloaded */
	dbus_send_reload_signal();

	/* We need to reinstate the read thread */
	thread_add_read(master, handle_dbus_msg, NULL, dbus_in_pipe[0], TIMER_NEVER);
}

dbus_reload(list o, list n)
{
	element e1, e2, e3;
	vrrp_t *vrrp_n, *vrrp_o, *vrrp_n3;

	if (!LIST_ISEMPTY(n)) {
		for (e1 = LIST_HEAD(n); e1; ELEMENT_NEXT(e1)) {
			char *n_name;
			bool match_found;

			vrrp_n = ELEMENT_DATA(e1);

			if (LIST_ISEMPTY(o)) {
				dbus_create_object(vrrp_n);
				continue;
			}

			n_name = IF_BASE_IFP(vrrp_n->ifp)->ifname;

			/* Try an find an instance with same vrid/family/interface that existed before and now */
			for (e2 = LIST_HEAD(o), match_found = false; e2 && !match_found; ELEMENT_NEXT(e2)) {
				vrrp_o = ELEMENT_DATA(e2);

				if (vrrp_n->vrid == vrrp_o->vrid &&
				    vrrp_n->family == vrrp_o->family &&
				    !strcmp(n_name, IF_BASE_IFP(vrrp_o->ifp)->ifname)) {
					/* If the old instance exists in the new config,
					 * then the dbus object will exist */
					if (!strcmp(vrrp_n->iname, vrrp_o->iname)) {
						match_found = true;
						break;
					}

					/* Check if the old instance name we found still exists
					 * (but has a different vrid/family/interface) */
					for (e3 = LIST_HEAD(n); e3; ELEMENT_NEXT(e3)) {
						vrrp_n3 = ELEMENT_DATA(e3);
						if (!strcmp(vrrp_o->iname, vrrp_n3->iname)) {
							match_found = true;
							break;
						}
					}
				}
			}

			if (match_found)
				continue;

			dbus_create_object(vrrp_n);
		}
	}

	/* Signal we have reloaded */
	dbus_send_reload_signal();

	/* We need to reinstate the read thread */
	thread_add_read(master, handle_dbus_msg, NULL, dbus_in_pipe[0], TIMER_NEVER);
}
