Esempio n. 1
0
OPENVPN_EXPORT int
openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
{
  struct auth_pam_context *context = (struct auth_pam_context *) handle;

  if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY && context->foreground_fd >= 0)
    {
      /* get username/password from envp string array */
      const char *username = get_env ("username", envp);
      const char *password = get_env ("password", envp);
      const char *common_name = get_env ("common_name", envp) ? get_env ("common_name", envp) : "";

      if (username && strlen (username) > 0 && password)
	{
	  if (send_control (context->foreground_fd, COMMAND_VERIFY) == -1
	      || send_string (context->foreground_fd, username) == -1
	      || send_string (context->foreground_fd, password) == -1
             || send_string (context->foreground_fd, common_name) == -1)
	    {
	      fprintf (stderr, "AUTH-PAM: Error sending auth info to background process\n");
	    }
	  else
	    {
	      const int status = recv_control (context->foreground_fd);
	      if (status == RESPONSE_VERIFY_SUCCEEDED)
		return OPENVPN_PLUGIN_FUNC_SUCCESS;
	      if (status == -1)
		fprintf (stderr, "AUTH-PAM: Error receiving auth confirmation from background process\n");
	    }
	}
    }
  return OPENVPN_PLUGIN_FUNC_ERROR;
}
Esempio n. 2
0
/*
 * Called from the main OpenVPN process to enable the port
 * share proxy.
 */
struct port_share *
port_share_open (const char *host,
		 const int port,
		 const int max_initial_buf,
		 const char *journal_dir)
{
  pid_t pid;
  socket_descriptor_t fd[2];
  in_addr_t hostaddr;
  struct port_share *ps;

  ALLOC_OBJ_CLEAR (ps, struct port_share);
  ps->foreground_fd = -1;
  ps->background_pid = -1;

  /*
   * Get host's IP address
   */
  hostaddr = getaddr (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, host, 0, NULL, NULL);

  /*
   * Make a socket for foreground and background processes
   * to communicate.
   */
  if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
    {
      msg (M_WARN, "PORT SHARE: socketpair call failed");
      goto error;
    }

  /*
   * Fork off background proxy process.
   */
  pid = fork ();

  if (pid)
    {
      int status;

      /*
       * Foreground Process
       */

      ps->background_pid = pid;

      /* close our copy of child's socket */
      openvpn_close_socket (fd[1]);

      /* don't let future subprocesses inherit child socket */
      set_cloexec (fd[0]);

      /* wait for background child process to initialize */
      status = recv_control (fd[0]);
      if (status == RESPONSE_INIT_SUCCEEDED)
	{
	  /* note that this will cause possible EAGAIN when writing to
	     control socket if proxy process is backlogged */
	  set_nonblock (fd[0]);

	  ps->foreground_fd = fd[0];
	  return ps;
	}
      else
	{
	  msg (M_ERR, "PORT SHARE: unexpected init recv_control status=%d", status);
	}
    }
  else
    {
      /*
       * Background Process
       */

      /* Ignore most signals (the parent will receive them) */
      set_signals ();

      /* Let msg know that we forked */
      msg_forked ();

#ifdef ENABLE_MANAGEMENT
      /* Don't interact with management interface */
      management = NULL;
#endif

      /* close all parent fds except our socket back to parent */
      close_fds_except (fd[1]);

      /* no blocking on control channel back to parent */
      set_nonblock (fd[1]);

      /* initialize prng */
      prng_init (NULL, 0);

      /* execute the event loop */
      port_share_proxy (hostaddr, port, fd[1], max_initial_buf, journal_dir);

      openvpn_close_socket (fd[1]);

      exit (0);
      return 0; /* NOTREACHED */
    }

 error:
  port_share_close (ps);
  return NULL;
}
Esempio n. 3
0
/*
 * Background process -- runs with privilege.
 */
static void
pam_server (int fd, const char *service, int verb, const struct name_value_list *name_value_list)
{
  struct user_pass up;
  int command;
#ifdef USE_PAM_DLOPEN
  static const char pam_so[] = "libpam.so";
#endif

  /*
   * Do initialization
   */
  if (DEBUG (verb))
    fprintf (stderr, "AUTH-PAM: BACKGROUND: INIT service='%s'\n", service);

#ifdef USE_PAM_DLOPEN
  /*
   * Load PAM shared object
   */
  if (!dlopen_pam (pam_so))
    {
      fprintf (stderr, "AUTH-PAM: BACKGROUND: could not load PAM lib %s: %s\n", pam_so, dlerror());
      send_control (fd, RESPONSE_INIT_FAILED);
      goto done;
    }
#endif

  /*
   * Tell foreground that we initialized successfully
   */
  if (send_control (fd, RESPONSE_INIT_SUCCEEDED) == -1)
    {
      fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on response socket [1]\n");
      goto done;
    }

  /*
   * Event loop
   */
  while (1)
    {
      memset (&up, 0, sizeof (up));
      up.verb = verb;
      up.name_value_list = name_value_list;

      /* get a command from foreground process */
      command = recv_control (fd);

      if (DEBUG (verb))
	fprintf (stderr, "AUTH-PAM: BACKGROUND: received command code: %d\n", command);

      switch (command)
	{
	case COMMAND_VERIFY:
	  if (recv_string (fd, up.username, sizeof (up.username)) == -1
	      || recv_string (fd, up.password, sizeof (up.password)) == -1
	      || recv_string (fd, up.common_name, sizeof (up.common_name)) == -1)
	    {
	      fprintf (stderr, "AUTH-PAM: BACKGROUND: read error on command channel: code=%d, exiting\n",
		       command);
	      goto done;
	    }

	  if (DEBUG (verb))
	    {
#if 0
	      fprintf (stderr, "AUTH-PAM: BACKGROUND: USER/PASS: %s/%s\n",
		       up.username, up.password);
#else
	      fprintf (stderr, "AUTH-PAM: BACKGROUND: USER: %s\n", up.username);
#endif
	    }

	  if (pam_auth (service, &up)) /* Succeeded */
	    {
	      if (send_control (fd, RESPONSE_VERIFY_SUCCEEDED) == -1)
		{
		  fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on response socket [2]\n");
		  goto done;
		}
	    }
	  else /* Failed */
	    {
	      if (send_control (fd, RESPONSE_VERIFY_FAILED) == -1)
		{
		  fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on response socket [3]\n");
		  goto done;
		}
	    }
	  break;

	case COMMAND_EXIT:
	  goto done;

	case -1:
	  fprintf (stderr, "AUTH-PAM: BACKGROUND: read error on command channel\n");
	  goto done;

	default:
	  fprintf (stderr, "AUTH-PAM: BACKGROUND: unknown command code: code=%d, exiting\n",
		   command);
	  goto done;
	}
    }
 done:

#ifdef USE_PAM_DLOPEN
  dlclose_pam ();
#endif
  if (DEBUG (verb))
    fprintf (stderr, "AUTH-PAM: BACKGROUND: EXIT\n");

  return;
}
Esempio n. 4
0
OPENVPN_EXPORT openvpn_plugin_handle_t
openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[])
{
  pid_t pid;
  int fd[2];

  struct auth_pam_context *context;
  struct name_value_list name_value_list;

  const int base_parms = 2;

  /*
   * Allocate our context
   */
  context = (struct auth_pam_context *) calloc (1, sizeof (struct auth_pam_context));
  if (!context)
    goto error;
  context->foreground_fd = -1;

  /*
   * Intercept the --auth-user-pass-verify callback.
   */
  *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY);

  /*
   * Make sure we have two string arguments: the first is the .so name,
   * the second is the PAM service type.
   */
  if (string_array_len (argv) < base_parms)
    {
      fprintf (stderr, "AUTH-PAM: need PAM service parameter\n");
      goto error;
    }

  /*
   * See if we have optional name/value pairs to match against
   * PAM module queried fields in the conversation function.
   */
  name_value_list.len = 0;
  if (string_array_len (argv) > base_parms)
    {
      const int nv_len = string_array_len (argv) - base_parms;
      int i;

      if ((nv_len & 1) == 1 || (nv_len / 2) > N_NAME_VALUE)
	{
	  fprintf (stderr, "AUTH-PAM: bad name/value list length\n");
	  goto error;
	}

      name_value_list.len = nv_len / 2;
      for (i = 0; i < name_value_list.len; ++i)
	{
	  const int base = base_parms + i * 2;
	  name_value_list.data[i].name = argv[base];
	  name_value_list.data[i].value = argv[base+1];
	}
    }

  /*
   * Get verbosity level from environment
   */
  {
    const char *verb_string = get_env ("verb", envp);
    if (verb_string)
      context->verb = atoi (verb_string);
  }

  /*
   * Make a socket for foreground and background processes
   * to communicate.
   */
  if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
    {
      fprintf (stderr, "AUTH-PAM: socketpair call failed\n");
      goto error;
    }

  /*
   * Fork off the privileged process.  It will remain privileged
   * even after the foreground process drops its privileges.
   */
  pid = fork ();

  if (pid)
    {
      int status;

      /*
       * Foreground Process
       */

      context->background_pid = pid;

      /* close our copy of child's socket */
      close (fd[1]);

      /* don't let future subprocesses inherit child socket */
      if (fcntl (fd[0], F_SETFD, FD_CLOEXEC) < 0)
	fprintf (stderr, "AUTH-PAM: Set FD_CLOEXEC flag on socket file descriptor failed\n");

      /* wait for background child process to initialize */
      status = recv_control (fd[0]);
      if (status == RESPONSE_INIT_SUCCEEDED)
	{
	  context->foreground_fd = fd[0];
	  return (openvpn_plugin_handle_t) context;
	}
    }
  else
    {
      /*
       * Background Process
       */

      /* close all parent fds except our socket back to parent */
      close_fds_except (fd[1]);

      /* Ignore most signals (the parent will receive them) */
      set_signals ();

#ifdef DO_DAEMONIZE
      /* Daemonize if --daemon option is set. */
      daemonize (envp);
#endif

      /* execute the event loop */
      pam_server (fd[1], argv[1], context->verb, &name_value_list);

      close (fd[1]);

      exit (0);
      return 0; /* NOTREACHED */
    }

 error:
  if (context)
    free (context);
  return NULL;
}
Esempio n. 5
0
/*
 * Background process -- runs with privilege.
 */
static void
down_root_server (const int fd, char *command, const char *argv[], const char *envp[], const int verb)
{
  const char *p[3];
  char *command_line = NULL;
  char *argv_cat = NULL;
  int i;

  /*
   * Do initialization
   */
  if (DEBUG (verb))
    fprintf (stderr, "DOWN-ROOT: BACKGROUND: INIT command='%s'\n", command);

  /*
   * Tell foreground that we initialized successfully
   */
  if (send_control (fd, RESPONSE_INIT_SUCCEEDED) == -1)
    {
      fprintf (stderr, "DOWN-ROOT: BACKGROUND: write error on response socket [1]\n");
      goto done;
    }

  /*
   * Build command line
   */
  if (string_array_len (argv) >= 2)
    argv_cat = build_command_line (&argv[1]);
  else
    argv_cat = build_command_line (NULL);
  p[0] = command;
  p[1] = argv_cat;
  p[2] = NULL;
  command_line = build_command_line (p);

  /*
   * Save envp in environment
   */
  for (i = 0; envp[i]; ++i)
    {
      putenv ((char *)envp[i]);
    }

  /*
   * Event loop
   */
  while (1)
    {
      int command_code;
      int status;

      /* get a command from foreground process */
      command_code = recv_control (fd);

      if (DEBUG (verb))
	fprintf (stderr, "DOWN-ROOT: BACKGROUND: received command code: %d\n", command_code);

      switch (command_code)
	{
	case COMMAND_RUN_SCRIPT:
	  status = system (command_line);
	  if (system_ok (status)) /* Succeeded */
	    {
	      if (send_control (fd, RESPONSE_SCRIPT_SUCCEEDED) == -1)
		{
		  fprintf (stderr, "DOWN-ROOT: BACKGROUND: write error on response socket [2]\n");
		  goto done;
		}
	    }
	  else /* Failed */
	    {
	      if (send_control (fd, RESPONSE_SCRIPT_FAILED) == -1)
		{
		  fprintf (stderr, "DOWN-ROOT: BACKGROUND: write error on response socket [3]\n");
		  goto done;
		}
	    }
	  break;

	case COMMAND_EXIT:
	  goto done;

	case -1:
	  fprintf (stderr, "DOWN-ROOT: BACKGROUND: read error on command channel\n");
	  goto done;

	default:
	  fprintf (stderr, "DOWN-ROOT: BACKGROUND: unknown command code: code=%d, exiting\n",
		   command_code);
	  goto done;
	}
    }

 done:
  if (argv_cat)
    free (argv_cat);
  if (command_line)
    free (command_line);
  if (DEBUG (verb))
    fprintf (stderr, "DOWN-ROOT: BACKGROUND: EXIT\n");

  return;
}
Esempio n. 6
0
OPENVPN_EXPORT int
openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
{
  struct down_root_context *context = (struct down_root_context *) handle;

  if (type == OPENVPN_PLUGIN_UP && context->foreground_fd == -1) /* fork off a process to hold onto root */
    {
      pid_t pid;
      int fd[2];

      /*
       * Make a socket for foreground and background processes
       * to communicate.
       */
      if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
	{
	  fprintf (stderr, "DOWN-ROOT: socketpair call failed\n");
	  return OPENVPN_PLUGIN_FUNC_ERROR;
	}

      /*
       * Fork off the privileged process.  It will remain privileged
       * even after the foreground process drops its privileges.
       */
      pid = fork ();

      if (pid)
	{
	  int status;

	  /*
	   * Foreground Process
	   */

	  context->background_pid = pid;

	  /* close our copy of child's socket */
	  close (fd[1]);

	  /* don't let future subprocesses inherit child socket */
	  if (fcntl (fd[0], F_SETFD, FD_CLOEXEC) < 0)
	    fprintf (stderr, "DOWN-ROOT: Set FD_CLOEXEC flag on socket file descriptor failed\n");

	  /* wait for background child process to initialize */
	  status = recv_control (fd[0]);
	  if (status == RESPONSE_INIT_SUCCEEDED)
	    {
	      context->foreground_fd = fd[0];
	      return OPENVPN_PLUGIN_FUNC_SUCCESS;
	    }
	}
      else
	{
	  /*
	   * Background Process
	   */

	  /* close all parent fds except our socket back to parent */
	  close_fds_except (fd[1]);

	  /* Ignore most signals (the parent will receive them) */
	  set_signals ();

	  /* Daemonize if --daemon option is set. */
	  daemonize (envp);

	  /* execute the event loop */
	  down_root_server (fd[1], context->command, argv, envp, context->verb);

	  close (fd[1]);
	  exit (0);
	  return 0; /* NOTREACHED */
	}
    }
  else if (type == OPENVPN_PLUGIN_DOWN && context->foreground_fd >= 0)
    {
      if (send_control (context->foreground_fd, COMMAND_RUN_SCRIPT) == -1)
	{
	  fprintf (stderr, "DOWN-ROOT: Error sending script execution signal to background process\n");
	}
      else
	{
	  const int status = recv_control (context->foreground_fd);
	  if (status == RESPONSE_SCRIPT_SUCCEEDED)
	    return OPENVPN_PLUGIN_FUNC_SUCCESS;
	  if (status == -1)
	    fprintf (stderr, "DOWN-ROOT: Error receiving script execution confirmation from background process\n");
	}
    }
  return OPENVPN_PLUGIN_FUNC_ERROR;
}
Esempio n. 7
0
/*
 * Background process -- runs with privilege.
 */
static void
down_root_server(const int fd, char *const *argv, char *const *envp, const int verb)
{
    /*
     * Do initialization
     */
    if (DEBUG(verb))
    {
        fprintf(stderr, "DOWN-ROOT: BACKGROUND: INIT command='%s'\n", argv[0]);
    }

    /*
     * Tell foreground that we initialized successfully
     */
    if (send_control(fd, RESPONSE_INIT_SUCCEEDED) == -1)
    {
        warn("DOWN-ROOT: BACKGROUND: write error on response socket [1]");
        goto done;
    }

    /*
     * Event loop
     */
    while (1)
    {
        int command_code;
        int exit_code = -1;

        /* get a command from foreground process */
        command_code = recv_control(fd);

        if (DEBUG(verb))
        {
            fprintf(stderr, "DOWN-ROOT: BACKGROUND: received command code: %d\n", command_code);
        }

        switch (command_code)
        {
            case COMMAND_RUN_SCRIPT:
                if ( (exit_code = run_script(argv, envp)) == 0) /* Succeeded */
                {
                    if (send_control(fd, RESPONSE_SCRIPT_SUCCEEDED) == -1)
                    {
                        warn("DOWN-ROOT: BACKGROUND: write error on response socket [2]");
                        goto done;
                    }
                }
                else /* Failed */
                {
                    fprintf(stderr, "DOWN-ROOT: BACKGROUND: %s exited with exit code %i\n", argv[0], exit_code);
                    if (send_control(fd, RESPONSE_SCRIPT_FAILED) == -1)
                    {
                        warn("DOWN-ROOT: BACKGROUND: write error on response socket [3]");
                        goto done;
                    }
                }
                break;

            case COMMAND_EXIT:
                goto done;

            case -1:
                warn("DOWN-ROOT: BACKGROUND: read error on command channel");
                goto done;

            default:
                fprintf(stderr, "DOWN-ROOT: BACKGROUND: unknown command code: code=%d, exiting\n",
                        command_code);
                goto done;
        }
    }

done:
    if (DEBUG(verb))
    {
        fprintf(stderr, "DOWN-ROOT: BACKGROUND: EXIT\n");
    }

    return;
}