⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 down-root.c

📁 the open vpn source code in linux
💻 C
字号:
/* *  OpenVPN -- An application to securely tunnel IP networks *             over a single TCP/UDP port, with support for SSL/TLS-based *             session authentication and key exchange, *             packet encryption, packet authentication, and *             packet compression. * *  Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License version 2 *  as published by the Free Software Foundation. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program (see the file COPYING included with this *  distribution); if not, write to the Free Software Foundation, Inc., *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *//* * OpenVPN plugin module to do privileged down-script execution. */#include <stdio.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/wait.h>#include <fcntl.h>#include <signal.h>#include <syslog.h>#include "openvpn-plugin.h"#define DEBUG(verb) ((verb) >= 7)/* Command codes for foreground -> background communication */#define COMMAND_RUN_SCRIPT 0#define COMMAND_EXIT       1/* Response codes for background -> foreground communication */#define RESPONSE_INIT_SUCCEEDED   10#define RESPONSE_INIT_FAILED      11#define RESPONSE_SCRIPT_SUCCEEDED 12#define RESPONSE_SCRIPT_FAILED    13/* Background process function */static void down_root_server (const int fd, char *command, const char *argv[], const char *envp[], const int verb);/* * Plugin state, used by foreground */struct down_root_context{  /* Foreground's socket to background process */  int foreground_fd;  /* Process ID of background process */  pid_t background_pid;  /* Verbosity level of OpenVPN */  int verb;  /* down command */  char *command;};/* * Given an environmental variable name, search * the envp array for its value, returning it * if found or NULL otherwise. */static const char *get_env (const char *name, const char *envp[]){  if (envp)    {      int i;      const int namelen = strlen (name);      for (i = 0; envp[i]; ++i)	{	  if (!strncmp (envp[i], name, namelen))	    {	      const char *cp = envp[i] + namelen;	      if (*cp == '=')		return cp + 1;	    }	}    }  return NULL;}/* * Return the length of a string array */static intstring_array_len (const char *array[]){  int i = 0;  if (array)    {      while (array[i])	++i;    }  return i;}/* * Socket read/write functions. */static intrecv_control (int fd){  unsigned char c;  const ssize_t size = read (fd, &c, sizeof (c));  if (size == sizeof (c))    return c;  else    return -1;}static intsend_control (int fd, int code){  unsigned char c = (unsigned char) code;  const ssize_t size = write (fd, &c, sizeof (c));  if (size == sizeof (c))    return (int) size;  else    return -1;}/* * Daemonize if "daemon" env var is true. * Preserve stderr across daemonization if * "daemon_log_redirect" env var is true. */static voiddaemonize (const char *envp[]){  const char *daemon_string = get_env ("daemon", envp);  if (daemon_string && daemon_string[0] == '1')    {      const char *log_redirect = get_env ("daemon_log_redirect", envp);      int fd = -1;      if (log_redirect && log_redirect[0] == '1')	fd = dup (2);      if (daemon (0, 0) < 0)	{	  fprintf (stderr, "DOWN-ROOT: daemonization failed\n");	}      else if (fd >= 3)	{	  dup2 (fd, 2);	  close (fd);	}    }}/* * Close most of parent's fds. * Keep stdin/stdout/stderr, plus one * other fd which is presumed to be * our pipe back to parent. * Admittedly, a bit of a kludge, * but posix doesn't give us a kind * of FD_CLOEXEC which will stop * fds from crossing a fork(). */static voidclose_fds_except (int keep){  int i;  closelog ();  for (i = 3; i <= 100; ++i)    {      if (i != keep)	close (i);    }}/* * Usually we ignore signals, because our parent will * deal with them. */static voidset_signals (void){  signal (SIGTERM, SIG_DFL);  signal (SIGINT, SIG_IGN);  signal (SIGHUP, SIG_IGN);  signal (SIGUSR1, SIG_IGN);  signal (SIGUSR2, SIG_IGN);  signal (SIGPIPE, SIG_IGN);}/* * convert system() return into a success/failure value */intsystem_ok (int stat){#ifdef WIN32  return stat == 0;#else  return stat != -1 && WIFEXITED (stat) && WEXITSTATUS (stat) == 0;#endif}static char *build_command_line (const char *argv[]){  int size = 0;  int n = 0;  int i;  char *string;  /* precompute size */  if (argv)    {      for (i = 0; argv[i]; ++i)	{	  size += (strlen (argv[i]) + 1); /* string length plus trailing space */	  ++n;	}    }  ++size;                                 /* for null terminator */  /* allocate memory */  string = (char *) malloc (size);  if (!string)    {      fprintf (stderr, "DOWN-ROOT: out of memory\n");      exit (1);    }  string[0] = '\0';  /* build string */  for (i = 0; i < n; ++i)    {      strcat (string, argv[i]);      if (i + 1 < n)	strcat (string, " ");    }  return string;}static voidfree_context (struct down_root_context *context){  if (context)    {      if (context->command)	free (context->command);      free (context);    }}OPENVPN_EXPORT openvpn_plugin_handle_topenvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]){  struct down_root_context *context;  /*   * Allocate our context   */  context = (struct down_root_context *) calloc (1, sizeof (struct down_root_context));  context->foreground_fd = -1;  /*   * Intercept the --up and --down callbacks   */  *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN);  /*   * Make sure we have two string arguments: the first is the .so name,   * the second is the script command.   */  if (string_array_len (argv) < 2)    {      fprintf (stderr, "DOWN-ROOT: need down script command\n");      goto error;    }  /*   * Save our argument in context   */  context->command = build_command_line (&argv[1]);  /*   * Get verbosity level from environment   */  {    const char *verb_string = get_env ("verb", envp);    if (verb_string)      context->verb = atoi (verb_string);  }  return (openvpn_plugin_handle_t) context; error:  free_context (context);  return NULL;}OPENVPN_EXPORT intopenvpn_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;}OPENVPN_EXPORT voidopenvpn_plugin_close_v1 (openvpn_plugin_handle_t handle){  struct down_root_context *context = (struct down_root_context *) handle;  if (DEBUG (context->verb))    fprintf (stderr, "DOWN-ROOT: close\n");  if (context->foreground_fd >= 0)    {      /* tell background process to exit */      if (send_control (context->foreground_fd, COMMAND_EXIT) == -1)	fprintf (stderr, "DOWN-ROOT: Error signaling background process to exit\n");      /* wait for background process to exit */      if (context->background_pid > 0)	waitpid (context->background_pid, NULL, 0);      close (context->foreground_fd);      context->foreground_fd = -1;    }  free_context (context);}OPENVPN_EXPORT voidopenvpn_plugin_abort_v1 (openvpn_plugin_handle_t handle){  struct down_root_context *context = (struct down_root_context *) handle;  if (context->foreground_fd >= 0)    {      /* tell background process to exit */      send_control (context->foreground_fd, COMMAND_EXIT);      close (context->foreground_fd);      context->foreground_fd = -1;    }}/* * Background process -- runs with privilege. */static voiddown_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;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -