Browse code

plugin: Export base64 encode and decode functions

This patch builds on the "Export secure_memzero() to plug-ins" patch and
adds export of openvpn_base64_encode() and openvpn_base64_decode()

This also ships with a very simple plug-in which demonstrates how to use
the new exported functions.

Signed-off-by: David Sommerseth <davids@openvpn.net>
Acked-by: Selva Nair <selva.nair@gmail.com>
Message-Id: <20170505214624.11675-1-davids@openvpn.net>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14558.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

David Sommerseth authored on 2017/05/06 06:46:23
Showing 3 changed files
... ...
@@ -219,6 +219,8 @@ struct openvpn_plugin_string_list
219 219
  *           OpenVPN to plug-ins.
220 220
  *
221 221
  *    4      Exported secure_memzero() as plugin_secure_memzero()
222
+ *           Exported openvpn_base64_encode() as plugin_base64_encode()
223
+ *           Exported openvpn_base64_decode() as plugin_base64_decode()
222 224
  */
223 225
 #define OPENVPN_PLUGINv3_STRUCTVER 4
224 226
 
... ...
@@ -267,6 +269,33 @@ typedef void (*plugin_vlog_t)(openvpn_plugin_log_flags_t flags,
267 267
  */
268 268
 typedef void (*plugin_secure_memzero_t)(void *data, size_t len);
269 269
 
270
+/**
271
+ *  Export of openvpn_base64_encode() to be used inside plug-ins
272
+ *
273
+ *  @param data   Pointer to data to BASE64 encode
274
+ *  @param size   Length of data, in bytes
275
+ *  @param *str   Pointer to the return buffer.  This needed memory is
276
+ *                allocated by openvpn_base64_encode() and needs to be free()d
277
+ *                after use.
278
+ *
279
+ *  @return int   Returns the length of the buffer created, or -1 on error.
280
+ *
281
+ */
282
+typedef int (*plugin_base64_encode_t)(const void *data, int size, char **str);
283
+
284
+/**
285
+ *  Export of openvpn_base64_decode() to be used inside plug-ins
286
+ *
287
+ *  @param str    Pointer to the BASE64 encoded data
288
+ *  @param data   Pointer to the buffer where save the decoded data
289
+ *  @param size   Size of the destination buffer
290
+ *
291
+ *  @return int   Returns the length of the decoded data, or -1 on error or
292
+ *                if the destination buffer is too small.
293
+ *
294
+ */
295
+typedef int (*plugin_base64_decode_t)(const char *str, void *data, int size);
296
+
270 297
 
271 298
 /**
272 299
  * Used by the openvpn_plugin_open_v3() function to pass callback
... ...
@@ -289,6 +318,8 @@ struct openvpn_plugin_callbacks
289 289
     plugin_log_t plugin_log;
290 290
     plugin_vlog_t plugin_vlog;
291 291
     plugin_secure_memzero_t plugin_secure_memzero;
292
+    plugin_base64_encode_t plugin_base64_encode;
293
+    plugin_base64_decode_t plugin_base64_decode;
292 294
 };
293 295
 
294 296
 /**
295 297
new file mode 100644
... ...
@@ -0,0 +1,203 @@
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) 2017  David Sommerseth <davids@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
+#include <stdio.h>
25
+#include <string.h>
26
+#include <stdlib.h>
27
+
28
+#include "openvpn-plugin.h"
29
+
30
+#define PLUGIN_NAME "base64.c"
31
+
32
+/* Exported plug-in v3 API functions */
33
+plugin_log_t ovpn_log = NULL;                      /**< Pointer to the OpenVPN log function.  See plugin_log() */
34
+plugin_vlog_t ovpn_vlog = NULL;                    /**< Pointer to the OpenVPN vlog function. See plugin_vlog() */
35
+plugin_base64_encode_t ovpn_base64_encode = NULL;  /**< Pointer to the openvpn_base64_encode () function */
36
+plugin_base64_decode_t ovpn_base64_decode = NULL;  /**< Pointer to the openvpn_base64_decode () function */
37
+
38
+/**
39
+ * Search the environment pointer for a specific env var name
40
+ *
41
+ * PLEASE NOTE! The result is not valid outside the local
42
+ * scope of the calling function.  Once the calling function
43
+ * returns, any returned pointers are invalid.
44
+ *
45
+ * @param name  String containing the env.var name to search for
46
+ * @param envp  String array pointer to the environment variable
47
+ *
48
+ * @return Returns a pointer to the value in the environment variable
49
+ *         table on successful match.  Otherwise NULL is returned
50
+ *
51
+ */
52
+static const char *
53
+get_env(const char *name, const char *envp[])
54
+{
55
+    if (envp)
56
+    {
57
+        int i;
58
+        const int namelen = strlen(name);
59
+        for (i = 0; envp[i]; ++i)
60
+        {
61
+            if (!strncmp(envp[i], name, namelen))
62
+            {
63
+                const char *cp = envp[i] + namelen;
64
+                if (*cp == '=')
65
+                {
66
+                    return cp + 1;
67
+                }
68
+            }
69
+        }
70
+    }
71
+    return NULL;
72
+}
73
+
74
+
75
+/**
76
+ * This function is called when OpenVPN loads the plug-in.
77
+ * The purpose is to initialize the plug-in and tell OpenVPN
78
+ * which plug-in hooks this plug-in wants to be involved in
79
+ *
80
+ * For the arguments, see the include/openvpn-plugin.h file
81
+ * for details on the function parameters
82
+ *
83
+ * @param v3structver  An integer containing the API version of
84
+ *                     the plug-in structs OpenVPN uses
85
+ * @param args         A pointer to the argument struct for
86
+ *                     information and features provided by
87
+ *                     OpenVPN to the plug-in
88
+ * @param ret          A pointer to the struct OpenVPN uses to
89
+ *                     receive information back from the plug-in
90
+ *
91
+ * @return Must return OPENVPN_PLUGIN_FUNC_SUCCESS when everything
92
+ *         completed successfully.  Otherwise it must be returned
93
+ *         OPENVPN_PLUGIN_FUNC_ERROR, which will stop OpenVPN
94
+ *         from running
95
+ *
96
+ */
97
+OPENVPN_EXPORT int
98
+openvpn_plugin_open_v3(const int v3structver,
99
+                       struct openvpn_plugin_args_open_in const *args,
100
+                       struct openvpn_plugin_args_open_return *ret)
101
+{
102
+    /* Check that we are API compatible */
103
+    if (v3structver != OPENVPN_PLUGINv3_STRUCTVER)
104
+    {
105
+        printf("base64.c: ** ERROR ** Incompatible plug-in interface between this plug-in and OpenVPN\n");
106
+        return OPENVPN_PLUGIN_FUNC_ERROR;
107
+    }
108
+
109
+    /*  Which callbacks to intercept.  */
110
+    ret->type_mask =
111
+        OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY)
112
+        |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2);
113
+
114
+    /* we don't need a plug-in context in this example, but OpenVPN expects "something" */
115
+    ret->handle = calloc(1, 1);
116
+
117
+    /* Hook into the exported functions from OpenVPN */
118
+    ovpn_log = args->callbacks->plugin_log;
119
+    ovpn_vlog = args->callbacks->plugin_vlog;
120
+    ovpn_base64_encode = args->callbacks->plugin_base64_encode;
121
+    ovpn_base64_decode = args->callbacks->plugin_base64_decode;
122
+
123
+    /* Print some version information about the OpenVPN process using this plug-in */
124
+    ovpn_log(PLOG_NOTE, PLUGIN_NAME, "OpenVPN %s  (Major: %i, Minor: %i, Patch: %s)\n",
125
+             args->ovpn_version, args->ovpn_version_major,
126
+             args->ovpn_version_minor, args->ovpn_version_patch);
127
+
128
+    return OPENVPN_PLUGIN_FUNC_SUCCESS;
129
+}
130
+
131
+
132
+/**
133
+ * This function is called by OpenVPN each time the OpenVPN reaches
134
+ * a point where plug-in calls should happen.  It only happens for those
135
+ * plug-in hooks enabled in openvpn_plugin_open_v3().
136
+ *
137
+ * For the arguments, see the include/openvpn-plugin.h file
138
+ * for details on the function parameters
139
+ *
140
+ * @param args        Pointer to a struct with details about the plug-in
141
+ *                    call from the main OpenVPN process.
142
+ * @param returndata  Pointer to a struct where the plug-in can provide
143
+ *                    information back to OpenVPN to be processed
144
+ *
145
+ * @return  Must return OPENVPN_PLUGIN_FUNC_SUCCESS or
146
+ *          OPENVPN_PLUGIN_FUNC_DEFERRED on success.  Otherwise it
147
+ *          should return OPENVPN_FUNC_ERROR, which will stop and reject
148
+ *          the client session from progressing.
149
+ *
150
+ */
151
+
152
+OPENVPN_EXPORT int
153
+openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
154
+{
155
+    if (type != OPENVPN_PLUGIN_TLS_VERIFY
156
+        && type != OPENVPN_PLUGIN_CLIENT_CONNECT_V2)
157
+    {
158
+        ovpn_log(PLOG_ERR, PLUGIN_NAME, "Unsupported plug-in hook call attempted");
159
+        return OPENVPN_PLUGIN_FUNC_ERROR;
160
+    }
161
+
162
+    /* get username/password from envp string array */
163
+    const char *clcert_cn = get_env("X509_0_CN", envp);
164
+    if (!clcert_cn)
165
+    {
166
+        /* Ignore certificate checks not being a client certificate */
167
+        return OPENVPN_PLUGIN_FUNC_SUCCESS;
168
+    }
169
+
170
+    /* test the BASE64 encode function */
171
+    char *buf = NULL;
172
+    int r = ovpn_base64_encode(clcert_cn, strlen(clcert_cn), &buf);
173
+    ovpn_log(PLOG_NOTE, PLUGIN_NAME, "BASE64 encoded '%s' (return value %i):  '%s'",
174
+             clcert_cn, r, buf);
175
+
176
+    /* test the BASE64 decode function */
177
+    char buf2[256] = {0};
178
+    r = ovpn_base64_decode(buf, &buf2, 255);
179
+    ovpn_log(PLOG_NOTE, PLUGIN_NAME, "BASE64 decoded '%s' (return value %i):  '%s'",
180
+             buf, r, buf2);
181
+
182
+    /* Verify the result, and free the buffer allocated by ovpn_base64_encode() */
183
+    r = strcmp(clcert_cn, buf2);
184
+    free(buf);
185
+
186
+    return (r == 0) ? OPENVPN_PLUGIN_FUNC_SUCCESS : OPENVPN_PLUGIN_FUNC_ERROR;
187
+}
188
+
189
+
190
+/**
191
+ * This cleans up the last part of the plug-in, allows it to
192
+ * shut down cleanly and release the plug-in global context buffer
193
+ *
194
+ * @param handle   Pointer to the plug-in global context buffer, which
195
+ *                 need to be released by this function
196
+ */
197
+OPENVPN_EXPORT void
198
+openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
199
+{
200
+    struct plugin_context *context = (struct plugin_context *) handle;
201
+    free(context);
202
+}
... ...
@@ -43,6 +43,7 @@
43 43
 #include "misc.h"
44 44
 #include "plugin.h"
45 45
 #include "ssl_backend.h"
46
+#include "base64.h"
46 47
 #include "win32.h"
47 48
 #include "memdbg.h"
48 49
 
... ...
@@ -410,7 +411,9 @@ plugin_log(openvpn_plugin_log_flags_t flags, const char *name, const char *forma
410 410
 static struct openvpn_plugin_callbacks callbacks = {
411 411
     plugin_log,
412 412
     plugin_vlog,
413
-    secure_memzero   /* plugin_secure_memzero */
413
+    secure_memzero,         /* plugin_secure_memzero */
414
+    openvpn_base64_encode,  /* plugin_base64_encode */
415
+    openvpn_base64_decode,  /* plugin_base64_decode */
414 416
 };
415 417
 
416 418