From 93e090592fc6de7ec5d3d42c1bb9074ad1f3ba34 Mon Sep 17 00:00:00 2001
From: Andris Zeila <andris.zeila@zabbix.com>
Date: Fri, 12 Jan 2024 05:48:31 +0000
Subject: [PATCH] .......PS. [DEV-2695] changed fping tests to read address
 from file

Merge in ZBX/zabbix from feature/DEV-2695-6.0 to release/6.0

* commit '6603893ff94620e28fc543d5d0d4c86b9be3342e':
  .......PS. [DEV-2695] fixed signal blocking
  .......PS. [DEV-2695] added target hostname/ip validation in fping feature tests
  .......PS. [DEV-2695] added error messages when failed to prepare temporary file for fping tests
  .......PS. [DEV-2695] changed fping tests to read address from file

CVE: CVE-2023-32727
Upstream-Status: BAckport [https://github.com/zabbix/zabbix/commit/93e090592fc6de7ec5d3d42c1bb9074ad1f3ba34]

Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
---
 src/libs/zbxicmpping/icmpping.c | 125 ++++++++++++++++++++++++++++----
 1 file changed, 112 insertions(+), 13 deletions(-)

diff --git a/src/libs/zbxicmpping/icmpping.c b/src/libs/zbxicmpping/icmpping.c
index 72f7e86..9a751b7 100644
--- a/src/libs/zbxicmpping/icmpping.c
+++ b/src/libs/zbxicmpping/icmpping.c
@@ -59,6 +59,8 @@ static void	get_source_ip_option(const char *fping, const char **option, unsigne

	zbx_snprintf(tmp, sizeof(tmp), "%s -h 2>&1", fping);

+	zabbix_log(LOG_LEVEL_DEBUG, "executing %s", tmp);
+
	if (NULL == (f = popen(tmp, "r")))
		return;

@@ -85,6 +87,110 @@ static void	get_source_ip_option(const char *fping, const char **option, unsigne
	*checked = 1;
 }

+/******************************************************************************
+ *                                                                            *
+ * Purpose: execute external program and return stdout and stderr values      *
+ *                                                                            *
+ * Parameters: fping         - [IN] location of fping program                 *
+ *             out           - [OUT] stdout and stderr values                 *
+ *             error         - [OUT] error string if function fails           *
+ *             max_error_len - [IN] length of error buffer                    *
+ *                                                                            *
+ * Return value: SUCCEED if processed successfully or FAIL otherwise          *
+ *                                                                            *
+ ******************************************************************************/
+static int	get_fping_out(const char *fping, const char *address, char **out, char *error, size_t max_error_len)
+{
+	FILE		*f;
+	size_t		buf_size = 0, offset = 0, len;
+	ssize_t		n;
+	char		tmp[MAX_STRING_LEN], *buffer = NULL;
+	int		ret = FAIL, fd;
+	sigset_t	mask, orig_mask;
+	char		filename[MAX_STRING_LEN];
+
+	if (FAIL == zbx_validate_hostname(address) && FAIL == is_supported_ip(address))
+	{
+		zbx_strlcpy(error, "Invalid host name or IP address", max_error_len);
+		return FAIL;
+	}
+
+	zbx_snprintf(filename, sizeof(filename), "%s/%s_XXXXXX", CONFIG_TMPDIR, progname);
+	if (-1 == (fd = mkstemp(filename)))
+	{
+		zbx_snprintf(error, max_error_len, "Cannot create temporary file \"%s\": %s", filename,
+				zbx_strerror(errno));
+
+		return FAIL;
+	}
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGINT);
+	sigaddset(&mask, SIGQUIT);
+
+	len = strlen(address);
+	if (-1 == (n = write(fd, address, len)))
+	{
+		zbx_snprintf(error, max_error_len, "Cannot write address into temporary file: %s", zbx_strerror(errno));
+		(void)close(fd);
+		goto out;
+	}
+
+	if (n != (ssize_t)len)
+	{
+		zbx_strlcpy(error, "Cannot write full address into temporary file", max_error_len);
+		(void)close(fd);
+		goto out;
+	}
+
+	if (-1 == close(fd))
+	{
+		zbx_snprintf(error, max_error_len, "Cannot close temporary file: %s", zbx_strerror(errno));
+		goto out;
+	}
+
+	zbx_snprintf(tmp, sizeof(tmp), "%s 2>&1 < %s", fping, filename);
+
+	if (0 > sigprocmask(SIG_BLOCK, &mask, &orig_mask))
+		zbx_error("cannot set sigprocmask to block the user signal");
+
+	zabbix_log(LOG_LEVEL_DEBUG, "executing %s", tmp);
+
+	if (NULL == (f = popen(tmp, "r")))
+	{
+		zbx_strlcpy(error, zbx_strerror(errno), max_error_len);
+		goto out;
+	}
+
+	while (NULL != zbx_fgets(tmp, sizeof(tmp), f))
+	{
+		len = strlen(tmp);
+
+		if (MAX_EXECUTE_OUTPUT_LEN < offset + len)
+			break;
+
+		zbx_strncpy_alloc(&buffer, &buf_size, &offset, tmp, len);
+	}
+
+	pclose(f);
+
+	if (NULL == buffer)
+	{
+		zbx_strlcpy(error, "Cannot obtain the program output", max_error_len);
+		goto out;
+	}
+
+	*out = buffer;
+	ret = SUCCEED;
+out:
+	unlink(filename);
+
+	if (0 > sigprocmask(SIG_SETMASK, &orig_mask, NULL))
+		zbx_error("cannot restore sigprocmask");
+
+	return ret;
+}
+
 /******************************************************************************
  *                                                                            *
  * Function: get_interval_option                                              *
@@ -137,19 +243,12 @@ static int	get_interval_option(const char *fping, ZBX_FPING_HOST *hosts, int hos

			zabbix_log(LOG_LEVEL_DEBUG, "testing fping interval %u ms", intervals[j]);

-			zbx_snprintf(tmp, sizeof(tmp), "%s -c1 -t50 -i%u %s", fping, intervals[j], dst);
+			zbx_snprintf(tmp, sizeof(tmp), "%s -c1 -t50 -i%u", fping, intervals[j]);

			zbx_free(out);

			/* call fping, ignore its exit code but mind execution failures */
-			if (TIMEOUT_ERROR == (ret_exec = zbx_execute(tmp, &out, err, sizeof(err), 1,
-					ZBX_EXIT_CODE_CHECKS_DISABLED, NULL)))
-			{
-				zbx_snprintf(error, max_error_len, "Timeout while executing \"%s\"", tmp);
-				goto out;
-			}
-
-			if (FAIL == ret_exec)
+			if (SUCCEED != (ret_exec = get_fping_out(tmp, dst, &out, err, sizeof(err))))
			{
				zbx_snprintf(error, max_error_len, "Cannot execute \"%s\": %s", tmp, err);
				goto out;
@@ -251,10 +350,10 @@ static int	get_ipv6_support(const char * fping, const char *dst)
	int	ret;
	char	tmp[MAX_STRING_LEN], error[255], *out = NULL;

-	zbx_snprintf(tmp, sizeof(tmp), "%s -6 -c1 -t50 %s", fping, dst);
+	zbx_snprintf(tmp, sizeof(tmp), "%s -6 -c1 -t50", fping);

-	if ((SUCCEED == (ret = zbx_execute(tmp, &out, error, sizeof(error), 1, ZBX_EXIT_CODE_CHECKS_DISABLED, NULL)) &&
-				ZBX_KIBIBYTE > strlen(out) && NULL != strstr(out, dst)) || TIMEOUT_ERROR == ret)
+	if (SUCCEED == (ret = get_fping_out(tmp, dst, &out, error, sizeof(error)) &&
+				ZBX_KIBIBYTE > strlen(out) && NULL != strstr(out, dst)))
	{
		ret = SUCCEED;
	}
@@ -538,7 +637,7 @@ static int	process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i

	fclose(f);

-	zabbix_log(LOG_LEVEL_DEBUG, "%s", tmp);
+	zabbix_log(LOG_LEVEL_DEBUG, "executing %s", tmp);

	sigemptyset(&mask);
	sigaddset(&mask, SIGINT);
--
2.40.0
