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

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