summaryrefslogtreecommitdiff
path: root/duo_openvpn.c
diff options
context:
space:
mode:
Diffstat (limited to 'duo_openvpn.c')
-rw-r--r--duo_openvpn.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/duo_openvpn.c b/duo_openvpn.c
new file mode 100644
index 0000000..0486765
--- /dev/null
+++ b/duo_openvpn.c
@@ -0,0 +1,118 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include "openvpn-plugin.h"
+
+#define PYTHON "python"
+#define DUO_PATH "/opt/duo/duo_openvpn.py"
+
+struct context {
+ char *ikey;
+ char *skey;
+ char *host;
+};
+
+static const char *
+get_env(const char *name, const char *envp[])
+{
+ int i, namelen;
+ const char *cp;
+
+ if (envp) {
+ namelen = strlen(name);
+ for (i = 0; envp[i]; ++i) {
+ if (!strncmp(envp[i], name, namelen)) {
+ cp = envp[i] + namelen;
+ if (*cp == '=') {
+ return cp + 1;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+static int
+auth_user_pass_verify(struct context *ctx, const char *args[], const char *envp[])
+{
+ int pid;
+ const char *control, *username, *password, *ipaddr;
+ char *argv[] = { PYTHON, DUO_PATH, NULL };
+
+ control = get_env("auth_control_file", envp);
+ username = get_env("common_name", envp);
+ password = get_env("password", envp);
+ ipaddr = get_env("untrusted_ip", envp);
+
+ if (!control || !username || !password || !ipaddr) {
+ return OPENVPN_PLUGIN_FUNC_ERROR;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ return OPENVPN_PLUGIN_FUNC_ERROR;
+ }
+
+ if (pid == 0) {
+ if (ctx->ikey && ctx->skey && ctx->host) {
+ setenv("ikey", ctx->ikey, 1);
+ setenv("skey", ctx->skey, 1);
+ setenv("host", ctx->host, 1);
+ }
+
+ setenv("control", control, 1);
+ setenv("username", username, 1);
+ setenv("password", password, 1);
+ setenv("ipaddr", ipaddr, 1);
+
+ execvp(argv[0], argv);
+ exit(1);
+ }
+
+ return OPENVPN_PLUGIN_FUNC_DEFERRED;
+}
+
+OPENVPN_EXPORT int
+openvpn_plugin_func_v2(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[], void *per_client_context, struct openvpn_plugin_string_list **return_list)
+{
+ struct context *ctx = (struct context *) handle;
+
+ if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) {
+ return auth_user_pass_verify(ctx, argv, envp);
+ } else {
+ return OPENVPN_PLUGIN_FUNC_ERROR;
+ }
+}
+
+OPENVPN_EXPORT openvpn_plugin_handle_t
+openvpn_plugin_open_v2(unsigned int *type_mask, const char *argv[], const char *envp[], struct openvpn_plugin_string_list **return_list)
+{
+ struct context *ctx;
+
+ ctx = (struct context *) calloc(1, sizeof(struct context));
+
+ if (argv[1] && argv[2] && argv[3]) {
+ ctx->ikey = strdup(argv[1]);
+ ctx->skey = strdup(argv[2]);
+ ctx->host = strdup(argv[3]);
+ }
+
+ *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY);
+
+ return (openvpn_plugin_handle_t) ctx;
+}
+
+OPENVPN_EXPORT void
+openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
+{
+ struct context *ctx = (struct context *) handle;
+
+ free(ctx->ikey);
+ free(ctx->skey);
+ free(ctx->host);
+ free(ctx);
+}