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-2022 OpenVPN Inc <sales@openvpn.net>
9  *  Copyright (C) 2010-2022 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, write to the Free Software Foundation, Inc.,
22  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 
25 /*
26  * This plugin is similar to simple.c, except it also logs extra information
27  * to stdout for every plugin method called by OpenVPN.  The only difference
28  * between this (log_v3.c) and log.c is that this module uses the v3 plug-in
29  * API.
30  *
31  * See the README file for build instructions.
32  */
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 
38 #include "openvpn-plugin.h"
39 
40 /*
41  * Our context, where we keep our state.
42  */
43 struct plugin_context {
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  */
53 static const char *
get_env(const char * name,const char * envp[])54 get_env(const char *name, const char *envp[])
55 {
56     if (envp)
57     {
58         int i;
59         const int namelen = strlen(name);
60         for (i = 0; envp[i]; ++i)
61         {
62             if (!strncmp(envp[i], name, namelen))
63             {
64                 const char *cp = envp[i] + namelen;
65                 if (*cp == '=')
66                 {
67                     return cp + 1;
68                 }
69             }
70         }
71     }
72     return NULL;
73 }
74 
75 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)76 openvpn_plugin_open_v3(const int v3structver,
77                        struct openvpn_plugin_args_open_in const *args,
78                        struct openvpn_plugin_args_open_return *ret)
79 {
80     struct plugin_context *context = NULL;
81 
82     /* Check that we are API compatible */
83     if (v3structver != OPENVPN_PLUGINv3_STRUCTVER)
84     {
85         printf("log_v3: ** ERROR ** Incompatible plug-in interface between this plug-in and OpenVPN\n");
86         return OPENVPN_PLUGIN_FUNC_ERROR;
87     }
88 
89     if (args->ssl_api != SSLAPI_OPENSSL)
90     {
91         printf("This plug-in can only be used against OpenVPN with OpenSSL\n");
92         return OPENVPN_PLUGIN_FUNC_ERROR;
93     }
94 
95     /* Print some version information about the OpenVPN process using this plug-in */
96     printf("log_v3: OpenVPN %s  (Major: %i, Minor: %i, Patch: %s)\n",
97            args->ovpn_version, args->ovpn_version_major,
98            args->ovpn_version_minor, args->ovpn_version_patch);
99 
100     /*  Which callbacks to intercept.  */
101     ret->type_mask =
102         OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP)
103         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN)
104         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP)
105         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE)
106         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY)
107         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
108         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2)
109         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
110         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS)
111         |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
112 
113 
114     /* Allocate our context */
115     context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
116     if (context == NULL)
117     {
118         printf("PLUGIN: allocating memory for context failed\n");
119         return OPENVPN_PLUGIN_FUNC_ERROR;
120     }
121 
122     /* Set the username/password we will require. */
123     context->username = "foo";
124     context->password = "bar";
125 
126     /* Point the global context handle to our newly created context */
127     ret->handle = (void *) context;
128 
129     return OPENVPN_PLUGIN_FUNC_SUCCESS;
130 }
131 
132 void
show(const int type,const char * argv[],const char * envp[])133 show(const int type, const char *argv[], const char *envp[])
134 {
135     size_t i;
136     switch (type)
137     {
138         case OPENVPN_PLUGIN_UP:
139             printf("OPENVPN_PLUGIN_UP\n");
140             break;
141 
142         case OPENVPN_PLUGIN_DOWN:
143             printf("OPENVPN_PLUGIN_DOWN\n");
144             break;
145 
146         case OPENVPN_PLUGIN_ROUTE_UP:
147             printf("OPENVPN_PLUGIN_ROUTE_UP\n");
148             break;
149 
150         case OPENVPN_PLUGIN_IPCHANGE:
151             printf("OPENVPN_PLUGIN_IPCHANGE\n");
152             break;
153 
154         case OPENVPN_PLUGIN_TLS_VERIFY:
155             printf("OPENVPN_PLUGIN_TLS_VERIFY\n");
156             break;
157 
158         case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
159             printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
160             break;
161 
162         case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
163             printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
164             break;
165 
166         case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
167             printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
168             break;
169 
170         case OPENVPN_PLUGIN_LEARN_ADDRESS:
171             printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
172             break;
173 
174         case OPENVPN_PLUGIN_TLS_FINAL:
175             printf("OPENVPN_PLUGIN_TLS_FINAL\n");
176             break;
177 
178         default:
179             printf("OPENVPN_PLUGIN_?\n");
180             break;
181     }
182 
183     printf("ARGV\n");
184     for (i = 0; argv[i] != NULL; ++i)
185     {
186         printf("%d '%s'\n", (int)i, argv[i]);
187     }
188 
189     printf("ENVP\n");
190     for (i = 0; envp[i] != NULL; ++i)
191     {
192         printf("%d '%s'\n", (int)i, envp[i]);
193     }
194 }
195 
196 static void
x509_print_info(X509 * x509crt)197 x509_print_info(X509 *x509crt)
198 {
199     int i, n;
200     int fn_nid;
201     ASN1_OBJECT *fn;
202     ASN1_STRING *val;
203     X509_NAME *x509_name;
204     X509_NAME_ENTRY *ent;
205     const char *objbuf;
206     unsigned char *buf = NULL;
207 
208     x509_name = X509_get_subject_name(x509crt);
209     n = X509_NAME_entry_count(x509_name);
210     for (i = 0; i < n; ++i)
211     {
212         ent = X509_NAME_get_entry(x509_name, i);
213         if (!ent)
214         {
215             continue;
216         }
217         fn = X509_NAME_ENTRY_get_object(ent);
218         if (!fn)
219         {
220             continue;
221         }
222         val = X509_NAME_ENTRY_get_data(ent);
223         if (!val)
224         {
225             continue;
226         }
227         fn_nid = OBJ_obj2nid(fn);
228         if (fn_nid == NID_undef)
229         {
230             continue;
231         }
232         objbuf = OBJ_nid2sn(fn_nid);
233         if (!objbuf)
234         {
235             continue;
236         }
237         if (ASN1_STRING_to_UTF8(&buf, val) < 0)
238         {
239             continue;
240         }
241 
242         printf("X509 %s: %s\n", objbuf, (char *)buf);
243         OPENSSL_free(buf);
244     }
245 }
246 
247 
248 
249 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)250 openvpn_plugin_func_v3(const int version,
251                        struct openvpn_plugin_args_func_in const *args,
252                        struct openvpn_plugin_args_func_return *retptr)
253 {
254     struct plugin_context *context = (struct plugin_context *) args->handle;
255 
256     printf("\nopenvpn_plugin_func_v3() :::::>> ");
257     show(args->type, args->argv, args->envp);
258 
259     /* Dump some X509 information if we're in the TLS_VERIFY phase */
260     if ((args->type == OPENVPN_PLUGIN_TLS_VERIFY) && args->current_cert)
261     {
262         printf("---- X509 Subject information ----\n");
263         printf("Certificate depth: %i\n", args->current_cert_depth);
264         x509_print_info(args->current_cert);
265         printf("----------------------------------\n");
266     }
267 
268     /* check entered username/password against what we require */
269     if (args->type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
270     {
271         /* get username/password from envp string array */
272         const char *username = get_env("username", args->envp);
273         const char *password = get_env("password", args->envp);
274 
275         if (username && !strcmp(username, context->username)
276             && password && !strcmp(password, context->password))
277         {
278             return OPENVPN_PLUGIN_FUNC_SUCCESS;
279         }
280         else
281         {
282             return OPENVPN_PLUGIN_FUNC_ERROR;
283         }
284     }
285     else
286     {
287         return OPENVPN_PLUGIN_FUNC_SUCCESS;
288     }
289 }
290 
291 OPENVPN_EXPORT void
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)292 openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
293 {
294     struct plugin_context *context = (struct plugin_context *) handle;
295     free(context);
296 }
297