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-2024 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);
}
|