32#include <security/pam_appl.h>
44#include <sys/socket.h>
54#define DEBUG(verb) ((verb) >= 4)
57#define COMMAND_VERIFY 0
61#define RESPONSE_INIT_SUCCEEDED 10
62#define RESPONSE_INIT_FAILED 11
63#define RESPONSE_VERIFY_SUCCEEDED 12
64#define RESPONSE_VERIFY_FAILED 13
65#define RESPONSE_DEFER 14
100#define N_NAME_VALUE 16
145 if (size ==
sizeof(
c))
161 if (size ==
sizeof(
c))
221#if defined(__APPLE__) && defined(__clang__)
222#pragma clang diagnostic push
223#pragma clang diagnostic ignored "-Wdeprecated-declarations"
229#if defined(__APPLE__) && defined(__clang__)
230#pragma clang diagnostic pop
257 for (
i = 3;
i <= 100; ++
i)
372 const char **envp =
args->envp;
378 "AUTH-PAM: This plugin is incompatible with the running version of OpenVPN\n");
431 const int base = base_parms +
i * 2;
441 const char *verb_string =
get_env(
"verb", envp);
444 context->verb = atoi(verb_string);
452 if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
478 if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0)
481 "Set FD_CLOEXEC flag on socket file descriptor failed");
488 context->foreground_fd = fd[0];
534 const char *username =
get_env(
"username", envp);
535 const char *password =
get_env(
"password", envp);
536 const char *common_name =
get_env(
"common_name", envp) ?
get_env(
"common_name", envp) :
"";
537 const char *remote =
get_env(
"untrusted_ip6", envp);
541 remote =
get_env(
"untrusted_ip", envp);
552 const char *auth_control_file =
get_env(
"auth_control_file", envp);
553 const char *deferred_auth_pam =
get_env(
"deferred_auth_pam", envp);
554 if (auth_control_file != NULL && deferred_auth_pam != NULL)
563 auth_control_file =
"";
566 if (username && strlen(username) > 0 && password)
576 "Error sending auth info to background process");
596 "Error receiving auth confirmation from background process");
614 if (
context->foreground_fd >= 0)
623 if (
context->background_pid > 0)
625 waitpid(
context->background_pid, NULL, 0);
653my_conv(
int num_msg,
const struct pam_message **msg_array,
struct pam_response **response_array,
657 struct pam_response *aresp;
658 int ret = PAM_SUCCESS;
660 *response_array = NULL;
662 if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
664 return (PAM_CONV_ERR);
666 if ((aresp = calloc((
size_t)num_msg,
sizeof *aresp)) == NULL)
668 return (PAM_BUF_ERR);
672 for (
int i = 0;
i < num_msg; ++
i)
674 const struct pam_message *
msg = msg_array[
i];
675 aresp[
i].resp_retcode = 0;
676 aresp[
i].resp = NULL;
681 msg->msg ?
msg->msg :
"NULL",
msg->msg_style);
691 for (
j = 0;
j < list->
len; ++
j)
705 "BACKGROUND: name match found, query/match-string ['%s', '%s'] = '%s'",
747 switch (
msg->msg_style)
796 struct pam_conv conv;
797 pam_handle_t *pamh = NULL;
804 conv.appdata_ptr = (
void *)up;
806 if (
status == PAM_SUCCESS)
814 if (
status == PAM_SUCCESS)
816 status = pam_authenticate(pamh, 0);
818 if (
status == PAM_SUCCESS)
820 status = pam_acct_mgmt(pamh, 0);
822 if (
status == PAM_SUCCESS)
871 waitpid(p1, NULL, 0);
895 int ac_fd = open(ac_file_name, O_WRONLY);
903 if (
write(ac_fd, pam_success ?
"1" :
"0", 1) != 1)
909 pam_success ?
"succeeded" :
"rejected");
920 char ac_file_name[PATH_MAX];
923 static const char pam_so[] =
"libpam.so";
938 if (!dlopen_pam(pam_so))
963 memset(&up, 0,
sizeof(up));
981 ||
recv_string(fd, ac_file_name,
sizeof(ac_file_name)) == -1
985 "BACKGROUND: read error on command channel: code=%d, exiting",
1006 if (strlen(ac_file_name) > 0)
1021 "BACKGROUND: write error on response socket [2]");
1030 "BACKGROUND: write error on response socket [3]");
1042 "BACKGROUND: read error on command channel");
1055#ifdef USE_PAM_DLOPEN
OPENVPN_EXPORT int openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
This function is called by OpenVPN each time the OpenVPN reaches a point where plug-in calls should h...
static void set_signals(void)
OPENVPN_EXPORT void openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
This cleans up the last part of the plug-in, allows it to shut down cleanly and release the plug-in g...
static plugin_log_t plugin_log
static int pam_auth(const char *service, const struct user_pass *up)
static int name_value_match(const char *query, const char *match)
#define RESPONSE_INIT_SUCCEEDED
static plugin_secure_memzero_t plugin_secure_memzero
static void do_deferred_pam_auth(int fd, const char *ac_file_name, const char *service, const struct user_pass *up)
#define RESPONSE_INIT_FAILED
static ssize_t send_string(int fd, const char *string)
static plugin_base64_decode_t plugin_base64_decode
static void pam_server(int fd, const char *service, int verb, const struct name_value_list *name_value_list)
#define RESPONSE_VERIFY_FAILED
OPENVPN_EXPORT void openvpn_plugin_abort_v1(openvpn_plugin_handle_t handle)
static int recv_control(int fd)
static int send_control(int fd, int code)
static void close_fds_except(int keep)
OPENVPN_EXPORT int openvpn_plugin_open_v3(const int v3structver, struct openvpn_plugin_args_open_in const *args, struct openvpn_plugin_args_open_return *ret)
This function is called when OpenVPN loads the plug-in.
#define RESPONSE_VERIFY_SUCCEEDED
static int my_conv(int num_msg, const struct pam_message **msg_array, struct pam_response **response_array, void *appdata_ptr)
static ssize_t recv_string(int fd, char *buffer, size_t len)
static void split_scrv1_password(struct user_pass *up)
int string_array_len(const char **array)
int daemon(int nochdir, int noclose)
static void daemonize(const char *envp[])
static SERVICE_STATUS status
static SERVICE_STATUS_HANDLE service
#define OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
void * openvpn_plugin_handle_t
#define OPENVPN_PLUGIN_MASK(x)
void(* plugin_log_t)(openvpn_plugin_log_flags_t flags, const char *plugin_name, const char *format,...) _ovpn_chk_fmt(3
#define OPENVPN_PLUGIN_FUNC_DEFERRED
#define OPENVPN_PLUGIN_FUNC_SUCCESS
void(*) typedef void(*) typedef void(* plugin_secure_memzero_t)(void *data, size_t len)
Export of secure_memzero() to be used inside plug-ins.
#define OPENVPN_PLUGIN_FUNC_ERROR
int(* plugin_base64_decode_t)(const char *str, void *data, int size)
Export of openvpn_base64_decode() to be used inside plug-ins.
static const char * get_env(const char *name, const char *envp[])
Wrapper structure for dynamically allocated memory.
Contains all state information for one tunnel.
struct name_value data[N_NAME_VALUE]
Arguments used to transport variables to the plug-in.
struct openvpn_plugin_callbacks * callbacks
Arguments used to transport variables from the plug-in back to the OpenVPN process.
openvpn_plugin_handle_t handle
plugin_base64_decode_t plugin_base64_decode
plugin_secure_memzero_t plugin_secure_memzero
const struct name_value_list * name_value_list
char password[USER_PASS_LEN]
char remote[INET6_ADDRSTRLEN]
char username[USER_PASS_LEN]
char * searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith)
Read 'tosearch', replace all occurrences of 'searchfor' with 'replacewith' and return a pointer to th...