DWORD
MsgToEventLog (DWORD flags, LPCTSTR format, ...)
{
  HANDLE hEventSource;
  TCHAR msg[2][256];
  DWORD error = 0;
  LPCTSTR err_msg = TEXT("");
  va_list arglist;

  if (flags & MSG_FLAGS_SYS_CODE)
    {
      error = GetLastError ();
      err_msg = GetLastErrorText ();
    }

  hEventSource = RegisterEventSource (NULL, APPNAME);
  if (hEventSource != NULL)
    {
      openvpn_sntprintf (msg[0], _countof (msg[0]),
                         TEXT("%s%s: %s"), APPNAME,
                         (flags & MSG_FLAGS_ERROR) ? TEXT(" error") : TEXT(""), err_msg);

      va_start (arglist, format);
      openvpn_vsntprintf (msg[1], _countof (msg[1]), format, arglist);
      va_end (arglist);

      const TCHAR *mesg[] = { msg[0], msg[1] };
      ReportEvent (hEventSource, flags & MSG_FLAGS_ERROR ?
                   EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
                   0, 0, NULL, 2, 0, mesg, NULL);
      DeregisterEventSource (hEventSource);
    }

  return error;
}
LPCTSTR
GetLastErrorText ()
{
  static TCHAR buf[256];
  DWORD len;
  LPTSTR tmp = NULL;

  len = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
                       NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&tmp, 0, NULL);

  if (len == 0 || (long) _countof (buf) < (long) len + 14)
    buf[0] = TEXT('\0');
  else
    {
      tmp[_tcslen (tmp) - 2] = TEXT('\0');  /* remove CR/LF characters */
      openvpn_sntprintf (buf, _countof (buf), TEXT("%s (0x%x)"), tmp, GetLastError());
    }

  if (tmp)
    LocalFree (tmp);

  return buf;
}
Example #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);
}
DWORD
GetOpenvpnSettings (settings_t *s)
{
  TCHAR priority[64];
  TCHAR append[2];
  DWORD error;
  HKEY key;

  LONG status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_KEY, 0, KEY_READ, &key);
  if (status != ERROR_SUCCESS)
    {
      SetLastError (status);
      return MsgToEventLog (M_SYSERR, TEXT("Could not open Registry key HKLM\\%s not found"), REG_KEY);
    }

  error = GetRegString (key, TEXT("exe_path"), s->exe_path, sizeof (s->exe_path));
  if (error != ERROR_SUCCESS)
    goto out;

  error = GetRegString (key, TEXT("config_dir"), s->config_dir, sizeof (s->config_dir));
  if (error != ERROR_SUCCESS)
    goto out;

  error = GetRegString (key, TEXT("config_ext"), s->ext_string, sizeof (s->ext_string));
  if (error != ERROR_SUCCESS)
    goto out;

  error = GetRegString (key, TEXT("log_dir"), s->log_dir, sizeof (s->log_dir));
  if (error != ERROR_SUCCESS)
    goto out;

  error = GetRegString (key, TEXT("priority"), priority, sizeof (priority));
  if (error != ERROR_SUCCESS)
    goto out;

  error = GetRegString (key, TEXT("log_append"), append, sizeof (append));
  if (error != ERROR_SUCCESS)
    goto out;

  /* read if present, else use default */
  error = GetRegString (key, TEXT("ovpn_admin_group"), s->ovpn_admin_group, sizeof (s->ovpn_admin_group));
  if (error != ERROR_SUCCESS)
  {
    openvpn_sntprintf(s->ovpn_admin_group, _countof(s->ovpn_admin_group), OVPN_ADMIN_GROUP);
    error = 0; /* this error is not fatal */
  }
  /* set process priority */
  if (!_tcsicmp (priority, TEXT("IDLE_PRIORITY_CLASS")))
    s->priority = IDLE_PRIORITY_CLASS;
  else if (!_tcsicmp (priority, TEXT("BELOW_NORMAL_PRIORITY_CLASS")))
    s->priority = BELOW_NORMAL_PRIORITY_CLASS;
  else if (!_tcsicmp (priority, TEXT("NORMAL_PRIORITY_CLASS")))
    s->priority = NORMAL_PRIORITY_CLASS;
  else if (!_tcsicmp (priority, TEXT("ABOVE_NORMAL_PRIORITY_CLASS")))
    s->priority = ABOVE_NORMAL_PRIORITY_CLASS;
  else if (!_tcsicmp (priority, TEXT("HIGH_PRIORITY_CLASS")))
    s->priority = HIGH_PRIORITY_CLASS;
  else
    {
      SetLastError (ERROR_INVALID_DATA);
      error = MsgToEventLog (M_SYSERR, TEXT("Unknown priority name: %s"), priority);
      goto out;
    }

  /* set log file append/truncate flag */
  if (append[0] == TEXT('0'))
    s->append = FALSE;
  else if (append[0] == TEXT('1'))
    s->append = TRUE;
  else
    {
      SetLastError (ERROR_INVALID_DATA);
      error = MsgToEventLog (M_ERR, TEXT("Log file append flag (given as '%s') must be '0' or '1'"), append);
      goto out;
    }

out:
  RegCloseKey (key);
  return error;
}