32#include <security/pam_appl.h>
44#include <sys/socket.h>
52#include <openvpn-plugin.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)
378 "AUTH-PAM: This plugin is incompatible with the running version of OpenVPN\n");
395 ret->type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY);
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];
489 ret->handle = (openvpn_plugin_handle_t *)
context;
491 return OPENVPN_PLUGIN_FUNC_SUCCESS;
522 return OPENVPN_PLUGIN_FUNC_ERROR;
531 if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY &&
context->foreground_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");
583 return OPENVPN_PLUGIN_FUNC_SUCCESS;
591 return OPENVPN_PLUGIN_FUNC_DEFERRED;
596 "Error receiving auth confirmation from background process");
601 return OPENVPN_PLUGIN_FUNC_ERROR;
614 if (
context->foreground_fd >= 0)
619 plugin_log(PLOG_ERR | PLOG_ERRNO,
MODULE,
"Error signaling background process to exit");
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)
830 plugin_log(PLOG_ERR,
MODULE,
"BACKGROUND: user '%s' failed to authenticate: %s",
857 plugin_log(PLOG_ERR | PLOG_ERRNO,
MODULE,
"BACKGROUND: write error on response socket [4]");
871 waitpid(p1, NULL, 0);
895 int ac_fd = open(ac_file_name, O_WRONLY);
898 plugin_log(PLOG_ERR | PLOG_ERRNO,
MODULE,
"cannot open '%s' for writing", ac_file_name);
903 if (
write(ac_fd, pam_success ?
"1" :
"0", 1) != 1)
905 plugin_log(PLOG_ERR | PLOG_ERRNO,
MODULE,
"cannot write to '%s'", ac_file_name);
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))
940 plugin_log(PLOG_ERR,
MODULE,
"BACKGROUND: could not load PAM lib %s: %s", pam_so,
952 plugin_log(PLOG_ERR | PLOG_ERRNO,
MODULE,
"BACKGROUND: write error on response socket [1]");
963 memset(&up, 0,
sizeof(up));
972 plugin_log(PLOG_NOTE,
MODULE,
"BACKGROUND: received command code: %d", command);
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");
1046 plugin_log(PLOG_ERR,
MODULE,
"BACKGROUND: unknown command code: code=%d, exiting",
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[])
static void set_signals(void)
OPENVPN_EXPORT void openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
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)
#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
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]
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...