text: /*
       This file is part of GNUnet.
       Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 GNUnet e.V.
  
       GNUnet is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published
       by the Free Software Foundation; either version 3, or (at your
       option) any later version.
  
       GNUnet 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 GNUnet; see the file COPYING.  If not, write to the
       Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       Boston, MA 02110-1301, USA.
  */
  
  /**
   * @file util/winproc.c
   * @brief Functions for MS Windows
   * @author Nils Durner
   */
  
  #include "platform.h"
  #include "gnunet_crypto_lib.h"
  #include "gnunet_common.h"
  
  
  #ifdef MINGW
  
  static HINSTANCE hNTDLL, hIphlpapi, hAdvapi, hNetapi;
  #ifdef W32_VEH
  static void *GNWinVEH_handle = NULL;
  #endif
  
  TNtQuerySystemInformation GNNtQuerySystemInformation;
  TGetIfEntry GNGetIfEntry;
  TGetIpAddrTable GNGetIpAddrTable;
  TGetIfTable GNGetIfTable;
  TOpenSCManager GNOpenSCManager;
  TCreateService GNCreateService;
  TCloseServiceHandle GNCloseServiceHandle;
  TDeleteService GNDeleteService;
  TRegisterServiceCtrlHandler GNRegisterServiceCtrlHandler;
  TSetServiceStatus GNSetServiceStatus;
  TStartServiceCtrlDispatcher GNStartServiceCtrlDispatcher;
  TControlService GNControlService;
  TOpenService GNOpenService;
  TGetBestInterfaceEx GNGetBestInterfaceEx;
  TGetAdaptersInfo GNGetAdaptersInfo;
  TNetUserAdd GNNetUserAdd;
  TNetUserSetInfo GNNetUserSetInfo;
  TLsaOpenPolicy GNLsaOpenPolicy;
  TLsaAddAccountRights GNLsaAddAccountRights;
  TLsaRemoveAccountRights GNLsaRemoveAccountRights;
  TLsaClose GNLsaClose;
  TLookupAccountName GNLookupAccountName;
  TGetFileSecurity GNGetFileSecurity;
  TInitializeSecurityDescriptor GNInitializeSecurityDescriptor;
  TGetSecurityDescriptorDacl GNGetSecurityDescriptorDacl;
  TGetAclInformation GNGetAclInformation;
  TInitializeAcl GNInitializeAcl;
  TGetAce GNGetAce;
  TEqualSid GNEqualSid;
  TAddAce GNAddAce;
  TAddAccessAllowedAce GNAddAccessAllowedAce;
  TSetNamedSecurityInfo GNSetNamedSecurityInfo;
  
  #define LOG(kind,...) GNUNET_log_from (kind, "winproc", __VA_ARGS__)
  /**
   * Log (panic) messages from PlibC
   */
  void
  plibc_panic (int err, char *msg)
  {
    LOG (((err == INT_MAX) ? GNUNET_ERROR_TYPE_DEBUG : GNUNET_ERROR_TYPE_ERROR),
         "%s", msg);
  }
  
  #ifdef W32_VEH
  /**
   * Handles exceptions (useful for debugging).
   * Issues a DebugBreak() call if the process is being debugged (not really
   * useful - if the process is being debugged, this handler won't be invoked
   * anyway). If it is not, runs a debugger from GNUNET_DEBUGGER env var,
   * substituting first %u in it for PID, and the second one for the event,
   * that should be set once the debugger attaches itself (otherwise the
   * only way out of WaitForSingleObject() is to time out after 1 minute).
   */
  LONG __stdcall
  GNWinVEH (PEXCEPTION_POINTERS ExceptionInfo)
  {
    char debugger[MAX_PATH + 1];
    char *debugger_env = NULL;
    if (IsDebuggerPresent ())
    {
      DebugBreak ();
      return EXCEPTION_CONTINUE_EXECUTION;
    }
    debugger_env = getenv ("GNUNET_DEBUGGER");
    if (debugger_env != NULL)
    {
      STARTUPINFO si;
      PROCESS_INFORMATION pi;
      HANDLE event;
      SECURITY_ATTRIBUTES sa;
      memset (&si, 0, sizeof (si));
      si.cb = sizeof (si);
      memset (&pi, 0, sizeof (pi));
      memset (&sa, 0, sizeof (sa));
      sa.nLength = sizeof (sa);
      sa.bInheritHandle = TRUE;
      event = CreateEvent (&sa, FALSE, FALSE, NULL);
      snprintf (debugger, MAX_PATH + 1, debugger_env, GetCurrentProcessId (), (uintptr_t) event);
      debugger[MAX_PATH] = '\0';
      if (0 != CreateProcessA (NULL, debugger, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
      {
        CloseHandle (pi.hProcess);
        CloseHandle (pi.hThread);
        WaitForSingleObject (event, 60000);
        CloseHandle (event);
        if (IsDebuggerPresent ())
        {
          return EXCEPTION_CONTINUE_EXECUTION;
        }
      }
      else
        CloseHandle (event);
    }
    return EXCEPTION_CONTINUE_SEARCH;
  }
  #endif
  
  /**
   * @brief Initialize PlibC and set up Windows environment
   * @param logging context, NULL means stderr
   * @return Error code from winerror.h, ERROR_SUCCESS on success
  */
  int
  GNInitWinEnv ()
  {
    int ret;
  
    plibc_initialized ();
    plibc_set_panic_proc (plibc_panic);
    ret = plibc_init_utf8 ("GNU", PACKAGE, 1);
    plibc_set_stat_size_size (sizeof (((struct stat *) 0)->st_size));
    plibc_set_stat_time_size (sizeof (((struct stat *) 0)->st_mtime));
    /* don't load other DLLs twice */
    if (hNTDLL)
      return ret;
  
  #ifdef W32_VEH
    if (GNWinVEH_handle == NULL)
    {
      GNWinVEH_handle = AddVectoredExceptionHandler (1, &GNWinVEH);
      if (GNWinVEH_handle == NULL)
      {
        /* This is bad, but what can we do? */
        printf ("Failed to set up an exception handler!\n");
      }
    }
  #endif
  
    hNTDLL = LoadLibrary ("ntdll.dll");
  
    /* Function to get CPU usage under Win NT */
    if (hNTDLL)
    {
      GNNtQuerySystemInformation =
          (TNtQuerySystemInformation) GetProcAddress (hNTDLL,
                                                      "NtQuerySystemInformation");
    }
    else
    {
      GNNtQuerySystemInformation = NULL;
    }
  
    /* Functions to get information about a network adapter */
    hIphlpapi = LoadLibrary ("iphlpapi.dll");
    if (hIphlpapi)
    {
      GNGetIfEntry = (TGetIfEntry) GetProcAddress (hIphlpapi, "GetIfEntry");
      GNGetIpAddrTable =
          (TGetIpAddrTable) GetProcAddress (hIphlpapi, "GetIpAddrTable");
      GNGetIfTable = (TGetIfTable) GetProcAddress (hIphlpapi, "GetIfTable");
      GNGetBestInterfaceEx =
          (TGetBestInterfaceEx) GetProcAddress (hIphlpapi, "GetBestInterfaceEx");
      GNGetAdaptersInfo =
          (TGetAdaptersInfo) GetProcAddress (hIphlpapi, "GetAdaptersInfo");
    }
    else
    {
      GNGetIfEntry = NULL;
      GNGetIpAddrTable = NULL;
      GNGetIfTable = NULL;
      GNGetBestInterfaceEx = NULL;
      GNGetAdaptersInfo = NULL;
    }
  
    /* Service & Account functions */
    hAdvapi = LoadLibrary ("advapi32.dll");
    if (hAdvapi)
    {
      GNOpenSCManager =
          (TOpenSCManager) GetProcAddress (hAdvapi, "OpenSCManagerA");
      GNCreateService =
          (TCreateService) GetProcAddress (hAdvapi, "CreateServiceA");
      GNCloseServiceHandle =
          (TCloseServiceHandle) GetProcAddress (hAdvapi, "CloseServiceHandle");
      GNDeleteService =
          (TDeleteService) GetProcAddress (hAdvapi, "DeleteService");
      GNRegisterServiceCtrlHandler =
          (TRegisterServiceCtrlHandler) GetProcAddress (hAdvapi,
                                                        "RegisterServiceCtrlHandlerA");
      GNSetServiceStatus =
          (TSetServiceStatus) GetProcAddress (hAdvapi, "SetServiceStatus");
      GNStartServiceCtrlDispatcher =
          (TStartServiceCtrlDispatcher) GetProcAddress (hAdvapi,
                                                        "StartServiceCtrlDispatcherA");
      GNControlService =
          (TControlService) GetProcAddress (hAdvapi, "ControlService");
      GNOpenService = (TOpenService) GetProcAddress (hAdvapi, "OpenServiceA");
  
      GNLsaOpenPolicy =
          (TLsaOpenPolicy) GetProcAddress (hAdvapi, "LsaOpenPolicy");
      GNLsaAddAccountRights =
          (TLsaAddAccountRights) GetProcAddress (hAdvapi, "LsaAddAccountRights");
      GNLsaRemoveAccountRights =
          (TLsaRemoveAccountRights) GetProcAddress (hAdvapi,
                                                    "LsaRemoveAccountRights");
      GNLsaClose = (TLsaClose) GetProcAddress (hAdvapi, "LsaClose");
      GNLookupAccountName =
          (TLookupAccountName) GetProcAddress (hAdvapi, "LookupAccountNameA");
  
      GNGetFileSecurity =
          (TGetFileSecurity) GetProcAddress (hAdvapi, "GetFileSecurityA");
      GNInitializeSecurityDescriptor =
          (TInitializeSecurityDescriptor) GetProcAddress (hAdvapi,
                                                          "InitializeSecurityDescriptor");
      GNGetSecurityDescriptorDacl =
          (TGetSecurityDescriptorDacl) GetProcAddress (hAdvapi,
                                                       "GetSecurityDescriptorDacl");
      GNGetAclInformation =
          (TGetAclInformation) GetProcAddress (hAdvapi, "GetAclInformation");
      GNInitializeAcl =
          (TInitializeAcl) GetProcAddress (hAdvapi, "InitializeAcl");
      GNGetAce = (TGetAce) GetProcAddress (hAdvapi, "GetAce");
      GNEqualSid = (TEqualSid) GetProcAddress (hAdvapi, "EqualSid");
      GNAddAce = (TAddAce) GetProcAddress (hAdvapi, "AddAce");
      GNAddAccessAllowedAce =
          (TAddAccessAllowedAce) GetProcAddress (hAdvapi, "AddAccessAllowedAce");
      GNSetNamedSecurityInfo =
          (TSetNamedSecurityInfo) GetProcAddress (hAdvapi,
                                                  "SetNamedSecurityInfoA");
    }
    else
    {
      GNOpenSCManager = NULL;
      GNCreateService = NULL;
      GNCloseServiceHandle = NULL;
      GNDeleteService = NULL;
      GNRegisterServiceCtrlHandler = NULL;
      GNSetServiceStatus = NULL;
      GNStartServiceCtrlDispatcher = NULL;
      GNControlService = NULL;
      GNOpenService = NULL;
  
      GNLsaOpenPolicy = NULL;
      GNLsaAddAccountRights = NULL;
      GNLsaRemoveAccountRights = NULL;
      GNLsaClose = NULL;
      GNLookupAccountName = NULL;
  
      GNGetFileSecurity = NULL;
      GNInitializeSecurityDescriptor = NULL;
      GNGetSecurityDescriptorDacl = NULL;
      GNGetAclInformation = NULL;
      GNInitializeAcl = NULL;
      GNGetAce = NULL;
      GNEqualSid = NULL;
      GNAddAce = NULL;
      GNAddAccessAllowedAce = NULL;
      GNSetNamedSecurityInfo = NULL;
    }
  
    /* Account function */
    hNetapi = LoadLibrary ("netapi32.dll");
    if (hNetapi)
    {
      GNNetUserAdd = (TNetUserAdd) GetProcAddress (hNetapi, "NetUserAdd");
      GNNetUserSetInfo =
          (TNetUserSetInfo) GetProcAddress (hNetapi, "NetUserSetInfo");
    }
    else
    {
      GNNetUserAdd = NULL;
      GNNetUserSetInfo = NULL;
    }
  
    return ret;
  }
  
  /**
   * Clean up Windows environment
   */
  void
  GNShutdownWinEnv ()
  {
    plibc_shutdown ();
  
  #ifdef W32_VEH
    if (GNWinVEH_handle != NULL)
    {
      RemoveVectoredExceptionHandler (GNWinVEH_handle);
      GNWinVEH_handle = NULL;
    }
  #endif
  
    FreeLibrary (hNTDLL);
    FreeLibrary (hIphlpapi);
    FreeLibrary (hAdvapi);
    FreeLibrary (hNetapi);
  
    CoUninitialize ();
  }
  
  #endif /* MINGW */
  
  #if !HAVE_ATOLL
  long long
  atoll (const char *nptr)
  {
    return atol (nptr);
  }
  #endif
  