HANDLE
create_event (const char *name, bool allow_all, bool initial_state, bool manual_reset)
{
  if (allow_all)
    {
      struct security_attributes sa;
      if (!init_security_attributes_allow_all (&sa))
	return NULL;
      return CreateEvent (&sa.sa, (BOOL)manual_reset, (BOOL)initial_state, name);
    }
  else
    return CreateEvent (NULL, (BOOL)manual_reset, (BOOL)initial_state, name);
}
Exemplo n.º 2
0
void
semaphore_open (struct semaphore *s, const char *name)
{
  struct security_attributes sa;

  s->locked = false;
  s->name = name;
  s->hand = NULL;

  if (init_security_attributes_allow_all (&sa))
    s->hand = CreateSemaphore(&sa.sa, 1, 1, name);

  if (s->hand == NULL)
    msg (M_WARN|M_ERRNO, "WARNING: Cannot create Win32 semaphore '%s'", name);
  else
    dmsg (D_SEMAPHORE, "Created Win32 semaphore '%s'", s->name);
}
Exemplo n.º 3
0
VOID WINAPI
ServiceStartAutomatic(DWORD dwArgc, LPTSTR *lpszArgv)
{
    DWORD error = NO_ERROR;
    settings_t settings;

    service = RegisterServiceCtrlHandlerEx(automatic_service.name, ServiceCtrlAutomatic, &status);
    if (!service)
    {
        return;
    }

    status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
    status.dwCurrentState = SERVICE_START_PENDING;
    status.dwServiceSpecificExitCode = NO_ERROR;
    status.dwWin32ExitCode = NO_ERROR;
    status.dwWaitHint = 3000;

    if (!ReportStatusToSCMgr(service, &status))
    {
        MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr #1 failed"));
        goto finish;
    }

    /*
     * Create our exit event
     */
    exit_event = create_event(EXIT_EVENT_NAME, false, false, true);
    if (!exit_event)
    {
        MsgToEventLog(M_ERR, TEXT("CreateEvent failed"));
        goto finish;
    }

    /*
     * If exit event is already signaled, it means we were not
     * shut down properly.
     */
    if (WaitForSingleObject(exit_event, 0) != WAIT_TIMEOUT)
    {
        MsgToEventLog(M_ERR, TEXT("Exit event is already signaled -- we were not shut down properly"));
        goto finish;
    }

    if (!ReportStatusToSCMgr(service, &status))
    {
        MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr #2 failed"));
        goto finish;
    }

    /*
     * Read info from registry in key HKLM\SOFTWARE\OpenVPN
     */
    error = GetOpenvpnSettings(&settings);
    if (error != ERROR_SUCCESS)
    {
        goto finish;
    }

    /*
     * Instantiate an OpenVPN process for each configuration
     * file found.
     */
    {
        WIN32_FIND_DATA find_obj;
        HANDLE find_handle;
        BOOL more_files;
        TCHAR find_string[MAX_PATH];

        openvpn_sntprintf(find_string, MAX_PATH, TEXT("%s\\*"), settings.config_dir);

        find_handle = FindFirstFile(find_string, &find_obj);
        if (find_handle == INVALID_HANDLE_VALUE)
        {
            MsgToEventLog(M_ERR, TEXT("Cannot get configuration file list using: %s"), find_string);
            goto finish;
        }

        /*
         * Loop over each config file
         */
        do {
            HANDLE log_handle = NULL;
            STARTUPINFO start_info;
            PROCESS_INFORMATION proc_info;
            struct security_attributes sa;
            TCHAR log_file[MAX_PATH];
            TCHAR log_path[MAX_PATH];
            TCHAR command_line[256];

            CLEAR(start_info);
            CLEAR(proc_info);
            CLEAR(sa);

            if (!ReportStatusToSCMgr(service, &status))
            {
                MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr #3 failed"));
                FindClose(find_handle);
                goto finish;
            }

            /* does file have the correct type and extension? */
            if (match(&find_obj, settings.ext_string))
            {
                /* get log file pathname */
                if (!modext(log_file, _countof(log_file), find_obj.cFileName, TEXT("log")))
                {
                    MsgToEventLog(M_ERR, TEXT("Cannot construct logfile name based on: %s"), find_obj.cFileName);
                    FindClose(find_handle);
                    goto finish;
                }
                openvpn_sntprintf(log_path, _countof(log_path),
                                  TEXT("%s\\%s"), settings.log_dir, log_file);

                /* construct command line */
                openvpn_sntprintf(command_line, _countof(command_line), TEXT(PACKAGE " --service %s 1 --config \"%s\""),
                                  EXIT_EVENT_NAME,
                                  find_obj.cFileName);

                /* Make security attributes struct for logfile handle so it can
                 * be inherited. */
                if (!init_security_attributes_allow_all(&sa))
                {
                    error = MsgToEventLog(M_SYSERR, TEXT("InitializeSecurityDescriptor start_" PACKAGE " failed"));
                    goto finish;
                }

                /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */
                log_handle = CreateFile(log_path,
                                        GENERIC_WRITE,
                                        FILE_SHARE_READ,
                                        &sa.sa,
                                        settings.append ? OPEN_ALWAYS : CREATE_ALWAYS,
                                        FILE_ATTRIBUTE_NORMAL,
                                        NULL);

                if (log_handle == INVALID_HANDLE_VALUE)
                {
                    error = MsgToEventLog(M_SYSERR, TEXT("Cannot open logfile: %s"), log_path);
                    FindClose(find_handle);
                    goto finish;
                }

                /* append to logfile? */
                if (settings.append)
                {
                    if (SetFilePointer(log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
                    {
                        error = MsgToEventLog(M_SYSERR, TEXT("Cannot seek to end of logfile: %s"), log_path);
                        FindClose(find_handle);
                        goto finish;
                    }
                }

                /* fill in STARTUPINFO struct */
                GetStartupInfo(&start_info);
                start_info.cb = sizeof(start_info);
                start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
                start_info.wShowWindow = SW_HIDE;
                start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
                start_info.hStdOutput = start_info.hStdError = log_handle;

                /* create an OpenVPN process for one config file */
                if (!CreateProcess(settings.exe_path,
                                   command_line,
                                   NULL,
                                   NULL,
                                   TRUE,
                                   settings.priority | CREATE_NEW_CONSOLE,
                                   NULL,
                                   settings.config_dir,
                                   &start_info,
                                   &proc_info))
                {
                    error = MsgToEventLog(M_SYSERR, TEXT("CreateProcess failed, exe='%s' cmdline='%s' dir='%s'"),
                                          settings.exe_path,
                                          command_line,
                                          settings.config_dir);

                    FindClose(find_handle);
                    CloseHandle(log_handle);
                    goto finish;
                }

                /* close unneeded handles */
                Sleep(1000); /* try to prevent race if we close logfile
                              * handle before child process DUPs it */
                if (!CloseHandle(proc_info.hProcess)
                    || !CloseHandle(proc_info.hThread)
                    || !CloseHandle(log_handle))
                {
                    error = MsgToEventLog(M_SYSERR, TEXT("CloseHandle failed"));
                    goto finish;
                }
            }

            /* more files to process? */
            more_files = FindNextFile(find_handle, &find_obj);

        } while (more_files);

        FindClose(find_handle);
    }

    /* we are now fully started */
    status.dwCurrentState = SERVICE_RUNNING;
    status.dwWaitHint = 0;
    if (!ReportStatusToSCMgr(service, &status))
    {
        MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr SERVICE_RUNNING failed"));
        goto finish;
    }

    /* wait for our shutdown signal */
    if (WaitForSingleObject(exit_event, INFINITE) != WAIT_OBJECT_0)
    {
        MsgToEventLog(M_ERR, TEXT("wait for shutdown signal failed"));
    }

finish:
    if (exit_event)
    {
        CloseHandle(exit_event);
    }

    status.dwCurrentState = SERVICE_STOPPED;
    status.dwWin32ExitCode = error;
    ReportStatusToSCMgr(service, &status);
}
Exemplo n.º 4
0
void
win32_signal_open (struct win32_signal *ws,
		   int force,
		   const char *exit_event_name,
		   bool exit_event_initial_state)
{
  CLEAR (*ws);

  ws->mode = WSO_MODE_UNDEF;
  ws->in.read = INVALID_HANDLE_VALUE;
  ws->in.write = INVALID_HANDLE_VALUE;
  ws->console_mode_save = 0;
  ws->console_mode_save_defined = false;

  if (force == WSO_NOFORCE || force == WSO_FORCE_CONSOLE)
    {
      /*
       * Try to open console.
       */
      ws->in.read = GetStdHandle (STD_INPUT_HANDLE);
      if (ws->in.read != INVALID_HANDLE_VALUE)
	{
	  if (GetConsoleMode (ws->in.read, &ws->console_mode_save))
	    {
	      /* running on a console */
	      const DWORD new_console_mode = ws->console_mode_save
		& ~(ENABLE_WINDOW_INPUT
		    | ENABLE_PROCESSED_INPUT
		    | ENABLE_LINE_INPUT
		    | ENABLE_ECHO_INPUT 
		    | ENABLE_MOUSE_INPUT);

	      if (new_console_mode != ws->console_mode_save)
		{
		  if (!SetConsoleMode (ws->in.read, new_console_mode))
		    msg (M_ERR, "Error: win32_signal_open: SetConsoleMode failed");
		  ws->console_mode_save_defined = true;
		}
	      ws->mode = WSO_MODE_CONSOLE;
	    }
	  else
	    ws->in.read = INVALID_HANDLE_VALUE; /* probably running as a service */
	}
    }

  /*
   * If console open failed, assume we are running
   * as a service.
   */
  if ((force == WSO_NOFORCE || force == WSO_FORCE_SERVICE)
      && !HANDLE_DEFINED (ws->in.read) && exit_event_name)
    {
      struct security_attributes sa;

      if (!init_security_attributes_allow_all (&sa))
	msg (M_ERR, "Error: win32_signal_open: init SA failed");

      ws->in.read = CreateEvent (&sa.sa,
				 TRUE,
				 exit_event_initial_state ? TRUE : FALSE,
				 exit_event_name);
      if (ws->in.read == NULL)
	{
	  msg (M_WARN|M_ERRNO, "NOTE: CreateEvent '%s' failed", exit_event_name);
	}
      else
	{
	  if (WaitForSingleObject (ws->in.read, 0) != WAIT_TIMEOUT)
	    msg (M_FATAL, "ERROR: Exit Event ('%s') is signaled", exit_event_name);
	  else
	    ws->mode = WSO_MODE_SERVICE;
	}
    }
}
VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
{
  char exe_path[MAX_PATH];
  char config_dir[MAX_PATH];
  char ext_string[16];
  char log_dir[MAX_PATH];
  char priority_string[64];
  char append_string[2];

  DWORD priority;
  bool append;

  ResetError ();

  if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
    {
      MSG (M_ERR, "ReportStatusToSCMgr #1 failed");
      goto finish;
    }

  /*
   * Create our exit event
   */
  exit_event = create_event (EXIT_EVENT_NAME, false, false, true);
  if (!exit_event)
    {
      MSG (M_ERR, "CreateEvent failed");
      goto finish;
    }

  /*
   * If exit event is already signaled, it means we were not
   * shut down properly.
   */
  if (WaitForSingleObject (exit_event, 0) != WAIT_TIMEOUT)
    {
      MSG (M_ERR, "Exit event is already signaled -- we were not shut down properly");
      goto finish;
    }

  if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
    {
      MSG (M_ERR, "ReportStatusToSCMgr #2 failed");
      goto finish;
    }

  /*
   * Read info from registry in key HKLM\SOFTWARE\OpenVPN
   */
  {
    HKEY openvpn_key;
    LONG status;
    DWORD len;
    DWORD type;
    char error_string[256];

    static const char error_format_str[] =
      "Error querying registry key of type REG_SZ: HKLM\\" REG_KEY "\\%s";

    static const char error_format_dword[] =
      "Error querying registry key of type REG_DWORD: HKLM\\" REG_KEY "\\%s";

    status = RegOpenKeyEx(
			  HKEY_LOCAL_MACHINE,
			  REG_KEY,
			  0,
			  KEY_READ,
			  &openvpn_key);

    if (status != ERROR_SUCCESS)
      {
	SetLastError (status);
	MSG (M_SYSERR, "Registry key HKLM\\" REG_KEY " not found");
	goto finish;
      }

    /* get path to openvpn.exe */
    QUERY_REG_STRING ("exe_path", exe_path);

    /* get path to configuration directory */
    QUERY_REG_STRING ("config_dir", config_dir);

    /* get extension on configuration files */
    QUERY_REG_STRING ("config_ext", ext_string);

    /* get path to log directory */
    QUERY_REG_STRING ("log_dir", log_dir);

    /* get priority for spawned OpenVPN subprocesses */
    QUERY_REG_STRING ("priority", priority_string);

    /* should we truncate or append to logfile? */
    QUERY_REG_STRING ("log_append", append_string);

    RegCloseKey (openvpn_key);
  }

  /* set process priority */
  priority = NORMAL_PRIORITY_CLASS;
  if (!strcasecmp (priority_string, "IDLE_PRIORITY_CLASS"))
    priority = IDLE_PRIORITY_CLASS;
  else if (!strcasecmp (priority_string, "BELOW_NORMAL_PRIORITY_CLASS"))
    priority = BELOW_NORMAL_PRIORITY_CLASS;
  else if (!strcasecmp (priority_string, "NORMAL_PRIORITY_CLASS"))
    priority = NORMAL_PRIORITY_CLASS;
  else if (!strcasecmp (priority_string, "ABOVE_NORMAL_PRIORITY_CLASS"))
    priority = ABOVE_NORMAL_PRIORITY_CLASS;
  else if (!strcasecmp (priority_string, "HIGH_PRIORITY_CLASS"))
    priority = HIGH_PRIORITY_CLASS;
  else
    {
      MSG (M_ERR, "Unknown priority name: %s", priority_string);
      goto finish;
    }

  /* set log file append/truncate flag */
  append = false;
  if (append_string[0] == '0')
    append = false;
  else if (append_string[0] == '1')
    append = true;
  else
    {
      MSG (M_ERR, "Log file append flag (given as '%s') must be '0' or '1'", append_string);
      goto finish;
    }

  /*
   * Instantiate an OpenVPN process for each configuration
   * file found.
   */
  {
    WIN32_FIND_DATA find_obj;
    HANDLE find_handle;
    BOOL more_files;
    char find_string[MAX_PATH];

    mysnprintf (find_string, "%s\\*", config_dir);

    find_handle = FindFirstFile (find_string, &find_obj);
    if (find_handle == INVALID_HANDLE_VALUE)
      {
        MSG (M_ERR, "Cannot get configuration file list using: %s", find_string);
	goto finish;
      }

    /*
     * Loop over each config file
     */
    do {
      HANDLE log_handle = NULL;
      STARTUPINFO start_info;
      PROCESS_INFORMATION proc_info;
      struct security_attributes sa;
      char log_file[MAX_PATH];
      char log_path[MAX_PATH];
      char command_line[256];

      CLEAR (start_info);
      CLEAR (proc_info);
      CLEAR (sa);

      if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
	{
	  MSG (M_ERR, "ReportStatusToSCMgr #3 failed");
	  FindClose (find_handle);
	  goto finish;
	}

      /* does file have the correct type and extension? */
      if (match (&find_obj, ext_string))
	{
	  /* get log file pathname */
	  if (!modext (log_file, sizeof (log_file), find_obj.cFileName, "log"))
	    {
	      MSG (M_ERR, "Cannot construct logfile name based on: %s", find_obj.cFileName);
	      FindClose (find_handle);
	      goto finish;
	    }
	  mysnprintf (log_path, "%s\\%s", log_dir, log_file);

	  /* construct command line */
	  mysnprintf (command_line, PACKAGE " --service %s 1 --config \"%s\"",
		      EXIT_EVENT_NAME,
		      find_obj.cFileName);

	  /* Make security attributes struct for logfile handle so it can
	     be inherited. */
	  if (!init_security_attributes_allow_all (&sa))
	    {
	      MSG (M_SYSERR, "InitializeSecurityDescriptor start_" PACKAGE " failed");
	      goto finish;
	    }

	  /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */
	  log_handle = CreateFile (log_path,
				   GENERIC_WRITE,
				   FILE_SHARE_READ,
				   &sa.sa,
				   append ? OPEN_ALWAYS : CREATE_ALWAYS,
				   FILE_ATTRIBUTE_NORMAL,
				   NULL);

	  if (log_handle == INVALID_HANDLE_VALUE)
	    {
	      MSG (M_SYSERR, "Cannot open logfile: %s", log_path);
	      FindClose (find_handle);
	      goto finish;
	    }

	  /* append to logfile? */
	  if (append)
	    {
	      if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
		{
		  MSG (M_SYSERR, "Cannot seek to end of logfile: %s", log_path);
		  FindClose (find_handle);
		  goto finish;
		}
	    }

	  /* fill in STARTUPINFO struct */
	  GetStartupInfo(&start_info);
	  start_info.cb = sizeof(start_info);
	  start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
	  start_info.wShowWindow = SW_HIDE;
	  start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	  start_info.hStdOutput = start_info.hStdError = log_handle;

	  /* create an OpenVPN process for one config file */
	  if (!CreateProcess(exe_path,
			     command_line,
			     NULL,
			     NULL,
			     TRUE,
			     priority | CREATE_NEW_CONSOLE,
			     NULL,
			     config_dir,
			     &start_info,
			     &proc_info))
	    {
	      MSG (M_SYSERR, "CreateProcess failed, exe='%s' cmdline='%s' dir='%s'",
		   exe_path,
		   command_line,
		   config_dir);

	      FindClose (find_handle);
	      CloseHandle (log_handle);
	      goto finish;
	    }

	  /* close unneeded handles */
	  Sleep (1000); /* try to prevent race if we close logfile
			   handle before child process DUPs it */
	  if (!CloseHandle (proc_info.hProcess)
	      || !CloseHandle (proc_info.hThread)
	      || !CloseHandle (log_handle))
	    {
	      MSG (M_SYSERR, "CloseHandle failed");
	      goto finish;
	    }
	}

      /* more files to process? */
      more_files = FindNextFile (find_handle, &find_obj);

    } while (more_files);
    
    FindClose (find_handle);
  }

  /* we are now fully started */
  if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
    {
      MSG (M_ERR, "ReportStatusToSCMgr SERVICE_RUNNING failed");
      goto finish;
    }

  /* wait for our shutdown signal */
  if (WaitForSingleObject (exit_event, INFINITE) != WAIT_OBJECT_0)
    {
      MSG (M_ERR, "wait for shutdown signal failed");
    }

 finish:
  ServiceStop ();
  if (exit_event)
    CloseHandle (exit_event);
}
Exemplo n.º 6
0
void
redirect_stdout_stderr (const char *file, bool append)
{
#if defined(WIN32)
  if (!std_redir)
    {
      HANDLE log_handle;
      int log_fd;
      struct security_attributes sa;

      init_security_attributes_allow_all (&sa);

      log_handle = CreateFile (file,
			       GENERIC_WRITE,
			       FILE_SHARE_READ,
			       &sa.sa,
			       append ? OPEN_ALWAYS : CREATE_ALWAYS,
			       FILE_ATTRIBUTE_NORMAL,
			       NULL);

      if (log_handle == INVALID_HANDLE_VALUE)
	{
	  msg (M_WARN|M_ERRNO, "Warning: cannot open --log file: %s", file);
	  return;
	}

      /* append to logfile? */
      if (append)
	{
	  if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
	    msg (M_ERR, "Error: cannot seek to end of --log file: %s", file);
	}
      
      /* save original stderr for password prompts */
      orig_stderr = GetStdHandle (STD_ERROR_HANDLE);

      /* set up for redirection */
      if (!SetStdHandle (STD_OUTPUT_HANDLE, log_handle)
	  || !SetStdHandle (STD_ERROR_HANDLE, log_handle))
	msg (M_ERR, "Error: cannot redirect stdout/stderr to --log file: %s", file);

      /* direct stdout/stderr to point to log_handle */
      log_fd = _open_osfhandle ((intptr_t)log_handle, _O_TEXT);
      if (log_fd == -1)
	msg (M_ERR, "Error: --log redirect failed due to _open_osfhandle failure");
      
      /* open log_handle as FILE stream */
      ASSERT (msgfp == NULL);
      msgfp = _fdopen (log_fd, "w");
      if (msgfp == NULL)
	msg (M_ERR, "Error: --log redirect failed due to _fdopen");

      std_redir = true;
    }
#elif defined(HAVE_DUP2)
  if (!std_redir)
    {
      int out = open (file,
		      O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC),
		      S_IRUSR | S_IWUSR);

      if (out < 0)
	{
	  msg (M_WARN|M_ERRNO, "Warning: Error redirecting stdout/stderr to --log file: %s", file);
	  return;
	}

      if (dup2 (out, 1) == -1)
	msg (M_ERR, "--log file redirection error on stdout");
      if (dup2 (out, 2) == -1)
	msg (M_ERR, "--log file redirection error on stderr");

      if (out > 2)
	close (out);

      std_redir = true;
    }

#else
  msg (M_WARN, "WARNING: The --log option is not supported on this OS because it lacks the dup2 function");
#endif
}