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

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