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