33#include <security/pam_appl.h>
45#include <sys/socket.h>
53#include <openvpn-plugin.h>
55#define DEBUG(verb) ((verb) >= 4)
58#define COMMAND_VERIFY 0
62#define RESPONSE_INIT_SUCCEEDED 10
63#define RESPONSE_INIT_FAILED 11
64#define RESPONSE_VERIFY_SUCCEEDED 12
65#define RESPONSE_VERIFY_FAILED 13
66#define RESPONSE_DEFER 14
101#define N_NAME_VALUE 16
142 if (size ==
sizeof(
c))
158 if (size ==
sizeof(
c))
219#if defined(__APPLE__) && defined(__clang__)
220#pragma clang diagnostic push
221#pragma clang diagnostic ignored "-Wdeprecated-declarations"
227#if defined(__APPLE__) && defined(__clang__)
228#pragma clang diagnostic pop
255 for (
i = 3;
i <= 100; ++
i)
376 fprintf(
stderr,
"AUTH-PAM: This plugin is incompatible with the running version of OpenVPN\n");
393 ret->type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY);
429 const int base = base_parms + i * 2;
439 const char *verb_string =
get_env(
"verb", envp);
442 context->verb = atoi(verb_string);
450 if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
476 if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0)
478 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"Set FD_CLOEXEC flag on socket file descriptor failed");
485 context->foreground_fd = fd[0];
486 ret->handle = (openvpn_plugin_handle_t *)
context;
488 return OPENVPN_PLUGIN_FUNC_SUCCESS;
519 return OPENVPN_PLUGIN_FUNC_ERROR;
527 if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY &&
context->foreground_fd >= 0)
530 const char *username =
get_env(
"username", envp);
531 const char *password =
get_env(
"password", envp);
532 const char *common_name =
get_env(
"common_name", envp) ?
get_env(
"common_name", envp) :
"";
533 const char *remote =
get_env(
"untrusted_ip6", envp);
537 remote =
get_env(
"untrusted_ip", envp);
548 const char *auth_control_file =
get_env(
"auth_control_file", envp);
549 const char *deferred_auth_pam =
get_env(
"deferred_auth_pam", envp);
550 if (auth_control_file != NULL && deferred_auth_pam != NULL)
560 auth_control_file =
"";
563 if (username && strlen(username) > 0 && password)
572 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"Error sending auth info to background process");
579 return OPENVPN_PLUGIN_FUNC_SUCCESS;
587 return OPENVPN_PLUGIN_FUNC_DEFERRED;
591 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"Error receiving auth confirmation from background process");
596 return OPENVPN_PLUGIN_FUNC_ERROR;
609 if (
context->foreground_fd >= 0)
614 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"Error signaling background process to exit");
618 if (
context->background_pid > 0)
620 waitpid(
context->background_pid, NULL, 0);
648my_conv(
int n,
const struct pam_message **msg_array,
649 struct pam_response **response_array,
void *appdata_ptr)
652 struct pam_response *aresp;
654 int ret = PAM_SUCCESS;
656 *response_array = NULL;
658 if (n <= 0 || n > PAM_MAX_NUM_MSG)
660 return (PAM_CONV_ERR);
662 if ((aresp = calloc(n,
sizeof *aresp)) == NULL)
664 return (PAM_BUF_ERR);
668 for (i = 0; i < n; ++i)
670 const struct pam_message *
msg = msg_array[i];
671 aresp[i].resp_retcode = 0;
672 aresp[i].resp = NULL;
676 plugin_log(PLOG_NOTE,
MODULE,
"BACKGROUND: my_conv[%d] query='%s' style=%d",
678 msg->msg ?
msg->msg :
"NULL",
689 for (
j = 0;
j < list->
len; ++
j)
744 switch (
msg->msg_style)
793 struct pam_conv conv;
794 pam_handle_t *pamh = NULL;
801 conv.appdata_ptr = (
void *)up;
803 if (
status == PAM_SUCCESS)
811 if (
status == PAM_SUCCESS)
813 status = pam_authenticate(pamh, 0);
815 if (
status == PAM_SUCCESS)
817 status = pam_acct_mgmt(pamh, 0);
819 if (
status == PAM_SUCCESS)
827 plugin_log(PLOG_ERR,
MODULE,
"BACKGROUND: user '%s' failed to authenticate: %s",
829 pam_strerror(pamh,
status));
855 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"BACKGROUND: write error on response socket [4]");
869 waitpid(p1, NULL, 0);
893 int ac_fd = open( ac_file_name, O_WRONLY );
902 if (
write( ac_fd, pam_success ?
"1" :
"0", 1 ) != 1)
909 up->
username, 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, dlerror());
951 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"BACKGROUND: write error on response socket [1]");
962 memset(&up, 0,
sizeof(up));
971 plugin_log(PLOG_NOTE,
MODULE,
"BACKGROUND: received command code: %d", command);
980 ||
recv_string(fd, ac_file_name,
sizeof(ac_file_name)) == -1
983 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"BACKGROUND: read error on command channel: code=%d, exiting",
1004 if (strlen(ac_file_name) > 0)
1018 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"BACKGROUND: write error on response socket [2]");
1026 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"BACKGROUND: write error on response socket [3]");
1037 plugin_log(PLOG_ERR|PLOG_ERRNO,
MODULE,
"BACKGROUND: read error on command channel");
1041 plugin_log(PLOG_ERR,
MODULE,
"BACKGROUND: unknown command code: code=%d, exiting",
1050#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)
static int send_string(int fd, const char *string)
#define RESPONSE_INIT_SUCCEEDED
static plugin_secure_memzero_t plugin_secure_memzero
static int my_conv(int n, const struct pam_message **msg_array, struct pam_response **response_array, void *appdata_ptr)
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 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 recv_string(int fd, char *buffer, int 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...