Go to the documentation of this file.
33 #include <security/pam_appl.h>
44 #include <sys/types.h>
45 #include <sys/socket.h>
52 #include <arpa/inet.h>
55 #define DEBUG(verb) ((verb) >= 4)
58 #define COMMAND_VERIFY 0
59 #define COMMAND_EXIT 1
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
141 const ssize_t size =
read(fd, &c,
sizeof(c));
142 if (size ==
sizeof(c))
156 unsigned char c = (
unsigned char) code;
157 const ssize_t size =
write(fd, &c,
sizeof(c));
158 if (size ==
sizeof(c))
188 const int len = strlen(
string) + 1;
189 const ssize_t size =
write(fd,
string,
len);
210 const char *daemon_string =
get_env(
"daemon", envp);
211 if (daemon_string && daemon_string[0] ==
'1')
213 const char *log_redirect =
get_env(
"daemon_log_redirect", envp);
215 if (log_redirect && log_redirect[0] ==
'1')
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)
271 signal(SIGTERM, SIG_DFL);
273 signal(SIGINT, SIG_IGN);
274 signal(SIGHUP, SIG_IGN);
275 signal(SIGUSR1, SIG_IGN);
276 signal(SIGUSR2, SIG_IGN);
277 signal(SIGPIPE, SIG_IGN);
286 while (!isalnum(*query))
294 return strncasecmp(match, query, strlen(match)) == 0;
305 const int skip = strlen(
"SCRV1:");
306 if (strncmp(up->
password,
"SCRV1:", skip) != 0)
318 char *pass = tmp + skip;
319 char *resp = strchr(pass,
':');
368 const int base_parms = 2;
371 const char **envp = args->
envp;
376 fprintf(stderr,
"AUTH-PAM: This plugin is incompatible with the running version of OpenVPN\n");
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)
485 context->foreground_fd = 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)
609 if (
context->foreground_fd >= 0)
618 if (
context->background_pid > 0)
620 waitpid(
context->background_pid, NULL, 0);
648 my_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;
678 msg->msg ?
msg->msg :
"NULL",
689 for (j = 0; j < list->
len; ++j)
691 const char *match_name = list->
data[j].
name;
692 const char *match_value = list->
data[j].
value;
697 aresp[i].resp = NULL;
707 if (strstr(match_value,
"USERNAME"))
711 else if (strstr(match_value,
"PASSWORD"))
715 else if (strstr(match_value,
"COMMONNAME"))
719 else if (strstr(match_value,
"OTP"))
725 aresp[i].resp = strdup(match_value);
728 if (aresp[i].resp == NULL)
744 switch (
msg->msg_style)
746 case PAM_PROMPT_ECHO_OFF:
747 aresp[i].resp = strdup(up->
password);
748 if (aresp[i].resp == NULL)
754 case PAM_PROMPT_ECHO_ON:
755 aresp[i].resp = strdup(up->
username);
756 if (aresp[i].resp == NULL)
773 if (ret == PAM_SUCCESS)
775 *response_array = aresp;
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)
829 pam_strerror(pamh,
status));
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];
922 #ifdef USE_PAM_DLOPEN
923 static const char pam_so[] =
"libpam.so";
934 #ifdef USE_PAM_DLOPEN
938 if (!dlopen_pam(pam_so))
962 memset(&up, 0,
sizeof(up));
980 ||
recv_string(fd, ac_file_name,
sizeof(ac_file_name)) == -1
1004 if (strlen(ac_file_name) > 0)
1050 #ifdef USE_PAM_DLOPEN
plugin_base64_decode_t plugin_base64_decode
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...
int string_array_len(const char **array)
plugin_secure_memzero_t plugin_secure_memzero
OPENVPN_EXPORT void openvpn_plugin_abort_v1(openvpn_plugin_handle_t handle)
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)
static const char * get_env(const char *name, const char *envp[])
Arguments used to transport variables to the plug-in.
Contains all state information for one tunnel.
char username[USER_PASS_LEN]
static void daemonize(const char *envp[])
#define OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
static int name_value_match(const char *query, const char *match)
void(* plugin_log_t)(openvpn_plugin_log_flags_t flags, const char *plugin_name, const char *format,...) _ovpn_chk_fmt(3
#define OPENVPN_PLUGIN_MASK(x)
static plugin_base64_decode_t plugin_base64_decode
#define RESPONSE_INIT_FAILED
#define OPENVPN_PLUGIN_FUNC_ERROR
static plugin_log_t plugin_log
int(* plugin_base64_decode_t)(const char *str, void *data, int size)
Export of openvpn_base64_decode() to be used inside plug-ins.
static int pam_auth(const char *service, const struct user_pass *up)
#define OPENVPN_PLUGIN_FUNC_DEFERRED
struct name_value data[N_NAME_VALUE]
static plugin_secure_memzero_t plugin_secure_memzero
Wrapper structure for dynamically allocated memory.
static int recv_control(int fd)
static int recv_string(int fd, char *buffer, int 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...
static int send_control(int fd, int code)
#define RESPONSE_VERIFY_FAILED
int daemon(int nochdir, int noclose)
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.
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 RESPONSE_VERIFY_SUCCEEDED
const struct name_value_list * name_value_list
static void pam_server(int fd, const char *service, int verb, const struct name_value_list *name_value_list)
static int send_string(int fd, const char *string)
static SERVICE_STATUS_HANDLE service
Arguments used to transport variables from the plug-in back to the OpenVPN process.
openvpn_plugin_handle_t handle
static SERVICE_STATUS status
static void close_fds_except(int keep)
#define OPENVPN_PLUGIN_FUNC_SUCCESS
char password[USER_PASS_LEN]
void * openvpn_plugin_handle_t
char remote[INET6_ADDRSTRLEN]
struct openvpn_plugin_callbacks * callbacks
static void set_signals(void)
static void split_scrv1_password(struct user_pass *up)
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...
#define RESPONSE_INIT_SUCCEEDED