Пример #1
0
/*
 * Entry point for register-dns thread.
 */
static DWORD WINAPI
RegisterDNS (LPVOID unused)
{
  DWORD err;
  DWORD i;
  WCHAR sys_path[MAX_PATH];
  DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */

  /* default paths of net and ipconfig commands */
  WCHAR net[MAX_PATH]   = L"C:\\Windows\\system32\\net.exe";
  WCHAR ipcfg[MAX_PATH] = L"C:\\Windows\\system32\\ipconfig.exe";

  struct
    {
      WCHAR *argv0;
      WCHAR *cmdline;
      DWORD timeout;
    } cmds [] = {
                  { net,   L"net stop dnscache",     timeout },
                  { net,   L"net start dnscache",    timeout },
                  { ipcfg, L"ipconfig /flushdns",    timeout },
                  { ipcfg, L"ipconfig /registerdns", timeout },
                };
  int ncmds = sizeof (cmds) / sizeof (cmds[0]);

  HANDLE wait_handles[2] = {rdns_semaphore, exit_event};

  if(GetSystemDirectory(sys_path, MAX_PATH))
    {
      _snwprintf (net, MAX_PATH, L"%s\\%s", sys_path, L"net.exe");
      net[MAX_PATH-1] = L'\0';

      _snwprintf (ipcfg, MAX_PATH, L"%s\\%s", sys_path, L"ipconfig.exe");
      ipcfg[MAX_PATH-1] = L'\0';
    }

  if (WaitForMultipleObjects (2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
    {
      /* Semaphore locked */
      for (i = 0; i < ncmds; ++i)
        {
          ExecCommand (cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
        }
      err = 0;
      if ( !ReleaseSemaphore (rdns_semaphore, 1, NULL) )
        err = MsgToEventLog (M_SYSERR, TEXT("RegisterDNS: Failed to release regsiter-dns semaphore:"));
    }
  else
    {
      MsgToEventLog (M_ERR, TEXT("RegisterDNS: Failed to lock register-dns semaphore"));
      err = ERROR_SEM_TIMEOUT;  /* Windows error code 0x79 */
    }
  return err;
}
Пример #2
0
/*
 * Execute a command and return its exit code. If timeout > 0, terminate
 * the process if still running after timeout milliseconds. In that case
 * the return value is the windows error code WAIT_TIMEOUT = 0x102
 */
static DWORD
ExecCommand (const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
{
  DWORD exit_code;
  STARTUPINFOW si;
  PROCESS_INFORMATION pi;
  DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT;
  WCHAR *cmdline_dup = NULL;

  ZeroMemory (&si, sizeof(si));
  ZeroMemory (&pi, sizeof(pi));

  si.cb = sizeof(si);

  /* CreateProcess needs a modifiable cmdline: make a copy */
  cmdline_dup = wcsdup (cmdline);
  if ( cmdline_dup && CreateProcessW (argv0, cmdline_dup, NULL, NULL, FALSE,
                                      proc_flags, NULL, NULL, &si, &pi) )
    {
      WaitForSingleObject (pi.hProcess, timeout ? timeout : INFINITE);
      if (!GetExitCodeProcess (pi.hProcess, &exit_code))
        {
          MsgToEventLog (M_SYSERR, TEXT("ExecCommand: Error getting exit_code:"));
          exit_code = GetLastError();
        }
      else if (exit_code == STILL_ACTIVE)
        {
          exit_code = WAIT_TIMEOUT;  /* Windows error code 0x102 */

          /* kill without impunity */
          TerminateProcess (pi.hProcess, exit_code);
          MsgToEventLog (M_ERR, TEXT("ExecCommand: \"%s %s\" killed after timeout"),
            argv0, cmdline);
        }
      else if (exit_code)
          MsgToEventLog (M_ERR, TEXT("ExecCommand: \"%s %s\" exited with status = %lu"),
                          argv0, cmdline, exit_code);
      else
          MsgToEventLog (M_INFO, TEXT("ExecCommand: \"%s %s\" completed"), argv0, cmdline);

      CloseHandle(pi.hProcess);
      CloseHandle(pi.hThread);
    }
  else
    {
      exit_code = GetLastError();
      MsgToEventLog (M_SYSERR, TEXT("ExecCommand: could not run \"%s %s\" :"),
                                      argv0, cmdline);
    }

  free (cmdline_dup);
  return exit_code;
}
Пример #3
0
BOOL
ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
{
    static DWORD dwCheckPoint = 1;
    BOOL res = TRUE;

    if (status->dwCurrentState == SERVICE_START_PENDING)
    {
        status->dwControlsAccepted = 0;
    }
    else
    {
        status->dwControlsAccepted = SERVICE_ACCEPT_STOP;
    }

    if (status->dwCurrentState == SERVICE_RUNNING
        || status->dwCurrentState == SERVICE_STOPPED)
    {
        status->dwCheckPoint = 0;
    }
    else
    {
        status->dwCheckPoint = dwCheckPoint++;
    }

    /* Report the status of the service to the service control manager. */
    res = SetServiceStatus(service, status);
    if (!res)
    {
        MsgToEventLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus"));
    }

    return res;
}
Пример #4
0
int
_tmain(int argc, TCHAR *argv[])
{
    SERVICE_TABLE_ENTRY dispatchTable[] = {
        { automatic_service.name, ServiceStartAutomatic },
        { interactive_service.name, ServiceStartInteractive },
        { NULL, NULL }
    };

    openvpn_service[0] = automatic_service;
    openvpn_service[1] = interactive_service;

    if (argc > 1 && (*argv[1] == TEXT('-') || *argv[1] == TEXT('/')))
    {
        if (_tcsicmp(TEXT("install"), argv[1] + 1) == 0)
        {
            return CmdInstallServices();
        }
        else if (_tcsicmp(TEXT("remove"), argv[1] + 1) == 0)
        {
            return CmdRemoveServices();
        }
        else if (_tcsicmp(TEXT("start"), argv[1] + 1) == 0)
        {
            BOOL is_auto = argc < 3 || _tcsicmp(TEXT("interactive"), argv[2]) != 0;
            return CmdStartService(is_auto ? automatic : interactive);
        }
        else
        {
            goto dispatch;
        }

        return 0;
    }

    /* If it doesn't match any of the above parameters
     * the service control manager may be starting the service
     * so we must call StartServiceCtrlDispatcher
     */
dispatch:
    _tprintf(TEXT("%s -install        to install the services\n"), APPNAME);
    _tprintf(TEXT("%s -start <name>   to start a service (\"automatic\" or \"interactive\")\n"), APPNAME);
    _tprintf(TEXT("%s -remove         to remove the services\n"), APPNAME);
    _tprintf(TEXT("\nStartServiceCtrlDispatcher being called.\n"));
    _tprintf(TEXT("This may take several seconds. Please wait.\n"));

    if (!StartServiceCtrlDispatcher(dispatchTable))
    {
        MsgToEventLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed."));
    }

    return 0;
}
Пример #5
0
static VOID
ReturnError (HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
{
  DWORD result_len;
  LPWSTR result = L"0xffffffff\nFormatMessage failed\nCould not return result";
  DWORD_PTR args[] = {
    (DWORD_PTR) error,
    (DWORD_PTR) func,
    (DWORD_PTR) ""
  };

  if (error != ERROR_OPENVPN_STARTUP)
    {
      FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
                      FORMAT_MESSAGE_ALLOCATE_BUFFER |
                      FORMAT_MESSAGE_IGNORE_INSERTS,
                      0, error, 0, (LPWSTR) &args[2], 0, NULL);
    }

  result_len = FormatMessageW (FORMAT_MESSAGE_FROM_STRING |
                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
                               FORMAT_MESSAGE_ARGUMENT_ARRAY,
                               L"0x%1!08x!\n%2!s!\n%3!s!", 0, 0,
                               (LPWSTR) &result, 0, (va_list*) args);

  WritePipeAsync (pipe, result, wcslen (result) * 2, count, events);
#ifdef UNICODE
  MsgToEventLog (MSG_FLAGS_ERROR, result);
#else
  MsgToEventLog (MSG_FLAGS_ERROR, "%S", result);
#endif

  if (error != ERROR_OPENVPN_STARTUP)
    LocalFree ((LPVOID) args[2]);
  if (result_len)
    LocalFree (result);
}
Пример #6
0
static void
BlockDNSErrHandler (DWORD err, const char *msg)
{
  TCHAR buf[256];
  LPCTSTR err_str;

  if (!err) return;

  err_str = TEXT("Unknown Win32 Error");

  if (FormatMessage (FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM
                          | FORMAT_MESSAGE_ARGUMENT_ARRAY,
                          NULL, err, 0, buf, sizeof (buf), NULL))
    {
      err_str = buf;
    }

#ifdef UNICODE
  MsgToEventLog (M_ERR, L"%S (status = %lu): %s", msg, err, err_str);
#else
  MsgToEventLog (M_ERR, "%s (status = %lu): %s", msg, err, err_str);
#endif

}
Пример #7
0
static DWORD
GetRegString (HKEY key, LPCTSTR value, LPTSTR data, DWORD size)
{
  DWORD type;
  LONG status = RegQueryValueEx (key, value, NULL, &type, (LPBYTE) data, &size);

  if (status == ERROR_SUCCESS && type != REG_SZ)
    status = ERROR_DATATYPE_MISMATCH;

  if (status != ERROR_SUCCESS)
    {
      SetLastError (status);
      return MsgToEventLog (M_SYSERR, TEXT("Error querying registry value: HKLM\\%s\\%s"), REG_KEY, value);
    }

  return ERROR_SUCCESS;
}
Пример #8
0
static DWORD
HandleBlockDNSMessage (const block_dns_message_t *msg, undo_lists_t *lists)
{
  DWORD err = 0;
  HANDLE engine = NULL;
  LPCWSTR exe_path;

#ifdef UNICODE
  exe_path = settings.exe_path;
#else
  WCHAR wide_path[MAX_PATH];
  MultiByteToWideChar (CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH);
  exe_path = wide_path;
#endif

  if (msg->header.type == msg_add_block_dns)
    {
      err = add_block_dns_filters (&engine, msg->iface.index, exe_path, BlockDNSErrHandler);
      if (!err)
        err = AddListItem (&(*lists)[block_dns], engine);
    }
  else
    {
      engine = RemoveListItem (&(*lists)[block_dns], CmpEngine, NULL);
      if (engine)
        {
          err = delete_block_dns_filters (engine);
          engine = NULL;
        }
      else
        MsgToEventLog (M_ERR, TEXT("No previous block DNS filters to delete"));
    }

  if (err && engine)
    {
      delete_block_dns_filters (engine);
    }

  return err;
}
Пример #9
0
/*
 * Check workdir\fname is inside config_dir
 * The logic here is simple: we may reject some valid paths if ..\ is in any of the strings
 */
static BOOL
CheckConfigPath(const WCHAR *workdir, const WCHAR *fname, const settings_t *s)
{
    WCHAR tmp[MAX_PATH];
    const WCHAR *config_file = NULL;
    const WCHAR *config_dir = NULL;

    /* convert fname to full path */
    if (PathIsRelativeW(fname) )
    {
        snwprintf(tmp, _countof(tmp), L"%s\\%s", workdir, fname);
        tmp[_countof(tmp)-1] = L'\0';
        config_file = tmp;
    }
    else
    {
        config_file = fname;
    }

#ifdef UNICODE
    config_dir = s->config_dir;
#else
    if (MultiByteToWideChar(CP_UTF8, 0, s->config_dir, -1, widepath, MAX_PATH) == 0)
    {
        MsgToEventLog(M_SYSERR, TEXT("Failed to convert config_dir name to WideChar"));
        return FALSE;
    }
    config_dir = widepath;
#endif

    if (wcsncmp(config_dir, config_file, wcslen(config_dir)) == 0
        && wcsstr(config_file + wcslen(config_dir), L"..") == NULL)
    {
        return TRUE;
    }

    return FALSE;
}
Пример #10
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);
}
Пример #11
0
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;
}
Пример #12
0
static BOOL
GetStartupData (HANDLE pipe, STARTUP_DATA *sud)
{
  size_t len;
  BOOL ret = FALSE;
  WCHAR *data = NULL;
  DWORD size, bytes, read;

  bytes = PeekNamedPipeAsync (pipe, 1, &exit_event);
  if (bytes == 0)
    {
      MsgToEventLog (M_SYSERR, TEXT("PeekNamedPipeAsync failed"));
      ReturnLastError (pipe, L"PeekNamedPipeAsync");
      goto out;
    }

  size = bytes / sizeof (*data);
  data = malloc (bytes);
  if (data == NULL)
    {
      MsgToEventLog (M_SYSERR, TEXT("malloc failed"));
      ReturnLastError (pipe, L"malloc");
      goto out;
    }

  read = ReadPipeAsync (pipe, data, bytes, 1, &exit_event);
  if (bytes != read)
  {
      MsgToEventLog (M_SYSERR, TEXT("ReadPipeAsync failed"));
      ReturnLastError (pipe, L"ReadPipeAsync");
      goto out;
  }

  if (data[size - 1] != 0)
    {
      MsgToEventLog (M_ERR, TEXT("Startup data is not NULL terminated"));
      ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
      goto out;
    }

  sud->directory = data;
  len = wcslen (sud->directory) + 1;
  size -= len;
  if (size <= 0)
    {
      MsgToEventLog (M_ERR, TEXT("Startup data ends at working directory"));
      ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
      goto out;
    }

  sud->options = sud->directory + len;
  len = wcslen (sud->options) + 1;
  size -= len;
  if (size <= 0)
    {
      MsgToEventLog (M_ERR, TEXT("Startup data ends at command line options"));
      ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
      goto out;
    }

  sud->std_input = sud->options + len;
  data = NULL; /* don't free data */
  ret = TRUE;

out:
  free (data);
  return ret;
}
Пример #13
0
/*
 * Check whether user is a member of Administrators group or
 * the group specified in s->ovpn_admin_group
 */
BOOL
IsAuthorizedUser(SID *sid, settings_t *s)
{
    LOCALGROUP_USERS_INFO_0 *groups = NULL;
    DWORD nread;
    DWORD nmax;
    WCHAR *tmp = NULL;
    const WCHAR *admin_group[2];
    WCHAR username[MAX_NAME];
    WCHAR domain[MAX_NAME];
    WCHAR sysadmin_group[MAX_NAME];
    DWORD err, len = MAX_NAME;
    int i;
    BOOL ret = FALSE;
    SID_NAME_USE sid_type;

    /* Get username */
    if (!LookupAccountSidW(NULL, sid, username, &len, domain, &len, &sid_type))
    {
        MsgToEventLog(M_SYSERR, TEXT("LookupAccountSid"));
        goto out;
    }

    /* Get an array of groups the user is member of */
    err = NetUserGetLocalGroups(NULL, username, 0, LG_INCLUDE_INDIRECT, (LPBYTE *) &groups,
                                MAX_PREFERRED_LENGTH, &nread, &nmax);
    if (err && err != ERROR_MORE_DATA)
    {
        SetLastError(err);
        MsgToEventLog(M_SYSERR, TEXT("NetUserGetLocalGroups"));
        goto out;
    }

    if (GetBuiltinAdminGroupName(sysadmin_group, _countof(sysadmin_group)))
    {
        admin_group[0] = sysadmin_group;
    }
    else
    {
        MsgToEventLog(M_SYSERR, TEXT("Failed to get the name of Administrators group. Using the default."));
        /* use the default value */
        admin_group[0] = SYSTEM_ADMIN_GROUP;
    }

#ifdef UNICODE
    admin_group[1] = s->ovpn_admin_group;
#else
    tmp = NULL;
    len = MultiByteToWideChar(CP_UTF8, 0, s->ovpn_admin_group, -1, NULL, 0);
    if (len == 0 || (tmp = malloc(len*sizeof(WCHAR))) == NULL)
    {
        MsgToEventLog(M_SYSERR, TEXT("Failed to convert admin group name to WideChar"));
        goto out;
    }
    MultiByteToWideChar(CP_UTF8, 0, s->ovpn_admin_group, -1, tmp, len);
    admin_group[1] = tmp;
#endif

    /* Check if user's groups include any of the admin groups */
    for (i = 0; i < nread; i++)
    {
        if (wcscmp(groups[i].lgrui0_name, admin_group[0]) == 0
            || wcscmp(groups[i].lgrui0_name, admin_group[1]) == 0
            )
        {
            MsgToEventLog(M_INFO, TEXT("Authorizing user %s by virtue of membership in group %s"),
                          username, groups[i].lgrui0_name);
            ret = TRUE;
            break;
        }
    }

out:
    if (groups)
    {
        NetApiBufferFree(groups);
    }
    free(tmp);

    return ret;
}