OpenVPN
auth-pam.c
Go to the documentation of this file.
1 /*
2  * OpenVPN -- An application to securely tunnel IP networks
3  * over a single TCP/UDP port, with support for SSL/TLS-based
4  * session authentication and key exchange,
5  * packet encryption, packet authentication, and
6  * packet compression.
7  *
8  * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
9  * Copyright (C) 2016-2018 Selva Nair <selva.nair@gmail.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2
13  * as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 
25 /*
26  * OpenVPN plugin module to do PAM authentication using a split
27  * privilege model.
28  */
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 #include <security/pam_appl.h>
34 
35 #ifdef USE_PAM_DLOPEN
36 #include "pamdl.h"
37 #endif
38 
39 #include <stdio.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <unistd.h>
43 #include <stdlib.h>
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <sys/wait.h>
47 #include <fcntl.h>
48 #include <signal.h>
49 #include <syslog.h>
50 #include "utils.h"
51 
52 #include <openvpn-plugin.h>
53 
54 #define DEBUG(verb) ((verb) >= 4)
55 
56 /* Command codes for foreground -> background communication */
57 #define COMMAND_VERIFY 0
58 #define COMMAND_EXIT 1
59 
60 /* Response codes for background -> foreground communication */
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 
66 /* Pointers to functions exported from openvpn */
68 static plugin_base64_decode_t plugin_base64_decode = NULL;
69 
70 /*
71  * Plugin state, used by foreground
72  */
74 {
75  /* Foreground's socket to background process */
77 
78  /* Process ID of background process */
80 
81  /* Verbosity level of OpenVPN */
82  int verb;
83 };
84 
85 /*
86  * Name/Value pairs for conversation function.
87  * Special Values:
88  *
89  * "USERNAME" -- substitute client-supplied username
90  * "PASSWORD" -- substitute client-specified password
91  * "COMMONNAME" -- substitute client certificate common name
92  * "OTP" -- substitute static challenge response if available
93  */
94 
95 #define N_NAME_VALUE 16
96 
97 struct name_value {
98  const char *name;
99  const char *value;
100 };
101 
103  int len;
104  struct name_value data[N_NAME_VALUE];
105 };
106 
107 /*
108  * Used to pass the username/password
109  * to the PAM conversation function.
110  */
111 struct user_pass {
112  int verb;
113 
114  char username[128];
115  char password[128];
116  char common_name[128];
117  char response[128];
118 
120 };
121 
122 /* Background process function */
123 static void pam_server(int fd, const char *service, int verb, const struct name_value_list *name_value_list);
124 
125 
126 /*
127  * Socket read/write functions.
128  */
129 
130 static int
132 {
133  unsigned char c;
134  const ssize_t size = read(fd, &c, sizeof(c));
135  if (size == sizeof(c))
136  {
137  return c;
138  }
139  else
140  {
141  /*fprintf (stderr, "AUTH-PAM: DEBUG recv_control.read=%d\n", (int)size);*/
142  return -1;
143  }
144 }
145 
146 static int
147 send_control(int fd, int code)
148 {
149  unsigned char c = (unsigned char) code;
150  const ssize_t size = write(fd, &c, sizeof(c));
151  if (size == sizeof(c))
152  {
153  return (int) size;
154  }
155  else
156  {
157  return -1;
158  }
159 }
160 
161 static int
162 recv_string(int fd, char *buffer, int len)
163 {
164  if (len > 0)
165  {
166  ssize_t size;
167  memset(buffer, 0, len);
168  size = read(fd, buffer, len);
169  buffer[len-1] = 0;
170  if (size >= 1)
171  {
172  return (int)size;
173  }
174  }
175  return -1;
176 }
177 
178 static int
179 send_string(int fd, const char *string)
180 {
181  const int len = strlen(string) + 1;
182  const ssize_t size = write(fd, string, len);
183  if (size == len)
184  {
185  return (int) size;
186  }
187  else
188  {
189  return -1;
190  }
191 }
192 
193 #ifdef DO_DAEMONIZE
194 
195 /*
196  * Daemonize if "daemon" env var is true.
197  * Preserve stderr across daemonization if
198  * "daemon_log_redirect" env var is true.
199  */
200 static void
201 daemonize(const char *envp[])
202 {
203  const char *daemon_string = get_env("daemon", envp);
204  if (daemon_string && daemon_string[0] == '1')
205  {
206  const char *log_redirect = get_env("daemon_log_redirect", envp);
207  int fd = -1;
208  if (log_redirect && log_redirect[0] == '1')
209  {
210  fd = dup(2);
211  }
212  if (daemon(0, 0) < 0)
213  {
214  fprintf(stderr, "AUTH-PAM: daemonization failed\n");
215  }
216  else if (fd >= 3)
217  {
218  dup2(fd, 2);
219  close(fd);
220  }
221  }
222 }
223 
224 #endif /* ifdef DO_DAEMONIZE */
225 
226 /*
227  * Close most of parent's fds.
228  * Keep stdin/stdout/stderr, plus one
229  * other fd which is presumed to be
230  * our pipe back to parent.
231  * Admittedly, a bit of a kludge,
232  * but posix doesn't give us a kind
233  * of FD_CLOEXEC which will stop
234  * fds from crossing a fork().
235  */
236 static void
238 {
239  int i;
240  closelog();
241  for (i = 3; i <= 100; ++i)
242  {
243  if (i != keep)
244  {
245  close(i);
246  }
247  }
248 }
249 
250 /*
251  * Usually we ignore signals, because our parent will
252  * deal with them.
253  */
254 static void
256 {
257  signal(SIGTERM, SIG_DFL);
258 
259  signal(SIGINT, SIG_IGN);
260  signal(SIGHUP, SIG_IGN);
261  signal(SIGUSR1, SIG_IGN);
262  signal(SIGUSR2, SIG_IGN);
263  signal(SIGPIPE, SIG_IGN);
264 }
265 
266 /*
267  * Return 1 if query matches match.
268  */
269 static int
270 name_value_match(const char *query, const char *match)
271 {
272  while (!isalnum(*query))
273  {
274  if (*query == '\0')
275  {
276  return 0;
277  }
278  ++query;
279  }
280  return strncasecmp(match, query, strlen(match)) == 0;
281 }
282 
283 /*
284  * Split and decode up->password in the form SCRV1:base64_pass:base64_response
285  * into pass and response and save in up->password and up->response.
286  * If the password is not in the expected format, input is not changed.
287  */
288 static void
290 {
291  const int skip = strlen("SCRV1:");
292  if (strncmp(up->password, "SCRV1:", skip) != 0)
293  {
294  return;
295  }
296 
297  char *tmp = strdup(up->password);
298  if (!tmp)
299  {
300  fprintf(stderr, "AUTH-PAM: out of memory parsing static challenge password\n");
301  goto out;
302  }
303 
304  char *pass = tmp + skip;
305  char *resp = strchr(pass, ':');
306  if (!resp) /* string not in SCRV1:xx:yy format */
307  {
308  goto out;
309  }
310  *resp++ = '\0';
311 
312  int n = plugin_base64_decode(pass, up->password, sizeof(up->password)-1);
313  if (n >= 0)
314  {
315  up->password[n] = '\0';
316  n = plugin_base64_decode(resp, up->response, sizeof(up->response)-1);
317  if (n >= 0)
318  {
319  up->response[n] = '\0';
320  if (DEBUG(up->verb))
321  {
322  fprintf(stderr, "AUTH-PAM: BACKGROUND: parsed static challenge password\n");
323  }
324  goto out;
325  }
326  }
327 
328  /* decode error: reinstate original value of up->password and return */
329  plugin_secure_memzero(up->password, sizeof(up->password));
330  plugin_secure_memzero(up->response, sizeof(up->response));
331  strcpy(up->password, tmp); /* tmp is guaranteed to fit in up->password */
332 
333  fprintf(stderr, "AUTH-PAM: base64 decode error while parsing static challenge password\n");
334 
335 out:
336  if (tmp)
337  {
338  plugin_secure_memzero(tmp, strlen(tmp));
339  free(tmp);
340  }
341 }
342 
343 OPENVPN_EXPORT int
344 openvpn_plugin_open_v3(const int v3structver,
345  struct openvpn_plugin_args_open_in const *args,
347 {
348  pid_t pid;
349  int fd[2];
350 
351  struct auth_pam_context *context;
352  struct name_value_list name_value_list;
353 
354  const int base_parms = 2;
355 
356  const char **argv = args->argv;
357  const char **envp = args->envp;
358 
359  /* Check API compatibility -- struct version 5 or higher needed */
360  if (v3structver < 5)
361  {
362  fprintf(stderr, "AUTH-PAM: This plugin is incompatible with the running version of OpenVPN\n");
364  }
365 
366  /*
367  * Allocate our context
368  */
369  context = (struct auth_pam_context *) calloc(1, sizeof(struct auth_pam_context));
370  if (!context)
371  {
372  goto error;
373  }
374  context->foreground_fd = -1;
375 
376  /*
377  * Intercept the --auth-user-pass-verify callback.
378  */
380 
381  /* Save global pointers to functions exported from openvpn */
383  plugin_base64_decode = args->callbacks->plugin_base64_decode;
384 
385  /*
386  * Make sure we have two string arguments: the first is the .so name,
387  * the second is the PAM service type.
388  */
389  if (string_array_len(argv) < base_parms)
390  {
391  fprintf(stderr, "AUTH-PAM: need PAM service parameter\n");
392  goto error;
393  }
394 
395  /*
396  * See if we have optional name/value pairs to match against
397  * PAM module queried fields in the conversation function.
398  */
399  name_value_list.len = 0;
400  if (string_array_len(argv) > base_parms)
401  {
402  const int nv_len = string_array_len(argv) - base_parms;
403  int i;
404 
405  if ((nv_len & 1) == 1 || (nv_len / 2) > N_NAME_VALUE)
406  {
407  fprintf(stderr, "AUTH-PAM: bad name/value list length\n");
408  goto error;
409  }
410 
411  name_value_list.len = nv_len / 2;
412  for (i = 0; i < name_value_list.len; ++i)
413  {
414  const int base = base_parms + i * 2;
415  name_value_list.data[i].name = argv[base];
416  name_value_list.data[i].value = argv[base+1];
417  }
418  }
419 
420  /*
421  * Get verbosity level from environment
422  */
423  {
424  const char *verb_string = get_env("verb", envp);
425  if (verb_string)
426  {
427  context->verb = atoi(verb_string);
428  }
429  }
430 
431  /*
432  * Make a socket for foreground and background processes
433  * to communicate.
434  */
435  if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
436  {
437  fprintf(stderr, "AUTH-PAM: socketpair call failed\n");
438  goto error;
439  }
440 
441  /*
442  * Fork off the privileged process. It will remain privileged
443  * even after the foreground process drops its privileges.
444  */
445  pid = fork();
446 
447  if (pid)
448  {
449  int status;
450 
451  /*
452  * Foreground Process
453  */
454 
455  context->background_pid = pid;
456 
457  /* close our copy of child's socket */
458  close(fd[1]);
459 
460  /* don't let future subprocesses inherit child socket */
461  if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0)
462  {
463  fprintf(stderr, "AUTH-PAM: Set FD_CLOEXEC flag on socket file descriptor failed\n");
464  }
465 
466  /* wait for background child process to initialize */
467  status = recv_control(fd[0]);
468  if (status == RESPONSE_INIT_SUCCEEDED)
469  {
470  context->foreground_fd = fd[0];
471  ret->handle = (openvpn_plugin_handle_t *) context;
473  }
474  }
475  else
476  {
477  /*
478  * Background Process
479  */
480 
481  /* close all parent fds except our socket back to parent */
482  close_fds_except(fd[1]);
483 
484  /* Ignore most signals (the parent will receive them) */
485  set_signals();
486 
487 #ifdef DO_DAEMONIZE
488  /* Daemonize if --daemon option is set. */
489  daemonize(envp);
490 #endif
491 
492  /* execute the event loop */
493  pam_server(fd[1], argv[1], context->verb, &name_value_list);
494 
495  close(fd[1]);
496 
497  exit(0);
498  return 0; /* NOTREACHED */
499  }
500 
501 error:
502  if (context)
503  {
504  free(context);
505  }
507 }
508 
509 OPENVPN_EXPORT int
510 openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
511 {
512  struct auth_pam_context *context = (struct auth_pam_context *) handle;
513 
514  if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY && context->foreground_fd >= 0)
515  {
516  /* get username/password from envp string array */
517  const char *username = get_env("username", envp);
518  const char *password = get_env("password", envp);
519  const char *common_name = get_env("common_name", envp) ? get_env("common_name", envp) : "";
520 
521  if (username && strlen(username) > 0 && password)
522  {
523  if (send_control(context->foreground_fd, COMMAND_VERIFY) == -1
524  || send_string(context->foreground_fd, username) == -1
525  || send_string(context->foreground_fd, password) == -1
526  || send_string(context->foreground_fd, common_name) == -1)
527  {
528  fprintf(stderr, "AUTH-PAM: Error sending auth info to background process\n");
529  }
530  else
531  {
532  const int status = recv_control(context->foreground_fd);
533  if (status == RESPONSE_VERIFY_SUCCEEDED)
534  {
536  }
537  if (status == -1)
538  {
539  fprintf(stderr, "AUTH-PAM: Error receiving auth confirmation from background process\n");
540  }
541  }
542  }
543  }
545 }
546 
547 OPENVPN_EXPORT void
549 {
550  struct auth_pam_context *context = (struct auth_pam_context *) handle;
551 
552  if (DEBUG(context->verb))
553  {
554  fprintf(stderr, "AUTH-PAM: close\n");
555  }
556 
557  if (context->foreground_fd >= 0)
558  {
559  /* tell background process to exit */
560  if (send_control(context->foreground_fd, COMMAND_EXIT) == -1)
561  {
562  fprintf(stderr, "AUTH-PAM: Error signaling background process to exit\n");
563  }
564 
565  /* wait for background process to exit */
566  if (context->background_pid > 0)
567  {
568  waitpid(context->background_pid, NULL, 0);
569  }
570 
571  close(context->foreground_fd);
572  context->foreground_fd = -1;
573  }
574 
575  free(context);
576 }
577 
578 OPENVPN_EXPORT void
580 {
581  struct auth_pam_context *context = (struct auth_pam_context *) handle;
582 
583  /* tell background process to exit */
584  if (context && context->foreground_fd >= 0)
585  {
587  close(context->foreground_fd);
588  context->foreground_fd = -1;
589  }
590 }
591 
592 /*
593  * PAM conversation function
594  */
595 static int
596 my_conv(int n, const struct pam_message **msg_array,
597  struct pam_response **response_array, void *appdata_ptr)
598 {
599  const struct user_pass *up = ( const struct user_pass *) appdata_ptr;
600  struct pam_response *aresp;
601  int i;
602  int ret = PAM_SUCCESS;
603 
604  *response_array = NULL;
605 
606  if (n <= 0 || n > PAM_MAX_NUM_MSG)
607  {
608  return (PAM_CONV_ERR);
609  }
610  if ((aresp = calloc(n, sizeof *aresp)) == NULL)
611  {
612  return (PAM_BUF_ERR);
613  }
614 
615  /* loop through each PAM-module query */
616  for (i = 0; i < n; ++i)
617  {
618  const struct pam_message *msg = msg_array[i];
619  aresp[i].resp_retcode = 0;
620  aresp[i].resp = NULL;
621 
622  if (DEBUG(up->verb))
623  {
624  fprintf(stderr, "AUTH-PAM: BACKGROUND: my_conv[%d] query='%s' style=%d\n",
625  i,
626  msg->msg ? msg->msg : "NULL",
627  msg->msg_style);
628  }
629 
630  if (up->name_value_list && up->name_value_list->len > 0)
631  {
632  /* use name/value list match method */
633  const struct name_value_list *list = up->name_value_list;
634  int j;
635 
636  /* loop through name/value pairs */
637  for (j = 0; j < list->len; ++j)
638  {
639  const char *match_name = list->data[j].name;
640  const char *match_value = list->data[j].value;
641 
642  if (name_value_match(msg->msg, match_name))
643  {
644  /* found name/value match */
645  aresp[i].resp = NULL;
646 
647  if (DEBUG(up->verb))
648  {
649  fprintf(stderr, "AUTH-PAM: BACKGROUND: name match found, query/match-string ['%s', '%s'] = '%s'\n",
650  msg->msg,
651  match_name,
652  match_value);
653  }
654 
655  if (strstr(match_value, "USERNAME"))
656  {
657  aresp[i].resp = searchandreplace(match_value, "USERNAME", up->username);
658  }
659  else if (strstr(match_value, "PASSWORD"))
660  {
661  aresp[i].resp = searchandreplace(match_value, "PASSWORD", up->password);
662  }
663  else if (strstr(match_value, "COMMONNAME"))
664  {
665  aresp[i].resp = searchandreplace(match_value, "COMMONNAME", up->common_name);
666  }
667  else if (strstr(match_value, "OTP"))
668  {
669  aresp[i].resp = searchandreplace(match_value, "OTP", up->response);
670  }
671  else
672  {
673  aresp[i].resp = strdup(match_value);
674  }
675 
676  if (aresp[i].resp == NULL)
677  {
678  ret = PAM_CONV_ERR;
679  }
680  break;
681  }
682  }
683 
684  if (j == list->len)
685  {
686  ret = PAM_CONV_ERR;
687  }
688  }
689  else
690  {
691  /* use PAM_PROMPT_ECHO_x hints */
692  switch (msg->msg_style)
693  {
694  case PAM_PROMPT_ECHO_OFF:
695  aresp[i].resp = strdup(up->password);
696  if (aresp[i].resp == NULL)
697  {
698  ret = PAM_CONV_ERR;
699  }
700  break;
701 
702  case PAM_PROMPT_ECHO_ON:
703  aresp[i].resp = strdup(up->username);
704  if (aresp[i].resp == NULL)
705  {
706  ret = PAM_CONV_ERR;
707  }
708  break;
709 
710  case PAM_ERROR_MSG:
711  case PAM_TEXT_INFO:
712  break;
713 
714  default:
715  ret = PAM_CONV_ERR;
716  break;
717  }
718  }
719  }
720 
721  if (ret == PAM_SUCCESS)
722  {
723  *response_array = aresp;
724  }
725  else
726  {
727  free(aresp);
728  }
729 
730  return ret;
731 }
732 
733 /*
734  * Return 1 if authenticated and 0 if failed.
735  * Called once for every username/password
736  * to be authenticated.
737  */
738 static int
739 pam_auth(const char *service, const struct user_pass *up)
740 {
741  struct pam_conv conv;
742  pam_handle_t *pamh = NULL;
743  int status = PAM_SUCCESS;
744  int ret = 0;
745  const int name_value_list_provided = (up->name_value_list && up->name_value_list->len > 0);
746 
747  /* Initialize PAM */
748  conv.conv = my_conv;
749  conv.appdata_ptr = (void *)up;
750  status = pam_start(service, name_value_list_provided ? NULL : up->username, &conv, &pamh);
751  if (status == PAM_SUCCESS)
752  {
753  /* Call PAM to verify username/password */
754  status = pam_authenticate(pamh, 0);
755  if (status == PAM_SUCCESS)
756  {
757  status = pam_acct_mgmt(pamh, 0);
758  }
759  if (status == PAM_SUCCESS)
760  {
761  ret = 1;
762  }
763 
764  /* Output error message if failed */
765  if (!ret)
766  {
767  fprintf(stderr, "AUTH-PAM: BACKGROUND: user '%s' failed to authenticate: %s\n",
768  up->username,
769  pam_strerror(pamh, status));
770  }
771 
772  /* Close PAM */
773  pam_end(pamh, status);
774  }
775 
776  return ret;
777 }
778 
779 /*
780  * Background process -- runs with privilege.
781  */
782 static void
783 pam_server(int fd, const char *service, int verb, const struct name_value_list *name_value_list)
784 {
785  struct user_pass up;
786  int command;
787 #ifdef USE_PAM_DLOPEN
788  static const char pam_so[] = "libpam.so";
789 #endif
790 
791  /*
792  * Do initialization
793  */
794  if (DEBUG(verb))
795  {
796  fprintf(stderr, "AUTH-PAM: BACKGROUND: INIT service='%s'\n", service);
797  }
798 
799 #ifdef USE_PAM_DLOPEN
800  /*
801  * Load PAM shared object
802  */
803  if (!dlopen_pam(pam_so))
804  {
805  fprintf(stderr, "AUTH-PAM: BACKGROUND: could not load PAM lib %s: %s\n", pam_so, dlerror());
807  goto done;
808  }
809 #endif
810 
811  /*
812  * Tell foreground that we initialized successfully
813  */
814  if (send_control(fd, RESPONSE_INIT_SUCCEEDED) == -1)
815  {
816  fprintf(stderr, "AUTH-PAM: BACKGROUND: write error on response socket [1]\n");
817  goto done;
818  }
819 
820  /*
821  * Event loop
822  */
823  while (1)
824  {
825  memset(&up, 0, sizeof(up));
826  up.verb = verb;
828 
829  /* get a command from foreground process */
830  command = recv_control(fd);
831 
832  if (DEBUG(verb))
833  {
834  fprintf(stderr, "AUTH-PAM: BACKGROUND: received command code: %d\n", command);
835  }
836 
837  switch (command)
838  {
839  case COMMAND_VERIFY:
840  if (recv_string(fd, up.username, sizeof(up.username)) == -1
841  || recv_string(fd, up.password, sizeof(up.password)) == -1
842  || recv_string(fd, up.common_name, sizeof(up.common_name)) == -1)
843  {
844  fprintf(stderr, "AUTH-PAM: BACKGROUND: read error on command channel: code=%d, exiting\n",
845  command);
846  goto done;
847  }
848 
849  if (DEBUG(verb))
850  {
851 #if 0
852  fprintf(stderr, "AUTH-PAM: BACKGROUND: USER/PASS: %s/%s\n",
853  up.username, up.password);
854 #else
855  fprintf(stderr, "AUTH-PAM: BACKGROUND: USER: %s\n", up.username);
856 #endif
857  }
858 
859  /* If password is of the form SCRV1:base64:base64 split it up */
861 
862  if (pam_auth(service, &up)) /* Succeeded */
863  {
865  {
866  fprintf(stderr, "AUTH-PAM: BACKGROUND: write error on response socket [2]\n");
867  goto done;
868  }
869  }
870  else /* Failed */
871  {
872  if (send_control(fd, RESPONSE_VERIFY_FAILED) == -1)
873  {
874  fprintf(stderr, "AUTH-PAM: BACKGROUND: write error on response socket [3]\n");
875  goto done;
876  }
877  }
878  plugin_secure_memzero(up.password, sizeof(up.password));
879  break;
880 
881  case COMMAND_EXIT:
882  goto done;
883 
884  case -1:
885  fprintf(stderr, "AUTH-PAM: BACKGROUND: read error on command channel\n");
886  goto done;
887 
888  default:
889  fprintf(stderr, "AUTH-PAM: BACKGROUND: unknown command code: code=%d, exiting\n",
890  command);
891  goto done;
892  }
893  plugin_secure_memzero(up.response, sizeof(up.response));
894  }
895 done:
896  plugin_secure_memzero(up.password, sizeof(up.password));
897  plugin_secure_memzero(up.response, sizeof(up.response));
898 #ifdef USE_PAM_DLOPEN
899  dlclose_pam();
900 #endif
901  if (DEBUG(verb))
902  {
903  fprintf(stderr, "AUTH-PAM: BACKGROUND: EXIT\n");
904  }
905 
906  return;
907 }
Arguments used to transport variables to the plug-in.
static const char * get_env(const char *name, const char *envp[])
Definition: simple.c:85
char response[128]
Definition: auth-pam.c:117
static plugin_base64_decode_t plugin_base64_decode
Definition: auth-pam.c:68
const char * name
Definition: auth-pam.c:98
Contains all state information for one tunnel.
Definition: openvpn.h:500
static void daemonize(const char *envp[])
Definition: down-root.c:165
openvpn_plugin_handle_t * handle
static void pam_server(int fd, const char *service, int verb, const struct name_value_list *name_value_list)
Definition: auth-pam.c:783
#define RESPONSE_VERIFY_SUCCEEDED
Definition: auth-pam.c:63
#define SIGUSR1
Definition: config-msvc.h:116
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.
Definition: auth-pam.c:344
plugin_secure_memzero_t plugin_secure_memzero
static bool match(const WIN32_FIND_DATA *find, LPCTSTR ext)
Definition: automatic.c:112
pid_t background_pid
Definition: auth-pam.c:79
static void close_fds_except(int keep)
Definition: auth-pam.c:237
#define SIGTERM
Definition: config-msvc.h:118
#define SIGHUP
Definition: config-msvc.h:114
static int send_string(int fd, const char *string)
Definition: auth-pam.c:179
#define OPENVPN_EXPORT
#define OPENVPN_PLUGIN_FUNC_SUCCESS
char username[USER_PASS_LEN]
Definition: misc.h:74
static int recv_control(int fd)
Definition: auth-pam.c:131
OPENVPN_EXPORT void openvpn_plugin_abort_v1(openvpn_plugin_handle_t handle)
Definition: auth-pam.c:579
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_FAILED
Definition: auth-pam.c:64
static plugin_secure_memzero_t plugin_secure_memzero
Definition: auth-pam.c:67
#define OPENVPN_PLUGIN_FUNC_ERROR
#define N_NAME_VALUE
Definition: auth-pam.c:95
static void split_scrv1_password(struct user_pass *up)
Definition: auth-pam.c:289
char common_name[128]
Definition: auth-pam.c:116
static SERVICE_STATUS status
Definition: automatic.c:43
#define COMMAND_VERIFY
Definition: auth-pam.c:57
#define RESPONSE_INIT_SUCCEEDED
Definition: auth-pam.c:61
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...
Definition: auth-pam.c:548
static SERVICE_STATUS_HANDLE service
Definition: automatic.c:42
#define msg
Definition: error.h:173
static int my_conv(int n, const struct pam_message **msg_array, struct pam_response **response_array, void *appdata_ptr)
Definition: auth-pam.c:596
void * openvpn_plugin_handle_t
#define RESPONSE_INIT_FAILED
Definition: auth-pam.c:62
int daemon(int nochdir, int noclose)
Definition: compat-daemon.c:57
const struct name_value_list * name_value_list
Definition: auth-pam.c:119
#define skip()
Definition: cmocka.h:1540
static int pam_auth(const char *service, const struct user_pass *up)
Definition: auth-pam.c:739
static int name_value_match(const char *query, const char *match)
Definition: auth-pam.c:270
#define strncasecmp
Definition: config-msvc.h:93
#define SIGINT
Definition: config-msvc.h:115
#define OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
int string_array_len(const char **array)
Definition: buffer.c:743
int verb
Definition: auth-pam.c:112
#define SIGUSR2
Definition: config-msvc.h:117
char * searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith)
Read &#39;tosearch&#39;, replace all occurrences of &#39;searchfor&#39; with &#39;replacewith&#39; and return a pointer to th...
Definition: utils.c:43
Definition: misc.h:62
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
#define COMMAND_EXIT
Definition: auth-pam.c:58
struct openvpn_plugin_callbacks * callbacks
static int recv_string(int fd, char *buffer, int len)
Definition: auth-pam.c:162
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...
Definition: auth-pam.c:510
static void set_signals(void)
Definition: auth-pam.c:255
#define free
Definition: cmocka.c:1850
const char * value
Definition: auth-pam.c:99
#define DEBUG(verb)
Definition: auth-pam.c:54
struct name_value data[N_NAME_VALUE]
Definition: auth-pam.c:104
char password[USER_PASS_LEN]
Definition: misc.h:75
static int send_control(int fd, int code)
Definition: auth-pam.c:147
Definition: argv.h:35
Arguments used to transport variables from the plug-in back to the OpenVPN process.
#define ssize_t
Definition: config-msvc.h:105
#define OPENVPN_PLUGIN_MASK(x)