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