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-2010 OpenVPN Technologies, Inc. <sales@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/* 26 * This file implements a simple OpenVPN plugin module which 27 * will test deferred authentication and packet filtering. 28 * 29 * Will run on Windows or *nix. 30 * 31 * Sample usage: 32 * 33 * setenv test_deferred_auth 20 34 * setenv test_packet_filter 10 35 * plugin plugin/defer/simple.so 36 * 37 * This will enable deferred authentication to occur 20 38 * seconds after the normal TLS authentication process, 39 * and will cause a packet filter file to be generated 10 40 * seconds after the initial TLS negotiation, using 41 * {common-name}.pf as the source. 42 * 43 * Sample packet filter configuration: 44 * 45 * [CLIENTS DROP] 46 * +otherclient 47 * [SUBNETS DROP] 48 * +10.0.0.0/8 49 * -10.10.0.8 50 * [END] 51 * 52 * See the README file for build instructions. 53 */ 54 55#include <stdio.h> 56#include <string.h> 57#include <stdlib.h> 58 59#include "openvpn-plugin.h" 60 61/* bool definitions */ 62#define bool int 63#define true 1 64#define false 0 65 66/* 67 * Our context, where we keep our state. 68 */ 69 70struct plugin_context { 71 int test_deferred_auth; 72 int test_packet_filter; 73}; 74 75struct plugin_per_client_context { 76 int n_calls; 77 bool generated_pf_file; 78}; 79 80/* 81 * Given an environmental variable name, search 82 * the envp array for its value, returning it 83 * if found or NULL otherwise. 84 */ 85static const char * 86get_env (const char *name, const char *envp[]) 87{ 88 if (envp) 89 { 90 int i; 91 const int namelen = strlen (name); 92 for (i = 0; envp[i]; ++i) 93 { 94 if (!strncmp (envp[i], name, namelen)) 95 { 96 const char *cp = envp[i] + namelen; 97 if (*cp == '=') 98 return cp + 1; 99 } 100 } 101 } 102 return NULL; 103} 104 105/* used for safe printf of possible NULL strings */ 106static const char * 107np (const char *str) 108{ 109 if (str) 110 return str; 111 else 112 return "[NULL]"; 113} 114 115static int 116atoi_null0 (const char *str) 117{ 118 if (str) 119 return atoi (str); 120 else 121 return 0; 122} 123 124OPENVPN_EXPORT openvpn_plugin_handle_t 125openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) 126{ 127 struct plugin_context *context; 128 129 printf ("FUNC: openvpn_plugin_open_v1\n"); 130 131 /* 132 * Allocate our context 133 */ 134 context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context)); 135 136 context->test_deferred_auth = atoi_null0 (get_env ("test_deferred_auth", envp)); 137 printf ("TEST_DEFERRED_AUTH %d\n", context->test_deferred_auth); 138 139 context->test_packet_filter = atoi_null0 (get_env ("test_packet_filter", envp)); 140 printf ("TEST_PACKET_FILTER %d\n", context->test_packet_filter); 141 142 /* 143 * Which callbacks to intercept. 144 */ 145 *type_mask = 146 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | 147 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) | 148 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) | 149 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) | 150 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) | 151 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) | 152 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | 153 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) | 154 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) | 155 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL) | 156 OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); 157 158 return (openvpn_plugin_handle_t) context; 159} 160 161static int 162auth_user_pass_verify (struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[]) 163{ 164 if (context->test_deferred_auth) 165 { 166 /* get username/password from envp string array */ 167 const char *username = get_env ("username", envp); 168 const char *password = get_env ("password", envp); 169 170 /* get auth_control_file filename from envp string array*/ 171 const char *auth_control_file = get_env ("auth_control_file", envp); 172 173 printf ("DEFER u='%s' p='%s' acf='%s'\n", 174 np(username), 175 np(password), 176 np(auth_control_file)); 177 178 /* Authenticate asynchronously in n seconds */ 179 if (auth_control_file) 180 { 181 char buf[256]; 182 int auth = 2; 183 sscanf (username, "%d", &auth); 184 snprintf (buf, sizeof(buf), "( sleep %d ; echo AUTH %s %d ; echo %d >%s ) &", 185 context->test_deferred_auth, 186 auth_control_file, 187 auth, 188 pcc->n_calls < auth, 189 auth_control_file); 190 printf ("%s\n", buf); 191 system (buf); 192 pcc->n_calls++; 193 return OPENVPN_PLUGIN_FUNC_DEFERRED; 194 } 195 else 196 return OPENVPN_PLUGIN_FUNC_ERROR; 197 } 198 else 199 return OPENVPN_PLUGIN_FUNC_SUCCESS; 200} 201 202static int 203tls_final (struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[]) 204{ 205 if (context->test_packet_filter) 206 { 207 if (!pcc->generated_pf_file) 208 { 209 const char *pff = get_env ("pf_file", envp); 210 const char *cn = get_env ("username", envp); 211 if (pff && cn) 212 { 213 char buf[256]; 214 snprintf (buf, sizeof(buf), "( sleep %d ; echo PF %s/%s ; cp \"%s.pf\" \"%s\" ) &", 215 context->test_packet_filter, cn, pff, cn, pff); 216 printf ("%s\n", buf); 217 system (buf); 218 pcc->generated_pf_file = true; 219 return OPENVPN_PLUGIN_FUNC_SUCCESS; 220 } 221 else 222 return OPENVPN_PLUGIN_FUNC_ERROR; 223 } 224 else 225 return OPENVPN_PLUGIN_FUNC_ERROR; 226 } 227 else 228 return OPENVPN_PLUGIN_FUNC_SUCCESS; 229} 230 231OPENVPN_EXPORT int 232openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, 233 const int type, 234 const char *argv[], 235 const char *envp[], 236 void *per_client_context, 237 struct openvpn_plugin_string_list **return_list) 238{ 239 struct plugin_context *context = (struct plugin_context *) handle; 240 struct plugin_per_client_context *pcc = (struct plugin_per_client_context *) per_client_context; 241 switch (type) 242 { 243 case OPENVPN_PLUGIN_UP: 244 printf ("OPENVPN_PLUGIN_UP\n"); 245 return OPENVPN_PLUGIN_FUNC_SUCCESS; 246 case OPENVPN_PLUGIN_DOWN: 247 printf ("OPENVPN_PLUGIN_DOWN\n"); 248 return OPENVPN_PLUGIN_FUNC_SUCCESS; 249 case OPENVPN_PLUGIN_ROUTE_UP: 250 printf ("OPENVPN_PLUGIN_ROUTE_UP\n"); 251 return OPENVPN_PLUGIN_FUNC_SUCCESS; 252 case OPENVPN_PLUGIN_IPCHANGE: 253 printf ("OPENVPN_PLUGIN_IPCHANGE\n"); 254 return OPENVPN_PLUGIN_FUNC_SUCCESS; 255 case OPENVPN_PLUGIN_TLS_VERIFY: 256 printf ("OPENVPN_PLUGIN_TLS_VERIFY\n"); 257 return OPENVPN_PLUGIN_FUNC_SUCCESS; 258 case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: 259 printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n"); 260 return auth_user_pass_verify (context, pcc, argv, envp); 261 case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: 262 printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n"); 263 return OPENVPN_PLUGIN_FUNC_SUCCESS; 264 case OPENVPN_PLUGIN_CLIENT_DISCONNECT: 265 printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n"); 266 return OPENVPN_PLUGIN_FUNC_SUCCESS; 267 case OPENVPN_PLUGIN_LEARN_ADDRESS: 268 printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n"); 269 return OPENVPN_PLUGIN_FUNC_SUCCESS; 270 case OPENVPN_PLUGIN_TLS_FINAL: 271 printf ("OPENVPN_PLUGIN_TLS_FINAL\n"); 272 return tls_final (context, pcc, argv, envp); 273 case OPENVPN_PLUGIN_ENABLE_PF: 274 printf ("OPENVPN_PLUGIN_ENABLE_PF\n"); 275 if (context->test_packet_filter) 276 return OPENVPN_PLUGIN_FUNC_SUCCESS; 277 else 278 return OPENVPN_PLUGIN_FUNC_ERROR; 279 default: 280 printf ("OPENVPN_PLUGIN_?\n"); 281 return OPENVPN_PLUGIN_FUNC_ERROR; 282 } 283} 284 285OPENVPN_EXPORT void * 286openvpn_plugin_client_constructor_v1 (openvpn_plugin_handle_t handle) 287{ 288 printf ("FUNC: openvpn_plugin_client_constructor_v1\n"); 289 return calloc (1, sizeof (struct plugin_per_client_context)); 290} 291 292OPENVPN_EXPORT void 293openvpn_plugin_client_destructor_v1 (openvpn_plugin_handle_t handle, void *per_client_context) 294{ 295 printf ("FUNC: openvpn_plugin_client_destructor_v1\n"); 296 free (per_client_context); 297} 298 299OPENVPN_EXPORT void 300openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) 301{ 302 struct plugin_context *context = (struct plugin_context *) handle; 303 printf ("FUNC: openvpn_plugin_close_v1\n"); 304 free (context); 305} 306