Blame SOURCES/0009-library-add-_adcli_call_external_program.patch

f441eb
From 63576f12524f521c0cf08d42b279654885135a90 Mon Sep 17 00:00:00 2001
f441eb
From: Sumit Bose <sbose@redhat.com>
f441eb
Date: Tue, 30 Jan 2018 14:39:17 +0100
f441eb
Subject: [PATCH 09/23] library: add _adcli_call_external_program()
f441eb
f441eb
Allow adcli to call an external program given by an absolute path name
f441eb
and an array of options. stdin and stdout can be used if needed.
f441eb
f441eb
https://bugs.freedesktop.org/show_bug.cgi?id=100118
f441eb
f441eb
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
f441eb
---
f441eb
 configure.ac        |  28 +++++++
f441eb
 library/adprivate.h |   6 ++
f441eb
 library/adutil.c    | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
f441eb
 3 files changed, 245 insertions(+)
f441eb
f441eb
diff --git a/configure.ac b/configure.ac
f441eb
index 221d8ae..fe86638 100644
f441eb
--- a/configure.ac
f441eb
+++ b/configure.ac
f441eb
@@ -263,6 +263,34 @@ AC_SUBST(LCOV)
f441eb
 AC_SUBST(GCOV)
f441eb
 AC_SUBST(GENHTML)
f441eb
 
f441eb
+AC_PATH_PROG(BIN_CAT, cat, no)
f441eb
+if test "$BIN_CAT" = "no" ; then
f441eb
+	AC_MSG_ERROR([cat is not available])
f441eb
+else
f441eb
+	AC_DEFINE_UNQUOTED(BIN_CAT, "$BIN_CAT", [path to cat, used in unit test])
f441eb
+fi
f441eb
+
f441eb
+AC_PATH_PROG(BIN_TAC, tac, no)
f441eb
+if test "$BIN_TAC" = "no" ; then
f441eb
+	AC_MSG_ERROR([tac is not available])
f441eb
+else
f441eb
+	AC_DEFINE_UNQUOTED(BIN_TAC, "$BIN_TAC", [path to tac, used in unit test])
f441eb
+fi
f441eb
+
f441eb
+AC_PATH_PROG(BIN_REV, rev, no)
f441eb
+if test "$BIN_REV" = "no" ; then
f441eb
+	AC_MSG_ERROR([rev is not available])
f441eb
+else
f441eb
+	AC_DEFINE_UNQUOTED(BIN_REV, "$BIN_REV", [path to rev, used in unit test])
f441eb
+fi
f441eb
+
f441eb
+AC_PATH_PROG(BIN_ECHO, echo, no)
f441eb
+if test "$BIN_ECHO" = "no" ; then
f441eb
+	AC_MSG_ERROR([echo is not available])
f441eb
+else
f441eb
+	AC_DEFINE_UNQUOTED(BIN_ECHO, "$BIN_ECHO", [path to echo, used in unit test])
f441eb
+fi
f441eb
+
f441eb
 # ---------------------------------------------------------------------
f441eb
 
f441eb
 ADCLI_LT_RELEASE=$ADCLI_CURRENT:$ADCLI_REVISION:$ADCLI_AGE
f441eb
diff --git a/library/adprivate.h b/library/adprivate.h
f441eb
index e99f9fc..7257c93 100644
f441eb
--- a/library/adprivate.h
f441eb
+++ b/library/adprivate.h
f441eb
@@ -285,4 +285,10 @@ struct _adcli_attrs {
f441eb
 
f441eb
 bool             _adcli_check_nt_time_string_lifetime (const char *nt_time_string, unsigned int lifetime);
f441eb
 
f441eb
+adcli_result     _adcli_call_external_program     (const char *binary,
f441eb
+                                                   char * const *argv,
f441eb
+                                                   const char *stdin_data,
f441eb
+                                                   uint8_t **stdout_data,
f441eb
+                                                   size_t *stdout_data_len);
f441eb
+
f441eb
 #endif /* ADPRIVATE_H_ */
f441eb
diff --git a/library/adutil.c b/library/adutil.c
f441eb
index 829cdd9..a27bd68 100644
f441eb
--- a/library/adutil.c
f441eb
+++ b/library/adutil.c
f441eb
@@ -36,6 +36,7 @@
f441eb
 #include <unistd.h>
f441eb
 #include <stdint.h>
f441eb
 #include <time.h>
f441eb
+#include <sys/wait.h>
f441eb
 
f441eb
 static adcli_message_func message_func = NULL;
f441eb
 static char last_error[2048] = { 0, };
f441eb
@@ -506,6 +507,161 @@ _adcli_check_nt_time_string_lifetime (const char *nt_time_string,
f441eb
 	return false;
f441eb
 }
f441eb
 
f441eb
+adcli_result
f441eb
+_adcli_call_external_program (const char *binary, char * const *argv,
f441eb
+                              const char *stdin_data,
f441eb
+                              uint8_t **stdout_data, size_t *stdout_data_len)
f441eb
+{
f441eb
+	int ret;
f441eb
+	int pipefd_to_child[2] = { -1, -1};
f441eb
+	int pipefd_from_child[2] = { -1, -1};
f441eb
+	pid_t child_pid = 0;
f441eb
+	int err;
f441eb
+	size_t len;
f441eb
+	ssize_t rlen;
f441eb
+	pid_t wret;
f441eb
+	int status;
f441eb
+	uint8_t read_buf[4096];
f441eb
+	uint8_t *out;
f441eb
+
f441eb
+	errno = 0;
f441eb
+	ret = access (binary, X_OK);
f441eb
+	if (ret != 0) {
f441eb
+		err = errno;
f441eb
+		_adcli_err ("Cannot run [%s]: [%d][%s].", binary, err,
f441eb
+		                                          strerror (err));
f441eb
+		ret = ADCLI_ERR_FAIL;
f441eb
+		goto done;
f441eb
+	}
f441eb
+
f441eb
+	ret = pipe (pipefd_from_child);
f441eb
+	if (ret == -1) {
f441eb
+		err = errno;
f441eb
+		_adcli_err ("pipe failed [%d][%s].", err, strerror (err));
f441eb
+		ret = ADCLI_ERR_FAIL;
f441eb
+		goto done;
f441eb
+	}
f441eb
+
f441eb
+	ret = pipe (pipefd_to_child);
f441eb
+	if (ret == -1) {
f441eb
+		err = errno;
f441eb
+		_adcli_err ("pipe failed [%d][%s].", err, strerror (err));
f441eb
+		ret = ADCLI_ERR_FAIL;
f441eb
+		goto done;
f441eb
+	}
f441eb
+
f441eb
+	child_pid = fork ();
f441eb
+
f441eb
+	if (child_pid == 0) { /* child */
f441eb
+		close (pipefd_to_child[1]);
f441eb
+		ret = dup2 (pipefd_to_child[0], STDIN_FILENO);
f441eb
+		if (ret == -1) {
f441eb
+			err = errno;
f441eb
+			_adcli_err ("dup2 failed [%d][%s].", err,
f441eb
+			                                     strerror (err));
f441eb
+			exit (EXIT_FAILURE);
f441eb
+		}
f441eb
+
f441eb
+		close (pipefd_from_child[0]);
f441eb
+		ret = dup2 (pipefd_from_child[1], STDOUT_FILENO);
f441eb
+		if (ret == -1) {
f441eb
+			err = errno;
f441eb
+			_adcli_err ("dup2 failed [%d][%s].", err,
f441eb
+			                                     strerror (err));
f441eb
+			exit (EXIT_FAILURE);
f441eb
+		}
f441eb
+
f441eb
+		execv (binary, argv);
f441eb
+		_adcli_err ("Failed to run %s.", binary);
f441eb
+		ret = ADCLI_ERR_FAIL;
f441eb
+		goto done;
f441eb
+	} else if (child_pid > 0) { /* parent */
f441eb
+
f441eb
+		if (stdin_data != NULL) {
f441eb
+			len = strlen (stdin_data);
f441eb
+			ret = write (pipefd_to_child[1], stdin_data, len);
f441eb
+			if (ret != len) {
f441eb
+				_adcli_err ("Failed to send computer account password "
f441eb
+				            "to net command.");
f441eb
+				ret = ADCLI_ERR_FAIL;
f441eb
+				goto done;
f441eb
+			}
f441eb
+		}
f441eb
+
f441eb
+		close (pipefd_to_child[0]);
f441eb
+		pipefd_to_child[0] = -1;
f441eb
+		close (pipefd_to_child[1]);
f441eb
+		pipefd_to_child[0] = -1;
f441eb
+
f441eb
+		if (stdout_data != NULL || stdout_data_len != NULL) {
f441eb
+			rlen = read (pipefd_from_child[0], read_buf, sizeof (read_buf));
f441eb
+			if (rlen < 0) {
f441eb
+				ret = errno;
f441eb
+				_adcli_err ("Failed to read from child [%d][%s].\n",
f441eb
+				            ret, strerror (ret));
f441eb
+				ret = ADCLI_ERR_FAIL;
f441eb
+				goto done;
f441eb
+			}
f441eb
+
f441eb
+			out = malloc (sizeof(uint8_t) * rlen);
f441eb
+			if (out == NULL) {
f441eb
+				_adcli_err ("Failed to allocate memory "
f441eb
+				            "for child output.");
f441eb
+				ret = ADCLI_ERR_FAIL;
f441eb
+				goto done;
f441eb
+			} else {
f441eb
+				memcpy (out, read_buf, rlen);
f441eb
+			}
f441eb
+
f441eb
+			if (stdout_data != NULL) {
f441eb
+				*stdout_data = out;
f441eb
+			} else {
f441eb
+				free (out);
f441eb
+			}
f441eb
+
f441eb
+			if (stdout_data_len != NULL) {
f441eb
+				*stdout_data_len = rlen;
f441eb
+			}
f441eb
+		}
f441eb
+
f441eb
+	} else {
f441eb
+		_adcli_err ("Cannot run net command.");
f441eb
+		ret = ADCLI_ERR_FAIL;
f441eb
+		goto done;
f441eb
+	}
f441eb
+
f441eb
+	ret = ADCLI_SUCCESS;
f441eb
+
f441eb
+done:
f441eb
+	if (pipefd_from_child[0] != -1) {
f441eb
+		close (pipefd_from_child[0]);
f441eb
+	}
f441eb
+	if (pipefd_from_child[1] != -1) {
f441eb
+		close (pipefd_from_child[1]);
f441eb
+	}
f441eb
+	if (pipefd_to_child[0] != -1) {
f441eb
+		close (pipefd_to_child[0]);
f441eb
+	}
f441eb
+	if (pipefd_to_child[1] != -1) {
f441eb
+		close (pipefd_to_child[1]);
f441eb
+	}
f441eb
+
f441eb
+	if (child_pid > 0) {
f441eb
+		wret = waitpid (child_pid, &status, 0);
f441eb
+		if (wret == -1) {
f441eb
+			_adcli_err ("No sure what happend to net command.");
f441eb
+		} else {
f441eb
+			if (WIFEXITED (status)) {
f441eb
+				_adcli_err ("net command failed with %d.",
f441eb
+				            WEXITSTATUS (status));
f441eb
+			}
f441eb
+		}
f441eb
+	}
f441eb
+
f441eb
+	return ret;
f441eb
+}
f441eb
+
f441eb
+
f441eb
 #ifdef UTIL_TESTS
f441eb
 
f441eb
 #include "test.h"
f441eb
@@ -620,6 +776,60 @@ test_bin_sid_to_str (void)
f441eb
 	free (str);
f441eb
 }
f441eb
 
f441eb
+static void
f441eb
+test_call_external_program (void)
f441eb
+{
f441eb
+	adcli_result res;
f441eb
+	char *argv[] = { NULL, NULL, NULL };
f441eb
+	uint8_t *stdout_data;
f441eb
+	size_t stdout_data_len;
f441eb
+
f441eb
+	argv[0] = "/does/not/exists";
f441eb
+	res = _adcli_call_external_program (argv[0], argv, NULL, NULL, NULL);
f441eb
+	assert (res == ADCLI_ERR_FAIL);
f441eb
+
f441eb
+#ifdef BIN_CAT
f441eb
+	argv[0] = BIN_CAT;
f441eb
+	res = _adcli_call_external_program (argv[0], argv, "Hello",
f441eb
+	                                    &stdout_data, &stdout_data_len);
f441eb
+	assert (res == ADCLI_SUCCESS);
f441eb
+	assert (strncmp ("Hello", (char *) stdout_data, stdout_data_len) == 0);
f441eb
+	free (stdout_data);
f441eb
+
f441eb
+	res = _adcli_call_external_program (argv[0], argv, "Hello",
f441eb
+	                                    NULL, NULL);
f441eb
+	assert (res == ADCLI_SUCCESS);
f441eb
+#endif
f441eb
+
f441eb
+#ifdef BIN_REV
f441eb
+	argv[0] = BIN_REV;
f441eb
+	res = _adcli_call_external_program (argv[0], argv, "Hello\n",
f441eb
+	                                    &stdout_data, &stdout_data_len);
f441eb
+	assert (res == ADCLI_SUCCESS);
f441eb
+	assert (strncmp ("olleH\n", (char *) stdout_data, stdout_data_len) == 0);
f441eb
+	free (stdout_data);
f441eb
+#endif
f441eb
+
f441eb
+#ifdef BIN_TAC
f441eb
+	argv[0] = BIN_TAC;
f441eb
+	res = _adcli_call_external_program (argv[0], argv, "Hello\nWorld\n",
f441eb
+	                                    &stdout_data, &stdout_data_len);
f441eb
+	assert (res == ADCLI_SUCCESS);
f441eb
+	assert (strncmp ("World\nHello\n", (char *) stdout_data, stdout_data_len) == 0);
f441eb
+	free (stdout_data);
f441eb
+#endif
f441eb
+
f441eb
+#ifdef BIN_ECHO
f441eb
+	argv[0] = BIN_ECHO;
f441eb
+	argv[1] = "Hello";
f441eb
+	res = _adcli_call_external_program (argv[0], argv, NULL,
f441eb
+	                                    &stdout_data, &stdout_data_len);
f441eb
+	assert (res == ADCLI_SUCCESS);
f441eb
+	assert (strncmp ("Hello\n", (char *) stdout_data, stdout_data_len) == 0);
f441eb
+	free (stdout_data);
f441eb
+#endif
f441eb
+}
f441eb
+
f441eb
 int
f441eb
 main (int argc,
f441eb
       char *argv[])
f441eb
@@ -629,6 +839,7 @@ main (int argc,
f441eb
 	test_func (test_strv_count, "/util/strv_count");
f441eb
 	test_func (test_check_nt_time_string_lifetime, "/util/check_nt_time_string_lifetime");
f441eb
 	test_func (test_bin_sid_to_str, "/util/bin_sid_to_str");
f441eb
+	test_func (test_call_external_program, "/util/call_external_program");
f441eb
 	return test_run (argc, argv);
f441eb
 }
f441eb
 
f441eb
-- 
f441eb
2.14.4
f441eb