]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
put argv_* functions into own file, add unit tests
authorHeiko Hund <heiko.hund@sophos.com>
Fri, 28 Oct 2016 16:42:37 +0000 (18:42 +0200)
committerGert Doering <gert@greenie.muc.de>
Mon, 14 Nov 2016 19:17:29 +0000 (20:17 +0100)
misc.c is too crowded with different things to perform any
sane unit testing due to its dependencies. So, in order to re-write
the #ifdef'ed tests for the argv_* family of functions into unit
tests I moved them into a dedicated file.

Signed-off-by: Heiko Hund <heiko.hund@sophos.com>
Acked-by: David Sommerseth <davids@redhat.com>
Message-Id: <1477672963-5724-2-git-send-email-heiko.hund@sophos.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12811.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
configure.ac
src/openvpn/Makefile.am
src/openvpn/argv.c [new file with mode: 0644]
src/openvpn/argv.h [new file with mode: 0644]
src/openvpn/misc.c
src/openvpn/misc.h
tests/unit_tests/Makefile.am
tests/unit_tests/openvpn/Makefile.am [new file with mode: 0644]
tests/unit_tests/openvpn/test_argv.c [new file with mode: 0644]

index 18c772d6235fb1cc4183ee22af1f8663cd6f2d0f..8ea9de8a700a3364305d74863c92c23d3ae24eae 100644 (file)
@@ -1301,6 +1301,7 @@ AC_CONFIG_FILES([
         tests/unit_tests/plugins/Makefile
         tests/unit_tests/plugins/auth-pam/Makefile
         tests/unit_tests/example_test/Makefile
+        tests/unit_tests/openvpn/Makefile
         vendor/Makefile
        sample/Makefile
        doc/Makefile
index a306726a89754753df214daf31c9e643481e0154..12b9ebf40916ac5c874ff05d7109e75d2187ab60 100644 (file)
@@ -36,6 +36,7 @@ endif
 sbin_PROGRAMS = openvpn
 
 openvpn_SOURCES = \
+       argv.c argv.h \
        base64.c base64.h \
        basic.h \
        buffer.c buffer.h \
diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c
new file mode 100644 (file)
index 0000000..2f2a5f5
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ *  A printf-like function (that only recognizes a subset of standard printf
+ *  format operators) that prints arguments to an argv list instead
+ *  of a standard string.  This is used to build up argv arrays for passing
+ *  to execve.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#include "argv.h"
+#include "options.h"
+
+void
+argv_init (struct argv *a)
+{
+  a->capacity = 0;
+  a->argc = 0;
+  a->argv = NULL;
+  a->system_str = NULL;
+}
+
+struct argv
+argv_new (void)
+{
+  struct argv ret;
+  argv_init (&ret);
+  return ret;
+}
+
+void
+argv_reset (struct argv *a)
+{
+  size_t i;
+  for (i = 0; i < a->argc; ++i)
+    free (a->argv[i]);
+  free (a->argv);
+  free (a->system_str);
+  argv_init (a);
+}
+
+static void
+argv_extend (struct argv *a, const size_t newcap)
+{
+  if (newcap > a->capacity)
+    {
+      char **newargv;
+      size_t i;
+      ALLOC_ARRAY_CLEAR (newargv, char *, newcap);
+      for (i = 0; i < a->argc; ++i)
+        newargv[i] = a->argv[i];
+      free (a->argv);
+      a->argv = newargv;
+      a->capacity = newcap;
+    }
+}
+
+static void
+argv_grow (struct argv *a, const size_t add)
+{
+  const size_t newargc = a->argc + add + 1;
+  ASSERT (newargc > a->argc);
+  argv_extend (a, adjust_power_of_2 (newargc));
+}
+
+static void
+argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */
+{
+  argv_grow (a, 1);
+  a->argv[a->argc++] = str;
+}
+
+static void
+argv_system_str_append (struct argv *a, const char *str, const bool enquote)
+{
+  if (str)
+    {
+      char *newstr;
+
+      /* compute length of new system_str */
+      size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */
+      if (a->system_str)
+        l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */
+      if (enquote)
+        l += 2; /* space for two quotes */
+
+      /* build new system_str */
+      newstr = (char *) malloc (l);
+      newstr[0] = '\0';
+      check_malloc_return (newstr);
+      if (a->system_str)
+        {
+          strcpy (newstr, a->system_str);
+          strcat (newstr, " ");
+        }
+      if (enquote)
+        strcat (newstr, "\"");
+      strcat (newstr, str);
+      if (enquote)
+        strcat (newstr, "\"");
+      free (a->system_str);
+      a->system_str = newstr;
+    }
+}
+
+static char *
+argv_extract_cmd_name (const char *path)
+{
+  char *ret = NULL;
+  if (path)
+    {
+      char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */
+      const char *bn = basename (path_cp);
+      if (bn)
+        {
+          char *dot = NULL;
+          ret = string_alloc (bn, NULL);
+          dot = strrchr (ret, '.');
+          if (dot)
+            *dot = '\0';
+          free(path_cp);
+          if (ret[0] == '\0')
+            {
+              free(ret);
+              ret = NULL;
+            }
+        }
+    }
+  return ret;
+}
+
+const char *
+argv_system_str (const struct argv *a)
+{
+  return a->system_str;
+}
+
+static struct argv
+argv_clone (const struct argv *a, const size_t headroom)
+{
+  struct argv r;
+  size_t i;
+
+  argv_init (&r);
+  for (i = 0; i < headroom; ++i)
+    argv_append (&r, NULL);
+  if (a)
+    {
+      for (i = 0; i < a->argc; ++i)
+        argv_append (&r, string_alloc (a->argv[i], NULL));
+      r.system_str = string_alloc (a->system_str, NULL);
+    }
+  return r;
+}
+
+struct argv
+argv_insert_head (const struct argv *a, const char *head)
+{
+  struct argv r;
+  char *s;
+
+  r = argv_clone (a, 1);
+  r.argv[0] = string_alloc (head, NULL);
+  s = r.system_str;
+  r.system_str = string_alloc (head, NULL);
+  if (s)
+    {
+      argv_system_str_append (&r, s, false);
+      free (s);
+    }
+  return r;
+}
+
+char *
+argv_term (const char **f)
+{
+  const char *p = *f;
+  const char *term = NULL;
+  size_t termlen = 0;
+
+  if (*p == '\0')
+    return NULL;
+
+  while (true)
+    {
+      const int c = *p;
+      if (c == '\0')
+        break;
+      if (term)
+        {
+          if (!isspace (c))
+            ++termlen;
+          else
+            break;
+        }
+      else
+        {
+          if (!isspace (c))
+            {
+              term = p;
+              termlen = 1;
+            }
+        }
+      ++p;
+    }
+  *f = p;
+
+  if (term)
+    {
+      char *ret;
+      ASSERT (termlen > 0);
+      ret = malloc (termlen + 1);
+      check_malloc_return (ret);
+      memcpy (ret, term, termlen);
+      ret[termlen] = '\0';
+      return ret;
+    }
+  else
+    return NULL;
+}
+
+const char *
+argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
+{
+  if (a->argv)
+    return print_argv ((const char **)a->argv, gc, flags);
+  else
+    return "";
+}
+
+void
+argv_msg (const int msglev, const struct argv *a)
+{
+  struct gc_arena gc = gc_new ();
+  msg (msglev, "%s", argv_str (a, &gc, 0));
+  gc_free (&gc);
+}
+
+void
+argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
+{
+  struct gc_arena gc = gc_new ();
+  msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
+  gc_free (&gc);
+}
+
+void
+argv_printf (struct argv *a, const char *format, ...)
+{
+  va_list arglist;
+  va_start (arglist, format);
+  argv_printf_arglist (a, format, 0, arglist);
+  va_end (arglist);
+ }
+
+void
+argv_printf_cat (struct argv *a, const char *format, ...)
+{
+  va_list arglist;
+  va_start (arglist, format);
+  argv_printf_arglist (a, format, APA_CAT, arglist);
+  va_end (arglist);
+}
+
+void
+argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
+{
+  struct gc_arena gc = gc_new ();
+  char *term;
+  const char *f = format;
+
+  if (!(flags & APA_CAT))
+    argv_reset (a);
+  argv_extend (a, 1); /* ensure trailing NULL */
+
+  while ((term = argv_term (&f)) != NULL)
+    {
+      if (term[0] == '%')
+        {
+          if (!strcmp (term, "%s"))
+            {
+              char *s = va_arg (arglist, char *);
+              if (!s)
+                s = "";
+              argv_append (a, string_alloc (s, NULL));
+              argv_system_str_append (a, s, true);
+            }
+          else if (!strcmp (term, "%sc"))
+            {
+              char *s = va_arg (arglist, char *);
+              if (s)
+                {
+                  int nparms;
+                  char *parms[MAX_PARMS+1];
+                  int i;
+
+                  nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
+                  if (nparms)
+                    {
+                      for (i = 0; i < nparms; ++i)
+                        argv_append (a, string_alloc (parms[i], NULL));
+                    }
+                  else
+                    argv_append (a, string_alloc (s, NULL));
+
+                  argv_system_str_append (a, s, false);
+                }
+              else
+                {
+                  argv_append (a, string_alloc ("", NULL));
+                  argv_system_str_append (a, "echo", false);
+                }
+            }
+          else if (!strcmp (term, "%d"))
+            {
+              char numstr[64];
+              openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
+              argv_append (a, string_alloc (numstr, NULL));
+              argv_system_str_append (a, numstr, false);
+            }
+          else if (!strcmp (term, "%u"))
+            {
+              char numstr[64];
+              openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
+              argv_append (a, string_alloc (numstr, NULL));
+              argv_system_str_append (a, numstr, false);
+            }
+          else if (!strcmp (term, "%s/%d"))
+            {
+              char numstr[64];
+              char *s = va_arg (arglist, char *);
+
+              if (!s)
+                s = "";
+
+              openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
+
+              {
+                const size_t len = strlen(s) + strlen(numstr) + 2;
+                char *combined = (char *) malloc (len);
+                check_malloc_return (combined);
+
+                strcpy (combined, s);
+                strcat (combined, "/");
+                strcat (combined, numstr);
+                argv_append (a, combined);
+                argv_system_str_append (a, combined, false);
+              }
+            }
+          else if (!strcmp (term, "%s%sc"))
+            {
+              char *s1 = va_arg (arglist, char *);
+              char *s2 = va_arg (arglist, char *);
+              char *combined;
+              char *cmd_name;
+
+              if (!s1) s1 = "";
+              if (!s2) s2 = "";
+              combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
+              check_malloc_return (combined);
+              strcpy (combined, s1);
+              strcat (combined, s2);
+              argv_append (a, combined);
+
+              cmd_name = argv_extract_cmd_name (combined);
+              if (cmd_name)
+                {
+                  argv_system_str_append (a, cmd_name, false);
+                  free (cmd_name);
+                }
+            }
+          else
+            ASSERT (0);
+          free (term);
+        }
+      else
+        {
+          argv_append (a, term);
+          argv_system_str_append (a, term, false);
+        }
+    }
+  gc_free (&gc);
+}
diff --git a/src/openvpn/argv.h b/src/openvpn/argv.h
new file mode 100644 (file)
index 0000000..df658a0
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ *  A printf-like function (that only recognizes a subset of standard printf
+ *  format operators) that prints arguments to an argv list instead
+ *  of a standard string.  This is used to build up argv arrays for passing
+ *  to execve.
+ */
+
+#ifndef ARGV_H
+#define ARGV_H
+
+#include "buffer.h"
+
+struct argv {
+  size_t capacity;
+  size_t argc;
+  char **argv;
+  char *system_str;
+};
+
+void argv_init (struct argv *a);
+struct argv argv_new (void);
+void argv_reset (struct argv *a);
+char *argv_term (const char **f);
+const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
+struct argv argv_insert_head (const struct argv *a, const char *head);
+void argv_msg (const int msglev, const struct argv *a);
+void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
+const char *argv_system_str (const struct argv *a);
+
+#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */
+void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist);
+
+void argv_printf (struct argv *a, const char *format, ...)
+#ifdef __GNUC__
+#if __USE_MINGW_ANSI_STDIO
+        __attribute__ ((format (gnu_printf, 2, 3)))
+#else
+        __attribute__ ((format (__printf__, 2, 3)))
+#endif
+#endif
+  ;
+
+void argv_printf_cat (struct argv *a, const char *format, ...)
+#ifdef __GNUC__
+#if __USE_MINGW_ANSI_STDIO
+        __attribute__ ((format (gnu_printf, 2, 3)))
+#else
+        __attribute__ ((format (__printf__, 2, 3)))
+#endif
+#endif
+  ;
+
+#endif
index b06d446b7027a7cb6375e8e3b40261958339db80..3d40f0bfe9affaede4a48fe06275e2c1f1afce28 100644 (file)
@@ -1587,465 +1587,6 @@ adjust_power_of_2 (size_t u)
   return ret;
 }
 
-/*
- * A printf-like function (that only recognizes a subset of standard printf
- * format operators) that prints arguments to an argv list instead
- * of a standard string.  This is used to build up argv arrays for passing
- * to execve.
- */
-
-void
-argv_init (struct argv *a)
-{
-  a->capacity = 0;
-  a->argc = 0;
-  a->argv = NULL;
-  a->system_str = NULL;
-}
-
-struct argv
-argv_new (void)
-{
-  struct argv ret;
-  argv_init (&ret);
-  return ret;
-}
-
-void
-argv_reset (struct argv *a)
-{
-  size_t i;
-  for (i = 0; i < a->argc; ++i)
-    free (a->argv[i]);
-  free (a->argv);
-  free (a->system_str);
-  argv_init (a);
-}
-
-static void
-argv_extend (struct argv *a, const size_t newcap)
-{
-  if (newcap > a->capacity)
-    {
-      char **newargv;
-      size_t i;
-      ALLOC_ARRAY_CLEAR (newargv, char *, newcap);
-      for (i = 0; i < a->argc; ++i)
-       newargv[i] = a->argv[i];
-      free (a->argv);
-      a->argv = newargv;
-      a->capacity = newcap;
-    }
-}
-
-static void
-argv_grow (struct argv *a, const size_t add)
-{
-  const size_t newargc = a->argc + add + 1;
-  ASSERT (newargc > a->argc);
-  argv_extend (a, adjust_power_of_2 (newargc));
-}
-
-static void
-argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */
-{
-  argv_grow (a, 1);
-  a->argv[a->argc++] = str;
-}
-
-static void
-argv_system_str_append (struct argv *a, const char *str, const bool enquote)
-{
-  if (str)
-    {
-      char *newstr;
-
-      /* compute length of new system_str */
-      size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */
-      if (a->system_str)
-       l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */
-      if (enquote)
-       l += 2; /* space for two quotes */
-
-      /* build new system_str */
-      newstr = (char *) malloc (l);
-      newstr[0] = '\0';
-      check_malloc_return (newstr);
-      if (a->system_str)
-       {
-         strcpy (newstr, a->system_str);
-         strcat (newstr, " ");
-       }
-      if (enquote)
-       strcat (newstr, "\"");
-      strcat (newstr, str);
-      if (enquote)
-       strcat (newstr, "\"");
-      free (a->system_str);
-      a->system_str = newstr;
-    }
-}
-
-static char *
-argv_extract_cmd_name (const char *path)
-{
-  char *ret = NULL;
-  if (path)
-    {
-      char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */
-      const char *bn = basename (path_cp);
-      if (bn)
-       {
-         char *dot = NULL;
-         ret = string_alloc (bn, NULL);
-         dot = strrchr (ret, '.');
-         if (dot)
-           *dot = '\0';
-         free(path_cp);
-         if (ret[0] == '\0')
-           {
-             free(ret);
-             ret = NULL;
-           }
-       }
-    }
-  return ret;
-}
-
-const char *
-argv_system_str (const struct argv *a)
-{
-  return a->system_str;
-}
-
-struct argv
-argv_clone (const struct argv *a, const size_t headroom)
-{
-  struct argv r;
-  size_t i;
-
-  argv_init (&r);
-  for (i = 0; i < headroom; ++i)
-    argv_append (&r, NULL);
-  if (a)
-    {
-      for (i = 0; i < a->argc; ++i)
-       argv_append (&r, string_alloc (a->argv[i], NULL));
-      r.system_str = string_alloc (a->system_str, NULL);
-    }
-  return r;
-}
-
-struct argv
-argv_insert_head (const struct argv *a, const char *head)
-{
-  struct argv r;
-  char *s;
-
-  r = argv_clone (a, 1);
-  r.argv[0] = string_alloc (head, NULL);
-  s = r.system_str;
-  r.system_str = string_alloc (head, NULL);
-  if (s)
-    {
-      argv_system_str_append (&r, s, false);
-      free (s);
-    }
-  return r;
-}
-
-char *
-argv_term (const char **f)
-{
-  const char *p = *f;
-  const char *term = NULL;
-  size_t termlen = 0;
-
-  if (*p == '\0')
-    return NULL;
-
-  while (true)
-    {
-      const int c = *p;
-      if (c == '\0')
-       break;
-      if (term)
-       {
-         if (!isspace (c))
-           ++termlen;
-         else
-           break;
-       }
-      else
-       {
-         if (!isspace (c))
-           {
-             term = p;
-             termlen = 1;
-           }
-       }
-      ++p;
-    }
-  *f = p;
-
-  if (term)
-    {
-      char *ret;
-      ASSERT (termlen > 0);
-      ret = malloc (termlen + 1);
-      check_malloc_return (ret);
-      memcpy (ret, term, termlen);
-      ret[termlen] = '\0';
-      return ret;
-    }
-  else
-    return NULL;
-}
-
-const char *
-argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
-{
-  if (a->argv)
-    return print_argv ((const char **)a->argv, gc, flags);
-  else
-    return "";
-}
-
-void
-argv_msg (const int msglev, const struct argv *a)
-{
-  struct gc_arena gc = gc_new ();
-  msg (msglev, "%s", argv_str (a, &gc, 0));
-  gc_free (&gc);
-}
-
-void
-argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
-{
-  struct gc_arena gc = gc_new ();
-  msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
-  gc_free (&gc);
-}
-
-void
-argv_printf (struct argv *a, const char *format, ...)
-{
-  va_list arglist;
-  va_start (arglist, format);
-  argv_printf_arglist (a, format, 0, arglist);
-  va_end (arglist);
- }
-
-void
-argv_printf_cat (struct argv *a, const char *format, ...)
-{
-  va_list arglist;
-  va_start (arglist, format);
-  argv_printf_arglist (a, format, APA_CAT, arglist);
-  va_end (arglist);
-}
-
-void
-argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
-{
-  struct gc_arena gc = gc_new ();
-  char *term;
-  const char *f = format;
-
-  if (!(flags & APA_CAT))
-    argv_reset (a);
-  argv_extend (a, 1); /* ensure trailing NULL */
-
-  while ((term = argv_term (&f)) != NULL) 
-    {
-      if (term[0] == '%')
-       {
-         if (!strcmp (term, "%s"))
-           {
-             char *s = va_arg (arglist, char *);
-             if (!s)
-               s = "";
-             argv_append (a, string_alloc (s, NULL));
-             argv_system_str_append (a, s, true);
-           }
-         else if (!strcmp (term, "%sc"))
-           {
-             char *s = va_arg (arglist, char *);
-             if (s)
-               {
-                 int nparms;
-                 char *parms[MAX_PARMS+1];
-                 int i;
-
-                 nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
-                 if (nparms)
-                   {
-                     for (i = 0; i < nparms; ++i)
-                       argv_append (a, string_alloc (parms[i], NULL));
-                   }
-                 else
-                   argv_append (a, string_alloc (s, NULL));
-
-                 argv_system_str_append (a, s, false);
-               }
-             else
-               {
-                 argv_append (a, string_alloc ("", NULL));
-                 argv_system_str_append (a, "echo", false);
-               }
-           }
-         else if (!strcmp (term, "%d"))
-           {
-             char numstr[64];
-             openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
-             argv_append (a, string_alloc (numstr, NULL));
-             argv_system_str_append (a, numstr, false);
-           }
-         else if (!strcmp (term, "%u"))
-           {
-             char numstr[64];
-             openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
-             argv_append (a, string_alloc (numstr, NULL));
-             argv_system_str_append (a, numstr, false);
-           }
-         else if (!strcmp (term, "%s/%d"))
-           {
-             char numstr[64];
-             char *s = va_arg (arglist, char *);
-
-             if (!s)
-               s = "";
-
-             openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
-
-             {
-               const size_t len = strlen(s) + strlen(numstr) + 2;
-               char *combined = (char *) malloc (len);
-               check_malloc_return (combined);
-
-               strcpy (combined, s);
-               strcat (combined, "/");
-               strcat (combined, numstr);
-               argv_append (a, combined);
-               argv_system_str_append (a, combined, false);
-             }
-           }
-         else if (!strcmp (term, "%s%sc"))
-           {
-             char *s1 = va_arg (arglist, char *);
-             char *s2 = va_arg (arglist, char *);
-             char *combined;
-             char *cmd_name;
-
-             if (!s1) s1 = "";
-             if (!s2) s2 = "";
-             combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
-             check_malloc_return (combined);
-             strcpy (combined, s1);
-             strcat (combined, s2);
-             argv_append (a, combined);
-
-             cmd_name = argv_extract_cmd_name (combined);
-             if (cmd_name)
-               {
-                 argv_system_str_append (a, cmd_name, false);
-                 free (cmd_name);
-               }
-           }
-         else
-           ASSERT (0);
-         free (term);
-       }
-      else
-       {
-         argv_append (a, term);
-         argv_system_str_append (a, term, false);
-       }
-    }
-  gc_free (&gc);
-}
-
-#ifdef ARGV_TEST
-void
-argv_test (void)
-{
-  struct gc_arena gc = gc_new ();
-  const char *s;
-
-  struct argv a;
-
-  argv_init (&a);
-  argv_printf (&a, "%sc foo bar %s", "c:\\\\src\\\\test\\\\jyargs.exe", "foo bar");
-  argv_msg_prefix (M_INFO, &a, "ARGV");
-  msg (M_INFO, "ARGV-S: %s", argv_system_str(&a));
-  /*openvpn_execve_check (&a, NULL, 0, "command failed");*/
-
-  argv_printf (&a, "%sc %s %s", "c:\\\\src\\\\test files\\\\batargs.bat", "foo", "bar");  
-  argv_msg_prefix (M_INFO, &a, "ARGV");
-  msg (M_INFO, "ARGV-S: %s", argv_system_str(&a));
-  /*openvpn_execve_check (&a, NULL, 0, "command failed");*/
-
-  argv_printf (&a, "%s%sc foo bar %s %s/%d %d %u", "/foo", "/bar.exe", "one two", "1.2.3.4", 24, -69, 96);
-  argv_msg_prefix (M_INFO, &a, "ARGV");
-  msg (M_INFO, "ARGV-S: %s", argv_system_str(&a));
-  /*openvpn_execve_check (&a, NULL, 0, "command failed");*/
-
-  argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42);
-  s = argv_str (&a, &gc, PA_BRACKET);
-  printf ("PF: %s\n", s);
-  printf ("PF-S: %s\n", argv_system_str(&a));
-
-  {
-    struct argv b = argv_insert_head (&a, "MARK");
-    s = argv_str (&b, &gc, PA_BRACKET);
-    printf ("PF: %s\n", s);
-    printf ("PF-S: %s\n", argv_system_str(&b));
-    argv_reset (&b);
-  }
-
-  argv_printf (&a, "%sc foo bar %d", "\"multi term\" command      following \\\"spaces", 99);
-  s = argv_str (&a, &gc, PA_BRACKET);
-  printf ("PF: %s\n", s);
-  printf ("PF-S: %s\n", argv_system_str(&a));
-  argv_reset (&a);
-
-  s = argv_str (&a, &gc, PA_BRACKET);
-  printf ("PF: %s\n", s);
-  printf ("PF-S: %s\n", argv_system_str(&a));
-  argv_reset (&a);
-
-  argv_printf (&a, "foo bar %d", 99);
-  argv_printf_cat (&a, "bar %d foo %sc", 42, "nonesuch");
-  argv_printf_cat (&a, "cool %s %d u %s/%d end", "frood", 4, "hello", 7);
-  s = argv_str (&a, &gc, PA_BRACKET);
-  printf ("PF: %s\n", s);
-  printf ("PF-S: %s\n", argv_system_str(&a));
-  argv_reset (&a);
-
-#if 0
-  {
-    char line[512];
-    while (fgets (line, sizeof(line), stdin) != NULL)
-      {
-       char *term;
-       const char *f = line;
-       int i = 0;
-
-       while ((term = argv_term (&f)) != NULL) 
-         {
-           printf ("[%d] '%s'\n", i, term);
-           ++i;
-           free (term);
-         }
-      }
-  }
-#endif
-
-  argv_reset (&a);
-  gc_free (&gc);
-}
-#endif
-
 /*
  * Remove security-sensitive strings from control message
  * so that they will not be output to log file.
index b69409684a8ad128c5e5fb5f829e92b8b3fff90a..ceda3235f620b19bc91a4331f83200eecfad5e14 100644 (file)
@@ -25,6 +25,7 @@
 #ifndef MISC_H
 #define MISC_H
 
+#include "argv.h"
 #include "basic.h"
 #include "common.h"
 #include "integer.h"
 /* forward declarations */
 struct plugin_list;
 
-/* used by argv_x functions */
-struct argv {
-  size_t capacity;
-  size_t argc;
-  char **argv;
-  char *system_str;
-};
-
 /*
  * Handle environmental variable lists
  */
@@ -325,45 +318,6 @@ extern int script_security; /* GLOBAL */
 /* return the next largest power of 2 */
 size_t adjust_power_of_2 (size_t u);
 
-/*
- * A printf-like function (that only recognizes a subset of standard printf
- * format operators) that prints arguments to an argv list instead
- * of a standard string.  This is used to build up argv arrays for passing
- * to execve.
- */
-void argv_init (struct argv *a);
-struct argv argv_new (void);
-void argv_reset (struct argv *a);
-char *argv_term (const char **f);
-const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
-struct argv argv_insert_head (const struct argv *a, const char *head);
-void argv_msg (const int msglev, const struct argv *a);
-void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
-const char *argv_system_str (const struct argv *a);
-
-#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */
-void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist);
-
-void argv_printf (struct argv *a, const char *format, ...)
-#ifdef __GNUC__
-#if __USE_MINGW_ANSI_STDIO
-       __attribute__ ((format (gnu_printf, 2, 3)))
-#else
-       __attribute__ ((format (__printf__, 2, 3)))
-#endif
-#endif
-  ;
-
-void argv_printf_cat (struct argv *a, const char *format, ...)
-#ifdef __GNUC__
-#if __USE_MINGW_ANSI_STDIO
-       __attribute__ ((format (gnu_printf, 2, 3)))
-#else
-       __attribute__ ((format (__printf__, 2, 3)))
-#endif
-#endif
-  ;
-
 #define COMPAT_FLAG_QUERY         0       /** compat_flags operator: Query for a flag */
 #define COMPAT_FLAG_SET           (1<<0)  /** compat_flags operator: Set a compat flag */
 #define COMPAT_NAMES              (1<<1)  /** compat flag: --compat-names set */
index 8868c1cb4f670d82f39a16f0ea2772b612993913..44ab26bd82dfd2bf667ae407dcce5bf8bab22e8b 100644 (file)
@@ -1,5 +1,5 @@
 AUTOMAKE_OPTIONS = foreign
 
 if CMOCKA_INITIALIZED
-SUBDIRS = example_test plugins
+SUBDIRS = example_test plugins openvpn
 endif
diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am
new file mode 100644 (file)
index 0000000..af7f12f
--- /dev/null
@@ -0,0 +1,15 @@
+AUTOMAKE_OPTIONS = foreign
+
+check_PROGRAMS = argv_testdriver
+
+TESTS = $(check_PROGRAMS)
+
+openvpn_srcdir = $(top_srcdir)/src/openvpn
+compat_srcdir = $(top_srcdir)/src/compat
+
+argv_testdriver_CFLAGS  = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir)
+argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line
+argv_testdriver_SOURCES = test_argv.c \
+       $(openvpn_srcdir)/platform.c \
+       $(openvpn_srcdir)/buffer.c \
+       $(openvpn_srcdir)/argv.c
diff --git a/tests/unit_tests/openvpn/test_argv.c b/tests/unit_tests/openvpn/test_argv.c
new file mode 100644 (file)
index 0000000..f07a5fb
--- /dev/null
@@ -0,0 +1,194 @@
+#include "config.h"
+#include "syshead.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <assert.h>
+
+#include "argv.h"
+#include "buffer.h"
+
+/*
+ * Dummy symbols that need to be defined due to them being
+ * referenced in #include'd header files and their includes
+ */
+unsigned int x_debug_level;
+bool dont_mute (unsigned int flags) { return true; }
+void assert_failed (const char *filename, int line, const char *condition) { exit(0); }
+void out_of_memory (void) { }
+void x_msg (const unsigned int flags, const char *format, ...) { }
+
+/*
+ * This is defined here to prevent #include'ing misc.h
+ * which makes things difficult beyond any recognition
+ */
+size_t
+adjust_power_of_2 (size_t u)
+{
+  size_t ret = 1;
+
+  while (ret < u)
+    {
+      ret <<= 1;
+      assert (ret > 0);
+    }
+
+  return ret;
+}
+
+/* Defines for use in the tests and the mock parse_line() */
+#define PATH1       "/s p a c e"
+#define PATH2       "/foo bar/baz"
+#define PARAM1      "param1"
+#define PARAM2      "param two"
+#define SCRIPT_CMD  "\"" PATH1 PATH2 "\"" PARAM1 "\"" PARAM2 "\""
+
+int
+__wrap_parse_line (const char *line, char **p, const int n, const char *file,
+                   const int line_num, int msglevel, struct gc_arena *gc)
+{
+  p[0] = PATH1 PATH2;
+  p[1] = PARAM1;
+  p[2] = PARAM2;
+  return 3;
+}
+
+static void
+argv_printf__multiple_spaces_in_format__parsed_as_one (void **state)
+{
+  struct argv a = argv_new ();
+
+  argv_printf (&a, "    %s     %s  %d   ", PATH1, PATH2, 42);
+  assert_int_equal (a.argc, 3);
+
+  argv_reset (&a);
+}
+
+static void
+argv_printf_cat__multiple_spaces_in_format__parsed_as_one (void **state)
+{
+  struct argv a = argv_new ();
+
+  argv_printf (&a, "%s ", PATH1);
+  argv_printf_cat (&a, " %s  %s", PATH2, PARAM1);
+  assert_int_equal (a.argc, 3);
+
+  argv_reset (&a);
+}
+
+static void
+argv_printf__combined_path_with_spaces__argc_correct (void **state)
+{
+  struct argv a = argv_new ();
+
+  argv_printf (&a, "%s%sc", PATH1, PATH2);
+  assert_int_equal (a.argc, 1);
+
+  argv_printf (&a, "%s%sc %d", PATH1, PATH2, 42);
+  assert_int_equal (a.argc, 2);
+
+  argv_printf (&a, "foo %s%sc %s x y", PATH2, PATH1, "foo");
+  assert_int_equal (a.argc, 5);
+
+  argv_reset (&a);
+}
+
+static void
+argv_printf__script_command__argc_correct (void **state)
+{
+  struct argv a = argv_new ();
+
+  argv_printf (&a, "%sc", SCRIPT_CMD);
+  assert_int_equal (a.argc, 3);
+
+  argv_printf (&a, "bar baz %sc %d %s", SCRIPT_CMD, 42, PATH1);
+  assert_int_equal (a.argc, 7);
+
+  argv_reset (&a);
+}
+
+static void
+argv_printf_cat__used_twice__argc_correct (void **state)
+{
+  struct argv a = argv_new ();
+
+  argv_printf (&a, "%s %s %s", PATH1, PATH2, PARAM1);
+  argv_printf_cat (&a, "%s", PARAM2);
+  argv_printf_cat (&a, "foo");
+  assert_int_equal (a.argc, 5);
+
+  argv_reset (&a);
+}
+
+static void
+argv_str__multiple_argv__correct_output (void **state)
+{
+  struct argv a = argv_new ();
+  struct gc_arena gc = gc_new ();
+  const char *output;
+
+  argv_printf (&a, "%s%sc", PATH1, PATH2);
+  argv_printf_cat (&a, "%s", PARAM1);
+  argv_printf_cat (&a, "%s", PARAM2);
+  output = argv_str (&a, &gc, PA_BRACKET);
+  assert_string_equal (output, "[" PATH1 PATH2 "] [" PARAM1 "] [" PARAM2 "]");
+
+  argv_reset (&a);
+  gc_free (&gc);
+}
+
+static void
+argv_insert_head__empty_argv__head_only (void **state)
+{
+  struct argv a = argv_new ();
+  struct argv b;
+
+  b = argv_insert_head (&a, PATH1);
+  assert_int_equal (b.argc, 1);
+  assert_string_equal (b.argv[0], PATH1);
+  argv_reset (&b);
+
+  argv_reset (&a);
+}
+
+static void
+argv_insert_head__non_empty_argv__head_added (void **state)
+{
+  struct argv a = argv_new ();
+  struct argv b;
+  int i;
+
+  argv_printf (&a, "%s", PATH2);
+  b = argv_insert_head (&a, PATH1);
+  assert_int_equal (b.argc, a.argc + 1);
+  for (i = 0; i < b.argc; i++) {
+    if (i == 0)
+      assert_string_equal (b.argv[i], PATH1);
+    else
+      assert_string_equal (b.argv[i], a.argv[i - 1]);
+  }
+  argv_reset (&b);
+
+  argv_reset (&a);
+}
+
+int
+main(void)
+{
+  const struct CMUnitTest tests[] = {
+    cmocka_unit_test (argv_printf__multiple_spaces_in_format__parsed_as_one),
+    cmocka_unit_test (argv_printf_cat__multiple_spaces_in_format__parsed_as_one),
+    cmocka_unit_test (argv_printf__combined_path_with_spaces__argc_correct),
+    cmocka_unit_test (argv_printf__script_command__argc_correct),
+    cmocka_unit_test (argv_printf_cat__used_twice__argc_correct),
+    cmocka_unit_test (argv_str__multiple_argv__correct_output),
+    cmocka_unit_test (argv_insert_head__non_empty_argv__head_added),
+  };
+
+  return cmocka_run_group_tests_name ("argv", tests, NULL, NULL);
+}