OpenVPN
log_v3.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2025 OpenVPN Inc <sales@openvpn.net>
9 * Copyright (C) 2010-2025 David Sommerseth <dazo@eurephia.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, see <https://www.gnu.org/licenses/>.
22 */
23
24/*
25 * This plugin is similar to simple.c, except it also logs extra information
26 * to stdout for every plugin method called by OpenVPN. The only difference
27 * between this (log_v3.c) and log.c is that this module uses the v3 plug-in
28 * API.
29 *
30 * See the README file for build instructions.
31 */
32
33#include <stdio.h>
34#include <string.h>
35#include <stdlib.h>
36
37#include "openvpn-plugin.h"
38
39/*
40 * Our context, where we keep our state.
41 */
42struct plugin_context
43{
44 const char *username;
45 const char *password;
46};
47
48/*
49 * Given an environmental variable name, search
50 * the envp array for its value, returning it
51 * if found or NULL otherwise.
52 */
53static const char *
54get_env(const char *name, const char *envp[])
55{
56 if (envp)
57 {
58 const size_t namelen = strlen(name);
59 for (int 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
74OPENVPN_EXPORT int
75openvpn_plugin_open_v3(const int v3structver, struct openvpn_plugin_args_open_in const *args,
76 struct openvpn_plugin_args_open_return *ret)
77{
78 struct plugin_context *context = NULL;
79
80 /* Check that we are API compatible */
81 if (v3structver != OPENVPN_PLUGINv3_STRUCTVER)
82 {
83 printf("log_v3: ** ERROR ** Incompatible plug-in interface between this plug-in and OpenVPN\n");
84 return OPENVPN_PLUGIN_FUNC_ERROR;
85 }
86
87 if (args->ssl_api != SSLAPI_OPENSSL)
88 {
89 printf("This plug-in can only be used against OpenVPN with OpenSSL\n");
90 return OPENVPN_PLUGIN_FUNC_ERROR;
91 }
92
93 /* Print some version information about the OpenVPN process using this plug-in */
94 printf("log_v3: OpenVPN %s (Major: %i, Minor: %i, Patch: %s)\n", args->ovpn_version,
95 args->ovpn_version_major, args->ovpn_version_minor, args->ovpn_version_patch);
96
97 /* Which callbacks to intercept. */
98 ret->type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP)
99 | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN)
100 | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP)
101 | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE)
102 | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY)
103 | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
104 | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2)
105 | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
106 | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS)
107 | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
108
109
110 /* Allocate our context */
111 context = (struct plugin_context *)calloc(1, sizeof(struct plugin_context));
112 if (context == NULL)
113 {
114 printf("PLUGIN: allocating memory for context failed\n");
115 return OPENVPN_PLUGIN_FUNC_ERROR;
116 }
117
118 /* Set the username/password we will require. */
119 context->username = "foo";
120 context->password = "bar";
121
122 /* Point the global context handle to our newly created context */
123 ret->handle = (void *)context;
124
125 return OPENVPN_PLUGIN_FUNC_SUCCESS;
126}
127
128void
129show(const int type, const char *argv[], const char *envp[])
130{
131 size_t i;
132 switch (type)
133 {
134 case OPENVPN_PLUGIN_UP:
135 printf("OPENVPN_PLUGIN_UP\n");
136 break;
137
138 case OPENVPN_PLUGIN_DOWN:
139 printf("OPENVPN_PLUGIN_DOWN\n");
140 break;
141
142 case OPENVPN_PLUGIN_ROUTE_UP:
143 printf("OPENVPN_PLUGIN_ROUTE_UP\n");
144 break;
145
146 case OPENVPN_PLUGIN_IPCHANGE:
147 printf("OPENVPN_PLUGIN_IPCHANGE\n");
148 break;
149
150 case OPENVPN_PLUGIN_TLS_VERIFY:
151 printf("OPENVPN_PLUGIN_TLS_VERIFY\n");
152 break;
153
154 case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
155 printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
156 break;
157
158 case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
159 printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
160 break;
161
162 case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
163 printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
164 break;
165
166 case OPENVPN_PLUGIN_LEARN_ADDRESS:
167 printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
168 break;
169
170 case OPENVPN_PLUGIN_TLS_FINAL:
171 printf("OPENVPN_PLUGIN_TLS_FINAL\n");
172 break;
173
174 default:
175 printf("OPENVPN_PLUGIN_?\n");
176 break;
177 }
178
179 printf("ARGV\n");
180 for (i = 0; argv[i] != NULL; ++i)
181 {
182 printf("%d '%s'\n", (int)i, argv[i]);
183 }
184
185 printf("ENVP\n");
186 for (i = 0; envp[i] != NULL; ++i)
187 {
188 printf("%d '%s'\n", (int)i, envp[i]);
189 }
190}
191
192static void
193x509_print_info(X509 *x509crt)
194{
195 int i, n;
196 int fn_nid;
197 ASN1_OBJECT *fn;
198 ASN1_STRING *val;
199 X509_NAME *x509_name;
200 X509_NAME_ENTRY *ent;
201 const char *objbuf;
202 unsigned char *buf = NULL;
203
204 x509_name = X509_get_subject_name(x509crt);
205 n = X509_NAME_entry_count(x509_name);
206 for (i = 0; i < n; ++i)
207 {
208 ent = X509_NAME_get_entry(x509_name, i);
209 if (!ent)
210 {
211 continue;
212 }
213 fn = X509_NAME_ENTRY_get_object(ent);
214 if (!fn)
215 {
216 continue;
217 }
218 val = X509_NAME_ENTRY_get_data(ent);
219 if (!val)
220 {
221 continue;
222 }
223 fn_nid = OBJ_obj2nid(fn);
224 if (fn_nid == NID_undef)
225 {
226 continue;
227 }
228 objbuf = OBJ_nid2sn(fn_nid);
229 if (!objbuf)
230 {
231 continue;
232 }
233 if (ASN1_STRING_to_UTF8(&buf, val) < 0)
234 {
235 continue;
236 }
237
238 printf("X509 %s: %s\n", objbuf, (char *)buf);
239 OPENSSL_free(buf);
240 }
241}
242
243
244OPENVPN_EXPORT int
245openvpn_plugin_func_v3(const int version, struct openvpn_plugin_args_func_in const *args,
246 struct openvpn_plugin_args_func_return *retptr)
247{
248 struct plugin_context *context = (struct plugin_context *)args->handle;
249
250 printf("\nopenvpn_plugin_func_v3() :::::>> ");
251 show(args->type, args->argv, args->envp);
252
253 /* Dump some X509 information if we're in the TLS_VERIFY phase */
254 if ((args->type == OPENVPN_PLUGIN_TLS_VERIFY) && args->current_cert)
255 {
256 printf("---- X509 Subject information ----\n");
257 printf("Certificate depth: %i\n", args->current_cert_depth);
258 x509_print_info(args->current_cert);
259 printf("----------------------------------\n");
260 }
261
262 /* check entered username/password against what we require */
263 if (args->type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
264 {
265 /* get username/password from envp string array */
266 const char *username = get_env("username", args->envp);
267 const char *password = get_env("password", args->envp);
268
269 if (username && !strcmp(username, context->username) && password
270 && !strcmp(password, context->password))
271 {
272 return OPENVPN_PLUGIN_FUNC_SUCCESS;
273 }
274 else
275 {
276 return OPENVPN_PLUGIN_FUNC_ERROR;
277 }
278 }
279 else
280 {
281 return OPENVPN_PLUGIN_FUNC_SUCCESS;
282 }
283}
284
285OPENVPN_EXPORT void
286openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
287{
288 struct plugin_context *context = (struct plugin_context *)handle;
289 free(context);
290}
OPENVPN_EXPORT void openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
Definition log_v3.c:286
static void x509_print_info(X509 *x509crt)
Definition log_v3.c:193
void show(const int type, const char *argv[], const char *envp[])
Definition log_v3.c:129
static const char * get_env(const char *name, const char *envp[])
Definition log_v3.c:54
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)
Definition log_v3.c:75
OPENVPN_EXPORT int openvpn_plugin_func_v3(const int version, struct openvpn_plugin_args_func_in const *args, struct openvpn_plugin_args_func_return *retptr)
Definition log_v3.c:245
Definition argv.h:35
Contains all state information for one tunnel.
Definition openvpn.h:474
const char * password
Definition log.c:42
const char * username
Definition log.c:41