Browse code

Move execve/run_script helper functions to run_command.c

To avoid having to include misc.c - which is a dependency mess - in the
tls-crypt unit tests, move the command execution helper functions to a new
run_command.c module.

While at it, abstract away the script_security global variable.

Signed-off-by: Steffan Karger <steffan.karger@fox-it.com>
Acked-by: Antonio Quartulli <antonio@openvpn.net>
Message-Id: <20180704175404.22371-2-steffan@karger.me>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg17212.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Steffan Karger authored on 2018/07/05 02:53:57
Showing 15 changed files
... ...
@@ -102,6 +102,7 @@ openvpn_SOURCES = \
102 102
 	pushlist.h \
103 103
 	reliable.c reliable.h \
104 104
 	route.c route.h \
105
+	run_command.c run_command.h \
105 106
 	schedule.c schedule.h \
106 107
 	session_id.c session_id.h \
107 108
 	shaper.c shaper.h \
... ...
@@ -32,10 +32,10 @@
32 32
 
33 33
 #include "syshead.h"
34 34
 
35
-#include "misc.h"
36
-
37 35
 #include "env_set.h"
38 36
 
37
+#include "run_command.h"
38
+
39 39
 /*
40 40
  * Set environmental variable (int or string).
41 41
  *
... ...
@@ -414,7 +414,7 @@ setenv_str_i(struct env_set *es, const char *name, const char *value, const int
414 414
 bool
415 415
 env_allowed(const char *str)
416 416
 {
417
-    return (script_security >= SSEC_PW_ENV || !is_password_env_var(str));
417
+    return (script_security() >= SSEC_PW_ENV || !is_password_env_var(str));
418 418
 }
419 419
 
420 420
 /* Make arrays of strings */
... ...
@@ -35,6 +35,7 @@
35 35
 
36 36
 #include "win32.h"
37 37
 #include "init.h"
38
+#include "run_command.h"
38 39
 #include "sig.h"
39 40
 #include "occ.h"
40 41
 #include "list.h"
... ...
@@ -3095,11 +3096,11 @@ do_option_warnings(struct context *c)
3095 3095
     /* If a script is used, print appropiate warnings */
3096 3096
     if (o->user_script_used)
3097 3097
     {
3098
-        if (script_security >= SSEC_SCRIPTS)
3098
+        if (script_security() >= SSEC_SCRIPTS)
3099 3099
         {
3100 3100
             msg(M_WARN, "NOTE: the current --script-security setting may allow this configuration to call user-defined scripts");
3101 3101
         }
3102
-        else if (script_security >= SSEC_PW_ENV)
3102
+        else if (script_security() >= SSEC_PW_ENV)
3103 3103
         {
3104 3104
             msg(M_WARN, "WARNING: the current --script-security setting may allow passwords to be passed to scripts via environmental variables");
3105 3105
         }
... ...
@@ -11,6 +11,7 @@
11 11
 #include "syshead.h"
12 12
 #include "error.h"
13 13
 #include "misc.h"
14
+#include "run_command.h"
14 15
 
15 16
 int
16 17
 set_lladdr(const char *ifname, const char *lladdr,
... ...
@@ -51,9 +51,6 @@
51 51
 const char *iproute_path = IPROUTE_PATH; /* GLOBAL */
52 52
 #endif
53 53
 
54
-/* contains an SSEC_x value defined in misc.h */
55
-int script_security = SSEC_BUILT_IN; /* GLOBAL */
56
-
57 54
 /*
58 55
  * Set standard file descriptors to /dev/null
59 56
  */
... ...
@@ -99,221 +96,6 @@ save_inetd_socket_descriptor(void)
99 99
 }
100 100
 
101 101
 /*
102
- * Print an error message based on the status code returned by system().
103
- */
104
-const char *
105
-system_error_message(int stat, struct gc_arena *gc)
106
-{
107
-    struct buffer out = alloc_buf_gc(256, gc);
108
-#ifdef _WIN32
109
-    if (stat == -1)
110
-    {
111
-        buf_printf(&out, "external program did not execute -- ");
112
-    }
113
-    buf_printf(&out, "returned error code %d", stat);
114
-#else  /* ifdef _WIN32 */
115
-    if (stat == -1)
116
-    {
117
-        buf_printf(&out, "external program fork failed");
118
-    }
119
-    else if (!WIFEXITED(stat))
120
-    {
121
-        buf_printf(&out, "external program did not exit normally");
122
-    }
123
-    else
124
-    {
125
-        const int cmd_ret = WEXITSTATUS(stat);
126
-        if (!cmd_ret)
127
-        {
128
-            buf_printf(&out, "external program exited normally");
129
-        }
130
-        else if (cmd_ret == 127)
131
-        {
132
-            buf_printf(&out, "could not execute external program");
133
-        }
134
-        else
135
-        {
136
-            buf_printf(&out, "external program exited with error status: %d", cmd_ret);
137
-        }
138
-    }
139
-#endif /* ifdef _WIN32 */
140
-    return (const char *)out.data;
141
-}
142
-
143
-/*
144
- * Wrapper around openvpn_execve
145
- */
146
-bool
147
-openvpn_execve_check(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message)
148
-{
149
-    struct gc_arena gc = gc_new();
150
-    const int stat = openvpn_execve(a, es, flags);
151
-    int ret = false;
152
-
153
-    if (platform_system_ok(stat))
154
-    {
155
-        ret = true;
156
-    }
157
-    else
158
-    {
159
-        if (error_message)
160
-        {
161
-            msg(((flags & S_FATAL) ? M_FATAL : M_WARN), "%s: %s",
162
-                error_message,
163
-                system_error_message(stat, &gc));
164
-        }
165
-    }
166
-    gc_free(&gc);
167
-    return ret;
168
-}
169
-
170
-bool
171
-openvpn_execve_allowed(const unsigned int flags)
172
-{
173
-    if (flags & S_SCRIPT)
174
-    {
175
-        return script_security >= SSEC_SCRIPTS;
176
-    }
177
-    else
178
-    {
179
-        return script_security >= SSEC_BUILT_IN;
180
-    }
181
-}
182
-
183
-
184
-#ifndef _WIN32
185
-/*
186
- * Run execve() inside a fork().  Designed to replicate the semantics of system() but
187
- * in a safer way that doesn't require the invocation of a shell or the risks
188
- * assocated with formatting and parsing a command line.
189
- */
190
-int
191
-openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags)
192
-{
193
-    struct gc_arena gc = gc_new();
194
-    int ret = -1;
195
-    static bool warn_shown = false;
196
-
197
-    if (a && a->argv[0])
198
-    {
199
-#if defined(ENABLE_FEATURE_EXECVE)
200
-        if (openvpn_execve_allowed(flags))
201
-        {
202
-            const char *cmd = a->argv[0];
203
-            char *const *argv = a->argv;
204
-            char *const *envp = (char *const *)make_env_array(es, true, &gc);
205
-            pid_t pid;
206
-
207
-            pid = fork();
208
-            if (pid == (pid_t)0) /* child side */
209
-            {
210
-                execve(cmd, argv, envp);
211
-                exit(127);
212
-            }
213
-            else if (pid < (pid_t)0) /* fork failed */
214
-            {
215
-                msg(M_ERR, "openvpn_execve: unable to fork");
216
-            }
217
-            else /* parent side */
218
-            {
219
-                if (waitpid(pid, &ret, 0) != pid)
220
-                {
221
-                    ret = -1;
222
-                }
223
-            }
224
-        }
225
-        else if (!warn_shown && (script_security < SSEC_SCRIPTS))
226
-        {
227
-            msg(M_WARN, SCRIPT_SECURITY_WARNING);
228
-            warn_shown = true;
229
-        }
230
-#else  /* if defined(ENABLE_FEATURE_EXECVE) */
231
-        msg(M_WARN, "openvpn_execve: execve function not available");
232
-#endif /* if defined(ENABLE_FEATURE_EXECVE) */
233
-    }
234
-    else
235
-    {
236
-        msg(M_FATAL, "openvpn_execve: called with empty argv");
237
-    }
238
-
239
-    gc_free(&gc);
240
-    return ret;
241
-}
242
-#endif /* ifndef _WIN32 */
243
-
244
-/*
245
- * Run execve() inside a fork(), duping stdout.  Designed to replicate the semantics of popen() but
246
- * in a safer way that doesn't require the invocation of a shell or the risks
247
- * assocated with formatting and parsing a command line.
248
- */
249
-int
250
-openvpn_popen(const struct argv *a,  const struct env_set *es)
251
-{
252
-    struct gc_arena gc = gc_new();
253
-    int ret = -1;
254
-    static bool warn_shown = false;
255
-
256
-    if (a && a->argv[0])
257
-    {
258
-#if defined(ENABLE_FEATURE_EXECVE)
259
-        if (script_security >= SSEC_BUILT_IN)
260
-        {
261
-            const char *cmd = a->argv[0];
262
-            char *const *argv = a->argv;
263
-            char *const *envp = (char *const *)make_env_array(es, true, &gc);
264
-            pid_t pid;
265
-            int pipe_stdout[2];
266
-
267
-            if (pipe(pipe_stdout) == 0)
268
-            {
269
-                pid = fork();
270
-                if (pid == (pid_t)0)       /* child side */
271
-                {
272
-                    close(pipe_stdout[0]);         /* Close read end */
273
-                    dup2(pipe_stdout[1],1);
274
-                    execve(cmd, argv, envp);
275
-                    exit(127);
276
-                }
277
-                else if (pid > (pid_t)0)       /* parent side */
278
-                {
279
-                    int status = 0;
280
-
281
-                    close(pipe_stdout[1]);        /* Close write end */
282
-                    waitpid(pid, &status, 0);
283
-                    ret = pipe_stdout[0];
284
-                }
285
-                else       /* fork failed */
286
-                {
287
-                    close(pipe_stdout[0]);
288
-                    close(pipe_stdout[1]);
289
-                    msg(M_ERR, "openvpn_popen: unable to fork %s", cmd);
290
-                }
291
-            }
292
-            else
293
-            {
294
-                msg(M_WARN, "openvpn_popen: unable to create stdout pipe for %s", cmd);
295
-                ret = -1;
296
-            }
297
-        }
298
-        else if (!warn_shown && (script_security < SSEC_SCRIPTS))
299
-        {
300
-            msg(M_WARN, SCRIPT_SECURITY_WARNING);
301
-            warn_shown = true;
302
-        }
303
-#else  /* if defined(ENABLE_FEATURE_EXECVE) */
304
-        msg(M_WARN, "openvpn_popen: execve function not available");
305
-#endif /* if defined(ENABLE_FEATURE_EXECVE) */
306
-    }
307
-    else
308
-    {
309
-        msg(M_FATAL, "openvpn_popen: called with empty argv");
310
-    }
311
-
312
-    gc_free(&gc);
313
-    return ret;
314
-}
315
-
316
-/*
317 102
  * Prepend a random string to hostname to prevent DNS caching.
318 103
  * For example, foo.bar.gov would be modified to <random-chars>.foo.bar.gov.
319 104
  * Of course, this requires explicit support in the DNS server (wildcard).
... ...
@@ -38,30 +38,6 @@
38 38
 /* forward declarations */
39 39
 struct plugin_list;
40 40
 
41
-/* system flags */
42
-#define S_SCRIPT (1<<0)
43
-#define S_FATAL  (1<<1)
44
-
45
-const char *system_error_message(int, struct gc_arena *gc);
46
-
47
-/* wrapper around the execve() call */
48
-int openvpn_popen(const struct argv *a,  const struct env_set *es);
49
-
50
-int openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags);
51
-
52
-bool openvpn_execve_check(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message);
53
-
54
-bool openvpn_execve_allowed(const unsigned int flags);
55
-
56
-static inline bool
57
-openvpn_run_script(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *hook)
58
-{
59
-    char msg[256];
60
-
61
-    openvpn_snprintf(msg, sizeof(msg), "WARNING: Failed running command (%s)", hook);
62
-    return openvpn_execve_check(a, es, flags | S_SCRIPT, msg);
63
-}
64
-
65 41
 
66 42
 /* Set standard file descriptors to /dev/null */
67 43
 void set_std_files_to_null(bool stdin_only);
... ...
@@ -198,14 +174,6 @@ void get_user_pass_auto_userid(struct user_pass *up, const char *tag);
198 198
 extern const char *iproute_path;
199 199
 #endif
200 200
 
201
-/* Script security */
202
-#define SSEC_NONE      0 /* strictly no calling of external programs */
203
-#define SSEC_BUILT_IN  1 /* only call built-in programs such as ifconfig, route, netsh, etc.*/
204
-#define SSEC_SCRIPTS   2 /* allow calling of built-in programs and user-defined scripts */
205
-#define SSEC_PW_ENV    3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */
206
-extern int script_security; /* GLOBAL */
207
-
208
-
209 201
 #define COMPAT_FLAG_QUERY         0       /** compat_flags operator: Query for a flag */
210 202
 #define COMPAT_FLAG_SET           (1<<0)  /** compat_flags operator: Set a compat flag */
211 203
 #define COMPAT_NAMES              (1<<1)  /** compat flag: --compat-names set */
... ...
@@ -38,7 +38,7 @@
38 38
 
39 39
 #include "multi.h"
40 40
 #include "push.h"
41
-#include "misc.h"
41
+#include "run_command.h"
42 42
 #include "otime.h"
43 43
 #include "gremlin.h"
44 44
 #include "mstats.h"
... ...
@@ -41,6 +41,7 @@
41 41
 #include "buffer.h"
42 42
 #include "error.h"
43 43
 #include "common.h"
44
+#include "run_command.h"
44 45
 #include "shaper.h"
45 46
 #include "crypto.h"
46 47
 #include "ssl.h"
... ...
@@ -6379,7 +6380,7 @@ add_option(struct options *options,
6379 6379
     else if (streq(p[0], "script-security") && p[1] && !p[2])
6380 6380
     {
6381 6381
         VERIFY_PERMISSION(OPT_P_GENERAL);
6382
-        script_security = atoi(p[1]);
6382
+        script_security_set(atoi(p[1]));
6383 6383
     }
6384 6384
     else if (streq(p[0], "mssfix") && !p[2])
6385 6385
     {
... ...
@@ -36,7 +36,7 @@
36 36
 #include "common.h"
37 37
 #include "error.h"
38 38
 #include "route.h"
39
-#include "misc.h"
39
+#include "run_command.h"
40 40
 #include "socket.h"
41 41
 #include "manage.h"
42 42
 #include "win32.h"
43 43
new file mode 100644
... ...
@@ -0,0 +1,267 @@
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-2017 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 along
19
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
20
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
+ */
22
+
23
+#ifdef HAVE_CONFIG_H
24
+#include "config.h"
25
+#elif defined(_MSC_VER)
26
+#include "config-msvc.h"
27
+#endif
28
+
29
+#include "syshead.h"
30
+
31
+#include "buffer.h"
32
+#include "error.h"
33
+#include "platform.h"
34
+#include "win32.h"
35
+
36
+#include "memdbg.h"
37
+
38
+#include "run_command.h"
39
+
40
+/* contains an SSEC_x value defined in platform.h */
41
+static int script_security_level = SSEC_BUILT_IN; /* GLOBAL */
42
+
43
+int script_security(void)
44
+{
45
+    return script_security_level;
46
+}
47
+
48
+void script_security_set(int level)
49
+{
50
+    script_security_level = level;
51
+}
52
+
53
+/*
54
+ * Print an error message based on the status code returned by system().
55
+ */
56
+static const char *
57
+system_error_message(int stat, struct gc_arena *gc)
58
+{
59
+    struct buffer out = alloc_buf_gc(256, gc);
60
+#ifdef _WIN32
61
+    if (stat == -1)
62
+    {
63
+        buf_printf(&out, "external program did not execute -- ");
64
+    }
65
+    buf_printf(&out, "returned error code %d", stat);
66
+#else  /* ifdef _WIN32 */
67
+    if (stat == -1)
68
+    {
69
+        buf_printf(&out, "external program fork failed");
70
+    }
71
+    else if (!WIFEXITED(stat))
72
+    {
73
+        buf_printf(&out, "external program did not exit normally");
74
+    }
75
+    else
76
+    {
77
+        const int cmd_ret = WEXITSTATUS(stat);
78
+        if (!cmd_ret)
79
+        {
80
+            buf_printf(&out, "external program exited normally");
81
+        }
82
+        else if (cmd_ret == 127)
83
+        {
84
+            buf_printf(&out, "could not execute external program");
85
+        }
86
+        else
87
+        {
88
+            buf_printf(&out, "external program exited with error status: %d", cmd_ret);
89
+        }
90
+    }
91
+#endif /* ifdef _WIN32 */
92
+    return (const char *)out.data;
93
+}
94
+
95
+bool
96
+openvpn_execve_allowed(const unsigned int flags)
97
+{
98
+    if (flags & S_SCRIPT)
99
+    {
100
+        return script_security() >= SSEC_SCRIPTS;
101
+    }
102
+    else
103
+    {
104
+        return script_security() >= SSEC_BUILT_IN;
105
+    }
106
+}
107
+
108
+
109
+#ifndef _WIN32
110
+/*
111
+ * Run execve() inside a fork().  Designed to replicate the semantics of system() but
112
+ * in a safer way that doesn't require the invocation of a shell or the risks
113
+ * assocated with formatting and parsing a command line.
114
+ */
115
+int
116
+openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags)
117
+{
118
+    struct gc_arena gc = gc_new();
119
+    int ret = -1;
120
+    static bool warn_shown = false;
121
+
122
+    if (a && a->argv[0])
123
+    {
124
+#if defined(ENABLE_FEATURE_EXECVE)
125
+        if (openvpn_execve_allowed(flags))
126
+        {
127
+            const char *cmd = a->argv[0];
128
+            char *const *argv = a->argv;
129
+            char *const *envp = (char *const *)make_env_array(es, true, &gc);
130
+            pid_t pid;
131
+
132
+            pid = fork();
133
+            if (pid == (pid_t)0) /* child side */
134
+            {
135
+                execve(cmd, argv, envp);
136
+                exit(127);
137
+            }
138
+            else if (pid < (pid_t)0) /* fork failed */
139
+            {
140
+                msg(M_ERR, "openvpn_execve: unable to fork");
141
+            }
142
+            else /* parent side */
143
+            {
144
+                if (waitpid(pid, &ret, 0) != pid)
145
+                {
146
+                    ret = -1;
147
+                }
148
+            }
149
+        }
150
+        else if (!warn_shown && (script_security() < SSEC_SCRIPTS))
151
+        {
152
+            msg(M_WARN, SCRIPT_SECURITY_WARNING);
153
+            warn_shown = true;
154
+        }
155
+#else  /* if defined(ENABLE_FEATURE_EXECVE) */
156
+        msg(M_WARN, "openvpn_execve: execve function not available");
157
+#endif /* if defined(ENABLE_FEATURE_EXECVE) */
158
+    }
159
+    else
160
+    {
161
+        msg(M_FATAL, "openvpn_execve: called with empty argv");
162
+    }
163
+
164
+    gc_free(&gc);
165
+    return ret;
166
+}
167
+#endif /* ifndef _WIN32 */
168
+
169
+/*
170
+ * Wrapper around openvpn_execve
171
+ */
172
+bool
173
+openvpn_execve_check(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message)
174
+{
175
+    struct gc_arena gc = gc_new();
176
+    const int stat = openvpn_execve(a, es, flags);
177
+    int ret = false;
178
+
179
+    if (platform_system_ok(stat))
180
+    {
181
+        ret = true;
182
+    }
183
+    else
184
+    {
185
+        if (error_message)
186
+        {
187
+            msg(((flags & S_FATAL) ? M_FATAL : M_WARN), "%s: %s",
188
+                error_message,
189
+                system_error_message(stat, &gc));
190
+        }
191
+    }
192
+    gc_free(&gc);
193
+    return ret;
194
+}
195
+
196
+/*
197
+ * Run execve() inside a fork(), duping stdout.  Designed to replicate the semantics of popen() but
198
+ * in a safer way that doesn't require the invocation of a shell or the risks
199
+ * assocated with formatting and parsing a command line.
200
+ */
201
+int
202
+openvpn_popen(const struct argv *a,  const struct env_set *es)
203
+{
204
+    struct gc_arena gc = gc_new();
205
+    int ret = -1;
206
+    static bool warn_shown = false;
207
+
208
+    if (a && a->argv[0])
209
+    {
210
+#if defined(ENABLE_FEATURE_EXECVE)
211
+        if (script_security() >= SSEC_BUILT_IN)
212
+        {
213
+            const char *cmd = a->argv[0];
214
+            char *const *argv = a->argv;
215
+            char *const *envp = (char *const *)make_env_array(es, true, &gc);
216
+            pid_t pid;
217
+            int pipe_stdout[2];
218
+
219
+            if (pipe(pipe_stdout) == 0)
220
+            {
221
+                pid = fork();
222
+                if (pid == (pid_t)0)       /* child side */
223
+                {
224
+                    close(pipe_stdout[0]);         /* Close read end */
225
+                    dup2(pipe_stdout[1],1);
226
+                    execve(cmd, argv, envp);
227
+                    exit(127);
228
+                }
229
+                else if (pid > (pid_t)0)       /* parent side */
230
+                {
231
+                    int status = 0;
232
+
233
+                    close(pipe_stdout[1]);        /* Close write end */
234
+                    waitpid(pid, &status, 0);
235
+                    ret = pipe_stdout[0];
236
+                }
237
+                else       /* fork failed */
238
+                {
239
+                    close(pipe_stdout[0]);
240
+                    close(pipe_stdout[1]);
241
+                    msg(M_ERR, "openvpn_popen: unable to fork %s", cmd);
242
+                }
243
+            }
244
+            else
245
+            {
246
+                msg(M_WARN, "openvpn_popen: unable to create stdout pipe for %s", cmd);
247
+                ret = -1;
248
+            }
249
+        }
250
+        else if (!warn_shown && (script_security() < SSEC_SCRIPTS))
251
+        {
252
+            msg(M_WARN, SCRIPT_SECURITY_WARNING);
253
+            warn_shown = true;
254
+        }
255
+#else  /* if defined(ENABLE_FEATURE_EXECVE) */
256
+        msg(M_WARN, "openvpn_popen: execve function not available");
257
+#endif /* if defined(ENABLE_FEATURE_EXECVE) */
258
+    }
259
+    else
260
+    {
261
+        msg(M_FATAL, "openvpn_popen: called with empty argv");
262
+    }
263
+
264
+    gc_free(&gc);
265
+    return ret;
266
+}
0 267
new file mode 100644
... ...
@@ -0,0 +1,63 @@
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-2017 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 along
19
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
20
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
+ */
22
+
23
+#ifndef RUN_COMMAND_H
24
+#define RUN_COMMAND_H
25
+
26
+#include "basic.h"
27
+#include "env_set.h"
28
+
29
+/* Script security */
30
+#define SSEC_NONE      0 /* strictly no calling of external programs */
31
+#define SSEC_BUILT_IN  1 /* only call built-in programs such as ifconfig, route, netsh, etc.*/
32
+#define SSEC_SCRIPTS   2 /* allow calling of built-in programs and user-defined scripts */
33
+#define SSEC_PW_ENV    3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */
34
+
35
+int script_security(void);
36
+
37
+void script_security_set(int level);
38
+
39
+/* openvpn_execve flags */
40
+#define S_SCRIPT (1<<0)
41
+#define S_FATAL  (1<<1)
42
+
43
+/* wrapper around the execve() call */
44
+int openvpn_popen(const struct argv *a,  const struct env_set *es);
45
+
46
+bool openvpn_execve_allowed(const unsigned int flags);
47
+
48
+bool openvpn_execve_check(const struct argv *a, const struct env_set *es,
49
+                          const unsigned int flags, const char *error_message);
50
+
51
+static inline bool
52
+openvpn_run_script(const struct argv *a, const struct env_set *es,
53
+                   const unsigned int flags, const char *hook)
54
+{
55
+    char msg[256];
56
+
57
+    openvpn_snprintf(msg, sizeof(msg),
58
+                     "WARNING: Failed running command (%s)", hook);
59
+    return openvpn_execve_check(a, es, flags | S_SCRIPT, msg);
60
+}
61
+
62
+#endif /* ifndef RUN_COMMAND_H */
... ...
@@ -35,6 +35,7 @@
35 35
 #include "gremlin.h"
36 36
 #include "plugin.h"
37 37
 #include "ps.h"
38
+#include "run_command.h"
38 39
 #include "manage.h"
39 40
 #include "misc.h"
40 41
 #include "manage.h"
... ...
@@ -34,10 +34,10 @@
34 34
 
35 35
 #include "syshead.h"
36 36
 
37
-#include "misc.h"
37
+#include "base64.h"
38 38
 #include "manage.h"
39 39
 #include "otime.h"
40
-#include "base64.h"
40
+#include "run_command.h"
41 41
 #include "ssl_verify.h"
42 42
 #include "ssl_verify_backend.h"
43 43
 
... ...
@@ -40,7 +40,7 @@
40 40
 #include "tun.h"
41 41
 #include "fdmisc.h"
42 42
 #include "common.h"
43
-#include "misc.h"
43
+#include "run_command.h"
44 44
 #include "socket.h"
45 45
 #include "manage.h"
46 46
 #include "route.h"
... ...
@@ -39,9 +39,9 @@
39 39
 #include "buffer.h"
40 40
 #include "error.h"
41 41
 #include "mtu.h"
42
+#include "run_command.h"
42 43
 #include "sig.h"
43 44
 #include "win32.h"
44
-#include "misc.h"
45 45
 #include "openvpn-msg.h"
46 46
 
47 47
 #include "memdbg.h"
... ...
@@ -1137,7 +1137,7 @@ openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned in
1137 1137
             free(env);
1138 1138
             gc_free(&gc);
1139 1139
         }
1140
-        else if (!exec_warn && (script_security < SSEC_SCRIPTS))
1140
+        else if (!exec_warn && (script_security() < SSEC_SCRIPTS))
1141 1141
         {
1142 1142
             msg(M_WARN, SCRIPT_SECURITY_WARNING);
1143 1143
             exec_warn = true;