simple.c 9.7 KB

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