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-2009 OpenVPN Technologies, Inc. <sales@openvpn.net> 9 * Copyright (C) 2010 David Sommerseth <dazo@users.sourceforge.net> 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 21 * along with this program (see the file COPYING included with this 22 * distribution); if not, write to the Free Software Foundation, Inc., 23 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 */ 25 26/* 27 * This plugin is similar to simple.c, except it also logs extra information 28 * to stdout for every plugin method called by OpenVPN. The only difference 29 * between this (log_v3.c) and log.c is that this module uses the v3 plug-in 30 * API. 31 * 32 * See the README file for build instructions. 33 */ 34 35#include <stdio.h> 36#include <string.h> 37#include <stdlib.h> 38 39#define ENABLE_SSL 40 41#include "openvpn-plugin.h" 42 43/* 44 * Our context, where we keep our state. 45 */ 46struct plugin_context { 47 const char *username; 48 const char *password; 49}; 50 51/* 52 * Given an environmental variable name, search 53 * the envp array for its value, returning it 54 * if found or NULL otherwise. 55 */ 56static const char * 57get_env (const char *name, const char *envp[]) 58{ 59 if (envp) 60 { 61 int i; 62 const int namelen = strlen (name); 63 for (i = 0; envp[i]; ++i) 64 { 65 if (!strncmp (envp[i], name, namelen)) 66 { 67 const char *cp = envp[i] + namelen; 68 if (*cp == '=') 69 return cp + 1; 70 } 71 } 72 } 73 return NULL; 74} 75 76OPENVPN_EXPORT int 77openvpn_plugin_open_v3 (const int v3structver, 78 struct openvpn_plugin_args_open_in const *args, 79 struct openvpn_plugin_args_open_return *ret) 80{ 81 struct plugin_context *context = NULL; 82 83 /* Check that we are API compatible */ 84 if( v3structver != OPENVPN_PLUGINv3_STRUCTVER ) { 85 return OPENVPN_PLUGIN_FUNC_ERROR; 86 } 87 88 /* Which callbacks to intercept. */ 89 ret->type_mask = 90 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | 91 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) | 92 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) | 93 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) | 94 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) | 95 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) | 96 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | 97 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) | 98 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) | 99 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL); 100 101 102 /* Allocate our context */ 103 context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context)); 104 105 /* Set the username/password we will require. */ 106 context->username = "foo"; 107 context->password = "bar"; 108 109 /* Point the global context handle to our newly created context */ 110 ret->handle = (void *) context; 111 112 return OPENVPN_PLUGIN_FUNC_SUCCESS; 113} 114 115void 116show (const int type, const char *argv[], const char *envp[]) 117{ 118 size_t i; 119 switch (type) 120 { 121 case OPENVPN_PLUGIN_UP: 122 printf ("OPENVPN_PLUGIN_UP\n"); 123 break; 124 case OPENVPN_PLUGIN_DOWN: 125 printf ("OPENVPN_PLUGIN_DOWN\n"); 126 break; 127 case OPENVPN_PLUGIN_ROUTE_UP: 128 printf ("OPENVPN_PLUGIN_ROUTE_UP\n"); 129 break; 130 case OPENVPN_PLUGIN_IPCHANGE: 131 printf ("OPENVPN_PLUGIN_IPCHANGE\n"); 132 break; 133 case OPENVPN_PLUGIN_TLS_VERIFY: 134 printf ("OPENVPN_PLUGIN_TLS_VERIFY\n"); 135 break; 136 case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: 137 printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n"); 138 break; 139 case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: 140 printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n"); 141 break; 142 case OPENVPN_PLUGIN_CLIENT_DISCONNECT: 143 printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n"); 144 break; 145 case OPENVPN_PLUGIN_LEARN_ADDRESS: 146 printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n"); 147 break; 148 case OPENVPN_PLUGIN_TLS_FINAL: 149 printf ("OPENVPN_PLUGIN_TLS_FINAL\n"); 150 break; 151 default: 152 printf ("OPENVPN_PLUGIN_?\n"); 153 break; 154 } 155 156 printf ("ARGV\n"); 157 for (i = 0; argv[i] != NULL; ++i) 158 printf ("%d '%s'\n", (int)i, argv[i]); 159 160 printf ("ENVP\n"); 161 for (i = 0; envp[i] != NULL; ++i) 162 printf ("%d '%s'\n", (int)i, envp[i]); 163} 164 165static void 166x509_print_info (X509 *x509crt) 167{ 168 int i, n; 169 int fn_nid; 170 ASN1_OBJECT *fn; 171 ASN1_STRING *val; 172 X509_NAME *x509_name; 173 X509_NAME_ENTRY *ent; 174 const char *objbuf; 175 unsigned char *buf; 176 177 x509_name = X509_get_subject_name (x509crt); 178 n = X509_NAME_entry_count (x509_name); 179 for (i = 0; i < n; ++i) 180 { 181 ent = X509_NAME_get_entry (x509_name, i); 182 if (!ent) 183 continue; 184 fn = X509_NAME_ENTRY_get_object (ent); 185 if (!fn) 186 continue; 187 val = X509_NAME_ENTRY_get_data (ent); 188 if (!val) 189 continue; 190 fn_nid = OBJ_obj2nid (fn); 191 if (fn_nid == NID_undef) 192 continue; 193 objbuf = OBJ_nid2sn (fn_nid); 194 if (!objbuf) 195 continue; 196 buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ 197 if (ASN1_STRING_to_UTF8 (&buf, val) <= 0) 198 continue; 199 200 printf("X509 %s: %s\n", objbuf, (char *)buf); 201 OPENSSL_free (buf); 202 } 203} 204 205 206 207OPENVPN_EXPORT int 208openvpn_plugin_func_v3 (const int version, 209 struct openvpn_plugin_args_func_in const *args, 210 struct openvpn_plugin_args_func_return *retptr) 211{ 212 struct plugin_context *context = (struct plugin_context *) args->handle; 213 214 printf("\nopenvpn_plugin_func_v3() :::::>> "); 215 show (args->type, args->argv, args->envp); 216 217 /* Dump some X509 information if we're in the TLS_VERIFY phase */ 218 if ((args->type == OPENVPN_PLUGIN_TLS_VERIFY) && args->current_cert ) { 219 printf("---- X509 Subject information ----\n"); 220 printf("Certificate depth: %i\n", args->current_cert_depth); 221 x509_print_info(args->current_cert); 222 printf("----------------------------------\n"); 223 } 224 225 /* check entered username/password against what we require */ 226 if (args->type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) 227 { 228 /* get username/password from envp string array */ 229 const char *username = get_env ("username", args->envp); 230 const char *password = get_env ("password", args->envp); 231 232 if (username && !strcmp (username, context->username) 233 && password && !strcmp (password, context->password)) 234 return OPENVPN_PLUGIN_FUNC_SUCCESS; 235 else 236 return OPENVPN_PLUGIN_FUNC_ERROR; 237 } 238 else 239 return OPENVPN_PLUGIN_FUNC_SUCCESS; 240} 241 242OPENVPN_EXPORT void 243openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) 244{ 245 struct plugin_context *context = (struct plugin_context *) handle; 246 free (context); 247} 248