ext-auth: Add an ext-auth plugin invoking an external authorization script
Original patch courtesy of Vyronas Tsingaras.
This commit is contained in:
parent
6890bdc7a0
commit
b2c1973ffb
|
@ -45,6 +45,7 @@ plugins = \
|
|||
plugins/eap-tnc.opt \
|
||||
plugins/eap-ttls.opt \
|
||||
plugins/error-notify.opt \
|
||||
plugins/ext-auth.opt \
|
||||
plugins/gcrypt.opt \
|
||||
plugins/ha.opt \
|
||||
plugins/imc-attestation.opt \
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
charon.plugins.ext-auth.script =
|
||||
Shell script to invoke for peer authorization.
|
||||
|
||||
Command to pass to the system shell for peer authorization. Authorization
|
||||
is considered successful if the command executes normally with an exit code
|
||||
of zero. For all other exit codes IKE_SA authorization is rejected.
|
||||
|
||||
The following environment variables get passed to the script:
|
||||
_IKE_UNIQUE_ID_: The IKE_SA numerical unique identifier.
|
||||
_IKE_NAME_: The peer configuration connection name.
|
||||
_IKE_LOCAL_HOST_: Local IKE IP address.
|
||||
_IKE_REMOTE_HOST_: Remote IKE IP address.
|
||||
_IKE_LOCAL_ID_: Local IKE identity.
|
||||
_IKE_REMOTE_ID_: Remote IKE identity.
|
||||
_IKE_REMOTE_EAP_ID_: Remote EAP or XAuth identity, if used.
|
|
@ -189,6 +189,7 @@ ARG_ENABL_SET([eap-peap], [enable EAP PEAP authentication module.])
|
|||
ARG_ENABL_SET([eap-tnc], [enable EAP TNC trusted network connect module.])
|
||||
ARG_ENABL_SET([eap-dynamic], [enable dynamic EAP proxy module.])
|
||||
ARG_ENABL_SET([eap-radius], [enable RADIUS proxy authentication module.])
|
||||
ARG_ENABL_SET([ext-auth], [enable plugin calling an external authorization script.])
|
||||
ARG_ENABL_SET([ipseckey], [enable IPSECKEY authentication plugin.])
|
||||
ARG_ENABL_SET([keychain], [enables OS X Keychain Services credential set.])
|
||||
ARG_ENABL_SET([pkcs11], [enables the PKCS11 token support plugin.])
|
||||
|
@ -1285,6 +1286,7 @@ ADD_PLUGIN([android-dns], [c charon])
|
|||
ADD_PLUGIN([android-log], [c charon])
|
||||
ADD_PLUGIN([ha], [c charon])
|
||||
ADD_PLUGIN([whitelist], [c charon])
|
||||
ADD_PLUGIN([ext-auth], [c charon])
|
||||
ADD_PLUGIN([lookip], [c charon])
|
||||
ADD_PLUGIN([error-notify], [c charon])
|
||||
ADD_PLUGIN([certexpire], [c charon])
|
||||
|
@ -1396,6 +1398,7 @@ AM_CONDITIONAL(USE_KERNEL_LIBIPSEC, test x$kernel_libipsec = xtrue)
|
|||
AM_CONDITIONAL(USE_KERNEL_WFP, test x$kernel_wfp = xtrue)
|
||||
AM_CONDITIONAL(USE_KERNEL_IPH, test x$kernel_iph = xtrue)
|
||||
AM_CONDITIONAL(USE_WHITELIST, test x$whitelist = xtrue)
|
||||
AM_CONDITIONAL(USE_EXT_AUTH, test x$ext_auth = xtrue)
|
||||
AM_CONDITIONAL(USE_LOOKIP, test x$lookip = xtrue)
|
||||
AM_CONDITIONAL(USE_ERROR_NOTIFY, test x$error_notify = xtrue)
|
||||
AM_CONDITIONAL(USE_CERTEXPIRE, test x$certexpire = xtrue)
|
||||
|
@ -1695,6 +1698,7 @@ AC_CONFIG_FILES([
|
|||
src/libcharon/plugins/kernel_wfp/Makefile
|
||||
src/libcharon/plugins/kernel_iph/Makefile
|
||||
src/libcharon/plugins/whitelist/Makefile
|
||||
src/libcharon/plugins/ext_auth/Makefile
|
||||
src/libcharon/plugins/lookip/Makefile
|
||||
src/libcharon/plugins/error_notify/Makefile
|
||||
src/libcharon/plugins/certexpire/Makefile
|
||||
|
|
|
@ -258,6 +258,13 @@ if MONOLITHIC
|
|||
endif
|
||||
endif
|
||||
|
||||
if USE_EXT_AUTH
|
||||
SUBDIRS += plugins/ext_auth
|
||||
if MONOLITHIC
|
||||
libcharon_la_LIBADD += plugins/ext_auth/libstrongswan-ext-auth.la
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_EAP_IDENTITY
|
||||
SUBDIRS += plugins/eap_identity
|
||||
if MONOLITHIC
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/libstrongswan \
|
||||
-I$(top_srcdir)/src/libhydra \
|
||||
-I$(top_srcdir)/src/libcharon
|
||||
|
||||
AM_CFLAGS = \
|
||||
$(PLUGIN_CFLAGS)
|
||||
|
||||
if MONOLITHIC
|
||||
noinst_LTLIBRARIES = libstrongswan-ext-auth.la
|
||||
else
|
||||
plugin_LTLIBRARIES = libstrongswan-ext-auth.la
|
||||
endif
|
||||
|
||||
libstrongswan_ext_auth_la_SOURCES = ext_auth_plugin.h ext_auth_plugin.c \
|
||||
ext_auth_listener.h ext_auth_listener.c
|
||||
|
||||
libstrongswan_ext_auth_la_LDFLAGS = -module -avoid-version
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Vyronas Tsingaras (vtsingaras@it.auth.gr)
|
||||
* Copyright (C) 2014 Martin Willi
|
||||
* Copyright (C) 2014 revosec AG
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* for vasprintf() */
|
||||
#define _GNU_SOURCE
|
||||
#include "ext_auth_listener.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <utils/process.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct private_ext_auth_listener_t private_ext_auth_listener_t;
|
||||
|
||||
/**
|
||||
* Private data of an ext_auth_listener_t object.
|
||||
*/
|
||||
struct private_ext_auth_listener_t {
|
||||
|
||||
/**
|
||||
* Public ext_auth_listener_listener_t interface.
|
||||
*/
|
||||
ext_auth_listener_t public;
|
||||
|
||||
/**
|
||||
* Path to authorization program
|
||||
*/
|
||||
char *script;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate and push a format string to the environment
|
||||
*/
|
||||
static bool push_env(char *envp[], u_int count, char *fmt, ...)
|
||||
{
|
||||
int i = 0;
|
||||
char *str;
|
||||
va_list args;
|
||||
|
||||
while (envp[i])
|
||||
{
|
||||
if (++i + 1 >= count)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
va_start(args, fmt);
|
||||
if (vasprintf(&str, fmt, args) >= 0)
|
||||
{
|
||||
envp[i] = str;
|
||||
}
|
||||
va_end(args);
|
||||
return envp[i] != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free all allocated environment strings
|
||||
*/
|
||||
static void free_env(char *envp[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; envp[i]; i++)
|
||||
{
|
||||
free(envp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(listener_t, authorize, bool,
|
||||
private_ext_auth_listener_t *this, ike_sa_t *ike_sa,
|
||||
bool final, bool *success)
|
||||
{
|
||||
if (final)
|
||||
{
|
||||
FILE *shell;
|
||||
process_t *process;
|
||||
char *envp[32] = {};
|
||||
int out, retval;
|
||||
|
||||
*success = FALSE;
|
||||
|
||||
push_env(envp, countof(envp), "IKE_UNIQUE_ID=%u",
|
||||
ike_sa->get_unique_id(ike_sa));
|
||||
push_env(envp, countof(envp), "IKE_NAME=%s",
|
||||
ike_sa->get_name(ike_sa));
|
||||
|
||||
push_env(envp, countof(envp), "IKE_LOCAL_HOST=%H",
|
||||
ike_sa->get_my_host(ike_sa));
|
||||
push_env(envp, countof(envp), "IKE_REMOTE_HOST=%H",
|
||||
ike_sa->get_other_host(ike_sa));
|
||||
|
||||
push_env(envp, countof(envp), "IKE_LOCAL_ID=%Y",
|
||||
ike_sa->get_my_id(ike_sa));
|
||||
push_env(envp, countof(envp), "IKE_REMOTE_ID=%Y",
|
||||
ike_sa->get_other_id(ike_sa));
|
||||
|
||||
if (ike_sa->has_condition(ike_sa, COND_EAP_AUTHENTICATED) ||
|
||||
ike_sa->has_condition(ike_sa, COND_XAUTH_AUTHENTICATED))
|
||||
{
|
||||
push_env(envp, countof(envp), "IKE_REMOTE_EAP_ID=%Y",
|
||||
ike_sa->get_other_eap_id(ike_sa));
|
||||
}
|
||||
|
||||
process = process_start_shell(envp, NULL, &out, NULL,
|
||||
"2>&1 %s", this->script);
|
||||
if (process)
|
||||
{
|
||||
shell = fdopen(out, "r");
|
||||
if (shell)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
char resp[128], *e;
|
||||
|
||||
if (fgets(resp, sizeof(resp), shell) == NULL)
|
||||
{
|
||||
if (ferror(shell))
|
||||
{
|
||||
DBG1(DBG_CFG, "error reading from ext-auth script");
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
e = resp + strlen(resp);
|
||||
if (e > resp && e[-1] == '\n')
|
||||
{
|
||||
e[-1] = '\0';
|
||||
}
|
||||
DBG1(DBG_CHD, "ext-auth: %s", resp);
|
||||
}
|
||||
}
|
||||
fclose(shell);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(out);
|
||||
}
|
||||
if (process->wait(process, &retval))
|
||||
{
|
||||
if (retval == EXIT_SUCCESS)
|
||||
{
|
||||
*success = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, "rejecting IKE_SA for ext-auth result: %d",
|
||||
retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
free_env(envp);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(ext_auth_listener_t, destroy, void,
|
||||
private_ext_auth_listener_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
ext_auth_listener_t *ext_auth_listener_create(char *script)
|
||||
{
|
||||
private_ext_auth_listener_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.listener = {
|
||||
.authorize = _authorize,
|
||||
},
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.script = script,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Vyronas Tsingaras (vtsingaras@it.auth.gr)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ext_auth_listener ext_auth_listener
|
||||
* @{ @ingroup ext_auth
|
||||
*/
|
||||
|
||||
#ifndef EXT_AUTH_LISTENER_H_
|
||||
#define EXT_AUTH_LISTENER_H_
|
||||
|
||||
#include <bus/listeners/listener.h>
|
||||
|
||||
typedef struct ext_auth_listener_t ext_auth_listener_t;
|
||||
|
||||
/**
|
||||
* Listener using an external script to authorize connection
|
||||
*/
|
||||
struct ext_auth_listener_t {
|
||||
|
||||
/**
|
||||
* Implements listener_t interface.
|
||||
*/
|
||||
listener_t listener;
|
||||
|
||||
/**
|
||||
* Destroy the listener.
|
||||
*/
|
||||
void (*destroy)(ext_auth_listener_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create ext_auth_listener instance.
|
||||
*
|
||||
* @param script path to authorization script
|
||||
* @return listener instance
|
||||
*/
|
||||
ext_auth_listener_t *ext_auth_listener_create(char *script);
|
||||
|
||||
#endif /** ext_auth_LISTENER_H_ @}*/
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Vyronas Tsingaras (vtsingaras@it.auth.gr)
|
||||
* Copyright (C) 2014 Martin Willi
|
||||
* Copyright (C) 2014 revosec AG
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ext_auth_plugin.h"
|
||||
#include "ext_auth_listener.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
typedef struct private_ext_auth_plugin_t private_ext_auth_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of ext_auth plugin
|
||||
*/
|
||||
struct private_ext_auth_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
ext_auth_plugin_t public;
|
||||
|
||||
/**
|
||||
* Listener verifying peers during authorization
|
||||
*/
|
||||
ext_auth_listener_t *listener;
|
||||
};
|
||||
|
||||
METHOD(plugin_t, get_name, char*,
|
||||
private_ext_auth_plugin_t *this)
|
||||
{
|
||||
return "ext-auth";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a listener instance, NULL on error
|
||||
*/
|
||||
static ext_auth_listener_t* create_listener()
|
||||
{
|
||||
char *script;
|
||||
|
||||
script = lib->settings->get_str(lib->settings,
|
||||
"%s.plugins.ext-auth.script", NULL, lib->ns);
|
||||
if (!script)
|
||||
{
|
||||
DBG1(DBG_CFG, "no script for ext-auth script defined, disabled");
|
||||
return NULL;
|
||||
}
|
||||
DBG1(DBG_CFG, "using ext-auth script '%s'", script);
|
||||
return ext_auth_listener_create(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register listener
|
||||
*/
|
||||
static bool plugin_cb(private_ext_auth_plugin_t *this,
|
||||
plugin_feature_t *feature, bool reg, void *cb_data)
|
||||
{
|
||||
if (reg)
|
||||
{
|
||||
this->listener = create_listener();
|
||||
if (!this->listener)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
charon->bus->add_listener(charon->bus, &this->listener->listener);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->listener)
|
||||
{
|
||||
charon->bus->remove_listener(charon->bus, &this->listener->listener);
|
||||
this->listener->destroy(this->listener);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(plugin_t, get_features, int,
|
||||
private_ext_auth_plugin_t *this, plugin_feature_t *features[])
|
||||
{
|
||||
static plugin_feature_t f[] = {
|
||||
PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
|
||||
PLUGIN_PROVIDE(CUSTOM, "ext_auth"),
|
||||
};
|
||||
*features = f;
|
||||
return countof(f);
|
||||
}
|
||||
|
||||
|
||||
METHOD(plugin_t, reload, bool,
|
||||
private_ext_auth_plugin_t *this)
|
||||
{
|
||||
ext_auth_listener_t *listener;
|
||||
|
||||
/* reload new listener overlapped */
|
||||
listener = create_listener();
|
||||
if (listener)
|
||||
{
|
||||
charon->bus->add_listener(charon->bus, &listener->listener);
|
||||
}
|
||||
if (this->listener)
|
||||
{
|
||||
charon->bus->remove_listener(charon->bus, &this->listener->listener);
|
||||
this->listener->destroy(this->listener);
|
||||
}
|
||||
this->listener = listener;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(plugin_t, destroy, void,
|
||||
private_ext_auth_plugin_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin constructor
|
||||
*/
|
||||
plugin_t *ext_auth_plugin_create()
|
||||
{
|
||||
private_ext_auth_plugin_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.plugin = {
|
||||
.get_name = _get_name,
|
||||
.get_features = _get_features,
|
||||
.reload = _reload,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Vyronas Tsingaras (vtsingaras@it.auth.gr)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ext_auth ext_auth
|
||||
* @ingroup cplugins
|
||||
*
|
||||
* @defgroup ext_auth_plugin ext_auth_plugin
|
||||
* @{ @ingroup ext_auth
|
||||
*/
|
||||
|
||||
#ifndef EXT_AUTH_PLUGIN_H_
|
||||
#define EXT_AUTH_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct ext_auth_plugin_t ext_auth_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin using an external script to authorize connections.
|
||||
*/
|
||||
struct ext_auth_plugin_t {
|
||||
|
||||
/**
|
||||
* Implements plugin interface.
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
#endif /** EXT_AUTH_PLUGIN_H_ @}*/
|
Loading…
Reference in New Issue