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