Browse code

Add a test for auth-pam searchandreplace

No functional changes.

Utility functions of auth-pam are split into a dedicated file. This allows
the test programs to easily test these functions without adding
dependencies.

Add a minimal test for searchandreplace as a proof of concept.

[ Modified during commit: Enhanced documentation of functions in utils.h
to comply with doxygen standards ]

Signed-off-by: Jens Neuhalfen <jens@neuhalfen.name>
Acked-by: Steffan Karger <steffan@karger.me>
Message-Id: <20160525175756.56186-3-openvpn-devel@neuhalfen.name>
URL: http://article.gmane.org/gmane.network.openvpn.devel/11724
Signed-off-by: David Sommerseth <dazo@privateinternetaccess.com>

Jens Neuhalfen authored on 2016/05/26 02:57:56
Showing 9 changed files
... ...
@@ -1230,6 +1230,8 @@ AC_CONFIG_FILES([
1230 1230
 	src/plugins/down-root/Makefile
1231 1231
 	tests/Makefile
1232 1232
         tests/unit_tests/Makefile
1233
+        tests/unit_tests/plugins/Makefile
1234
+        tests/unit_tests/plugins/auth-pam/Makefile
1233 1235
         tests/unit_tests/example_test/Makefile
1234 1236
         vendor/Makefile
1235 1237
 	sample/Makefile
... ...
@@ -18,6 +18,7 @@ dist_doc_DATA = README.auth-pam
18 18
 endif
19 19
 
20 20
 openvpn_plugin_auth_pam_la_SOURCES = \
21
+	utils.c \
21 22
 	auth-pam.c \
22 23
 	pamdl.c  pamdl.h \
23 24
 	auth-pam.exports
... ...
@@ -39,7 +39,6 @@
39 39
 #include <stdio.h>
40 40
 #include <string.h>
41 41
 #include <ctype.h>
42
-#include <stdbool.h>
43 42
 #include <unistd.h>
44 43
 #include <stdlib.h>
45 44
 #include <sys/types.h>
... ...
@@ -48,7 +47,7 @@
48 48
 #include <fcntl.h>
49 49
 #include <signal.h>
50 50
 #include <syslog.h>
51
-#include <stdint.h>
51
+#include "utils.h"
52 52
 
53 53
 #include <openvpn-plugin.h>
54 54
 
... ...
@@ -117,94 +116,6 @@ struct user_pass {
117 117
 /* Background process function */
118 118
 static void pam_server (int fd, const char *service, int verb, const struct name_value_list *name_value_list);
119 119
 
120
-/*  Read 'tosearch', replace all occurences of 'searchfor' with 'replacewith' and return
121
- *  a pointer to the NEW string.  Does not modify the input strings.  Will not enter an
122
- *  infinite loop with clever 'searchfor' and 'replacewith' strings.
123
- *  Daniel Johnson - Progman2000@usa.net / djohnson@progman.us
124
- *
125
- *  Retuns NULL when
126
- *   - any parameter is NULL
127
- *   - the worst-case result is to large ( >= SIZE_MAX)
128
- */
129
-static char *
130
-searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith)
131
-{
132
-  if (!tosearch || !searchfor || !replacewith) return NULL;
133
-
134
-  size_t tosearchlen = strlen(tosearch);
135
-  size_t replacewithlen = strlen(replacewith);
136
-  size_t templen = tosearchlen * replacewithlen;
137
-
138
-  if (tosearchlen == 0 || strlen(searchfor) == 0 || replacewithlen == 0) {
139
-    return NULL;
140
-  }
141
-
142
-  bool is_potential_integer_overflow =  (templen == SIZE_MAX) || (templen / tosearchlen != replacewithlen);
143
-
144
-  if (is_potential_integer_overflow) {
145
-       return NULL;
146
-  }
147
-
148
-  // state: all parameters are valid
149
-
150
-  const char *searching=tosearch;
151
-  char *scratch;
152
-
153
-  char temp[templen+1];
154
-  temp[0]=0;
155
-
156
-  scratch = strstr(searching,searchfor);
157
-  if (!scratch) return strdup(tosearch);
158
-
159
-  while (scratch) {
160
-    strncat(temp,searching,scratch-searching);
161
-    strcat(temp,replacewith);
162
-
163
-    searching=scratch+strlen(searchfor);
164
-    scratch = strstr(searching,searchfor);
165
-  }
166
-  return strdup(temp);
167
-}
168
-
169
-/*
170
- * Given an environmental variable name, search
171
- * the envp array for its value, returning it
172
- * if found or NULL otherwise.
173
- */
174
-static const char *
175
-get_env (const char *name, const char *envp[])
176
-{
177
-  if (envp)
178
-    {
179
-      int i;
180
-      const int namelen = strlen (name);
181
-      for (i = 0; envp[i]; ++i)
182
-	{
183
-	  if (!strncmp (envp[i], name, namelen))
184
-	    {
185
-	      const char *cp = envp[i] + namelen;
186
-	      if (*cp == '=')
187
-		return cp + 1;
188
-	    }
189
-	}
190
-    }
191
-  return NULL;
192
-}
193
-
194
-/*
195
- * Return the length of a string array
196
- */
197
-static int
198
-string_array_len (const char *array[])
199
-{
200
-  int i = 0;
201
-  if (array)
202
-    {
203
-      while (array[i])
204
-	++i;
205
-    }
206
-  return i;
207
-}
208 120
 
209 121
 /*
210 122
  * Socket read/write functions.
211 123
new file mode 100644
... ...
@@ -0,0 +1,113 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
3
+ *             session authentication and key exchange,
4
+ *             packet encryption, packet authentication, and
5
+ *             packet compression.
6
+ *
7
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+/*
25
+ * OpenVPN plugin module to do PAM authentication using a split
26
+ * privilege model.
27
+ */
28
+#ifdef HAVE_CONFIG_H
29
+#include <config.h>
30
+#endif
31
+
32
+
33
+#include <string.h>
34
+#include <ctype.h>
35
+#include <stdbool.h>
36
+#include <stdlib.h>
37
+#include <sys/types.h>
38
+#include <stdint.h>
39
+
40
+#include "utils.h"
41
+
42
+char *
43
+searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith)
44
+{
45
+  if (!tosearch || !searchfor || !replacewith) return NULL;
46
+
47
+  size_t tosearchlen = strlen(tosearch);
48
+  size_t replacewithlen = strlen(replacewith);
49
+  size_t templen = tosearchlen * replacewithlen;
50
+
51
+  if (tosearchlen == 0 || strlen(searchfor) == 0 || replacewithlen == 0) {
52
+    return NULL;
53
+  }
54
+
55
+  bool is_potential_integer_overflow =  (templen == SIZE_MAX) || (templen / tosearchlen != replacewithlen);
56
+
57
+  if (is_potential_integer_overflow) {
58
+       return NULL;
59
+  }
60
+
61
+  // state: all parameters are valid
62
+
63
+  const char *searching=tosearch;
64
+  char *scratch;
65
+
66
+  char temp[templen+1];
67
+  temp[0]=0;
68
+
69
+  scratch = strstr(searching,searchfor);
70
+  if (!scratch) return strdup(tosearch);
71
+
72
+  while (scratch) {
73
+    strncat(temp,searching,scratch-searching);
74
+    strcat(temp,replacewith);
75
+
76
+    searching=scratch+strlen(searchfor);
77
+    scratch = strstr(searching,searchfor);
78
+  }
79
+  return strdup(temp);
80
+}
81
+
82
+const char *
83
+get_env (const char *name, const char *envp[])
84
+{
85
+  if (envp)
86
+    {
87
+      int i;
88
+      const int namelen = strlen (name);
89
+      for (i = 0; envp[i]; ++i)
90
+	{
91
+	  if (!strncmp (envp[i], name, namelen))
92
+	    {
93
+	      const char *cp = envp[i] + namelen;
94
+	      if (*cp == '=')
95
+		return cp + 1;
96
+	    }
97
+	}
98
+    }
99
+  return NULL;
100
+}
101
+
102
+int
103
+string_array_len (const char *array[])
104
+{
105
+  int i = 0;
106
+  if (array)
107
+    {
108
+      while (array[i])
109
+	++i;
110
+    }
111
+  return i;
112
+}
0 113
new file mode 100644
... ...
@@ -0,0 +1,66 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
3
+ *             session authentication and key exchange,
4
+ *             packet encryption, packet authentication, and
5
+ *             packet compression.
6
+ *
7
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+#ifndef _PLUGIN_AUTH_PAM_UTILS__H
25
+#define _PLUGIN_AUTH_PAM_UTILS__H
26
+
27
+/**
28
+ *  Read 'tosearch', replace all occurences of 'searchfor' with 'replacewith' and return
29
+ *  a pointer to the NEW string.  Does not modify the input strings.  Will not enter an
30
+ *  infinite loop with clever 'searchfor' and 'replacewith' strings.
31
+ *
32
+ *  @author Daniel Johnson - Progman2000@usa.net / djohnson@progman.us
33
+ *
34
+ *  @param tosearch      haystack to search in
35
+ *  @param searchfor     needle to search for in the haystack
36
+ *  @param replacewith   when a match is found, replace needle with this string
37
+ *
38
+ *  @return Retuns NULL when any parameter is NULL or the worst-case result is to large ( >= SIZE_MAX).
39
+ *          Otherwise it returns a pointer to a new buffer containing the modified input
40
+ */
41
+char *
42
+searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith);
43
+
44
+/**
45
+ * Given an environmental variable name, search
46
+ * the envp array for its value
47
+ *
48
+ * @param name  Environment variable to look up
49
+ * @param envp  Environment variable table with all key/value pairs
50
+ *
51
+ * @return Returns a pointer to the value of the enviroment variable if found, otherwise NULL is returned.
52
+ */
53
+const char *
54
+get_env (const char *name, const char *envp[]);
55
+
56
+/**
57
+ * Return the length of a string array
58
+ *
59
+ * @param array   Pointer to the array to calculate size of
60
+ *
61
+ */
62
+int
63
+string_array_len (const char *array[]);
64
+
65
+#endif
... ...
@@ -1,3 +1,3 @@
1 1
 AUTOMAKE_OPTIONS = foreign
2 2
 
3
-SUBDIRS = example_test
3
+SUBDIRS = example_test plugins
4 4
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+AUTOMAKE_OPTIONS = foreign
1
+
2
+SUBDIRS = auth-pam
0 3
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+AUTOMAKE_OPTIONS = foreign
1
+
2
+if ENABLE_PLUGIN_AUTH_PAM
3
+check_PROGRAMS = auth_pam_testdriver
4
+TESTS = $(check_PROGRAMS)
5
+endif
6
+
7
+sut_sourcedir = $(top_srcdir)/src/plugins/auth-pam
8
+
9
+auth_pam_testdriver_SOURCES = test_search_and_replace.c  $(sut_sourcedir)/utils.h $(sut_sourcedir)/utils.c
10
+auth_pam_testdriver_CFLAGS  = @TEST_CFLAGS@ -I$(sut_sourcedir)
11
+auth_pam_testdriver_LDFLAGS = @TEST_LDFLAGS@
0 12
new file mode 100644
... ...
@@ -0,0 +1,78 @@
0
+#include <stdio.h>
1
+#include <unistd.h>
2
+#include <stdlib.h>
3
+#include <stdarg.h>
4
+#include <string.h>
5
+#include <setjmp.h>
6
+#include <cmocka.h>
7
+
8
+#include "utils.h"
9
+
10
+static void pass_any_null_param__returns_null() {
11
+
12
+  char DUMMY[] = "DUMMY";
13
+
14
+  assert_null(searchandreplace(NULL,DUMMY,DUMMY));
15
+  assert_null(searchandreplace(DUMMY,NULL,DUMMY));
16
+  assert_null(searchandreplace(DUMMY,DUMMY,NULL));
17
+}
18
+
19
+static void pass_any_empty_string__returns_null() {
20
+
21
+  char DUMMY[] = "DUMMY";
22
+  char EMPTY[] = "";
23
+
24
+  assert_null(searchandreplace(EMPTY,DUMMY,DUMMY));
25
+  assert_null(searchandreplace(DUMMY,EMPTY,DUMMY));
26
+  assert_null(searchandreplace(DUMMY,DUMMY,EMPTY));
27
+}
28
+
29
+static void replace_single_char__one_time__match_is_replaced() {
30
+  char *replaced = searchandreplace("X","X","Y");
31
+
32
+  assert_non_null(replaced);
33
+  assert_string_equal("Y", replaced);
34
+
35
+  free(replaced);
36
+}
37
+
38
+static void replace_single_char__multiple_times__match_all_matches_are_replaced() {
39
+  char *replaced = searchandreplace("XaX","X","Y");
40
+
41
+  assert_non_null(replaced);
42
+  assert_string_equal ("YaY", replaced);
43
+
44
+  free(replaced);
45
+}
46
+
47
+static void replace_longer_text__multiple_times__match_all_matches_are_replaced() {
48
+  char *replaced = searchandreplace("XXaXX","XX","YY");
49
+
50
+  assert_non_null(replaced);
51
+  assert_string_equal ("YYaYY", replaced);
52
+
53
+  free(replaced);
54
+}
55
+
56
+static void pattern_not_found__returns_original() {
57
+  char *replaced = searchandreplace("abc","X","Y");
58
+
59
+  assert_non_null(replaced);
60
+  assert_string_equal ("abc", replaced);
61
+
62
+  free(replaced);
63
+}
64
+
65
+
66
+int main(void) {
67
+    const struct CMUnitTest tests[] = {
68
+        cmocka_unit_test(pass_any_null_param__returns_null),
69
+        cmocka_unit_test(pass_any_empty_string__returns_null),
70
+        cmocka_unit_test(replace_single_char__one_time__match_is_replaced),
71
+        cmocka_unit_test(replace_single_char__multiple_times__match_all_matches_are_replaced),
72
+        cmocka_unit_test(replace_longer_text__multiple_times__match_all_matches_are_replaced),
73
+        cmocka_unit_test(pattern_not_found__returns_original),
74
+    };
75
+
76
+    return cmocka_run_group_tests_name("searchandreplace", tests, NULL, NULL);
77
+}