mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

jvergara
18.28.2007 076e8757ee775d69a1dad8c5349074d28c9542ef
Fix for issue 1603 (quickInstall fails to register service on vista)

With the new user access control of Vista, even if we are administrators we are not allowed to do certain operations (such as writing in the service registry) in some circumstances. For instance if we launch net start <service_name> from a normal command prompt this will fail systematically. In order to be able to execute these "privileged" operations we have different alternatives:

Execute the binary that will do the operations using the "Run as Administrator" option in Vista (or launching them from a command prompt that has been started using that same option).
Add a manifest to the binary informing that the binary requires administrator privileges.

The first alternative is one of the workarounds for the bug, however it does not apply to the case of the Java Web Start Installer.

The second alternative is in what consists the bug fix. A new binary has been created. This binary has a manifest informing that it requires administrator privileges. This binary will be used in Vista as a wrapper to call operations that require administrator privileges (modifying the registry in windows-services.bat command line and calling "net start" and "net stop").

If the user is running the setup, the status-panel using the "Run as Administrator" option or is using the command lines from a command prompt launched with that option the behavior in Vista does not change with the behavior in previous versions of Windows.

If the UAC is enabled and the user is not using the "Run as Administrator" options, (s)he will be prompted for confirmation each time the registry is modified and the server is started or stopped as a service. The wrapper is called on any of the individual operations. An alternative would be to call the wrapper when we launch the setup or the status-panel but this generates some issues:
1. This does not work (directly) with the Java Web Start installer.
2. This would force users that are not administrators to provide administrator credentials even to install/run an OpenDS that does not require to do privileged operations (an OpenDS that does not run as a service).
3 files added
16 files modified
580 ■■■■ changed files
opends/lib/launcher_administrator.exe patch | view | raw | blame | history
opends/lib/opends_service.exe patch | view | raw | blame | history
opends/lib/winlauncher.exe patch | view | raw | blame | history
opends/resource/bin/_client-script.bat 2 ●●● patch | view | raw | blame | history
opends/resource/bin/start-ds.bat 4 ●●●● patch | view | raw | blame | history
opends/resource/bin/status-panel.bat 2 ●●● patch | view | raw | blame | history
opends/resource/setup.bat 2 ●●● patch | view | raw | blame | history
opends/resource/uninstall.bat 2 ●●● patch | view | raw | blame | history
opends/src/build-tools/windows/Makefile 20 ●●●● patch | view | raw | blame | history
opends/src/build-tools/windows/README 12 ●●●●● patch | view | raw | blame | history
opends/src/build-tools/windows/common.c 12 ●●●●● patch | view | raw | blame | history
opends/src/build-tools/windows/launcher_administrator.exe.manifest 16 ●●●●● patch | view | raw | blame | history
opends/src/build-tools/windows/opends_service.exe.manifest 16 ●●●●● patch | view | raw | blame | history
opends/src/build-tools/windows/service.c 135 ●●●●● patch | view | raw | blame | history
opends/src/build-tools/windows/winlauncher.c 130 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/ConfigureWindowsService.java 153 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/StartWindowsService.java 27 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/StopWindowsService.java 27 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/SetupUtils.java 20 ●●●●● patch | view | raw | blame | history
opends/lib/launcher_administrator.exe
Binary files differ
opends/lib/opends_service.exe
Binary files differ
opends/lib/winlauncher.exe
Binary files differ
opends/resource/bin/_client-script.bat
@@ -25,7 +25,7 @@
rem
rem      Portions Copyright 2006-2007 Sun Microsystems, Inc.
rem This script is used to invoke various server-side processes.  It should not
rem This script is used to invoke various client-side processes.  It should not
rem be invoked directly by end users.
setlocal
opends/resource/bin/start-ds.bat
@@ -111,7 +111,7 @@
goto end
:runDetachCalledByWinService
rem We write the output of the start command to the winwervice.out file.
rem We write the output of the start command to the winservice.out file.
echo %SCRIPT%: Run detach called by windows service  >> %LOG%
if not exist "%DIR_HOME%\logs\server.out" echo. > "%DIR_HOME%\logs\server.out"
if not exist "%DIR_HOME%\logs\server.starting" echo. > "%DIR_HOME%\logs\server.starting"
@@ -133,4 +133,4 @@
if exist "%DIR_HOME%\logs\winservice.out" erase "%DIR_HOME%\logs\winservice.out"
:end
echo %SCRIPT%: finished >> %LOG%
echo %SCRIPT%: finished >> %LOG%
opends/resource/bin/status-panel.bat
@@ -57,7 +57,7 @@
set PATH=%SystemRoot%
"%DIR_HOME%\lib\winlauncher.exe" launch "%DIR_HOME%" "%JAVA_BIN%" %JAVA_ARGS%  org.opends.statuspanel.StatusPanelLauncher %*
"%DIR_HOME%\lib\winlauncher.exe" launch "%JAVA_BIN%" %JAVA_ARGS%  org.opends.statuspanel.StatusPanelLauncher %*
goto end
opends/resource/setup.bat
@@ -72,7 +72,7 @@
goto callJava
:callLaunch
"%DIR_HOME%\lib\winlauncher.exe" launch "%DIR_HOME%" "%JAVA_BIN%" %JAVA_ARGS% org.opends.quicksetup.installer.InstallLauncher -P setup.bat
"%DIR_HOME%\lib\winlauncher.exe" launch "%JAVA_BIN%" %JAVA_ARGS% org.opends.quicksetup.installer.InstallLauncher -P setup.bat
goto end
:callJava
opends/resource/uninstall.bat
@@ -72,7 +72,7 @@
goto callJava
:callLaunch
"%DIR_HOME%\lib\winlauncher.exe" launch "%DIR_HOME%" "%JAVA_BIN%" %JAVA_ARGS% org.opends.quicksetup.uninstaller.UninstallLauncher
"%DIR_HOME%\lib\winlauncher.exe" launch "%JAVA_BIN%" %JAVA_ARGS% org.opends.quicksetup.uninstaller.UninstallLauncher
goto end
:callJava
opends/src/build-tools/windows/Makefile
@@ -44,13 +44,15 @@
CC=cl
SERVICE_PROGNAME=opends_service.exe
LAUNCHER_ADMINISTRATOR_PROGNAME=launcher_administrator.exe
WINLAUNCHER_PROGNAME=winlauncher.exe
LINKER=link -nologo
LINKER=link -nologo /machine:x86
LIBS=advapi32.lib
CFLAGS= -D_WINDOWS  -nologo -MD  -W3 -O2 -G6
CFLAGS= -D_WINDOWS  -nologo  -W3 -O2
RC=rc
MC=mc
MT=mt
SRCS = common.c winlauncher.c service.c 
@@ -65,6 +67,9 @@
RES_FILE = EventLogMsg.res
SERVICE_MANIFEST_FILE = opends_service.exe.manifest
LAUNCHER_ADMINISTRATOR_MANIFEST_FILE = launcher_administrator.exe.manifest
.c.obj:
  $(CC) $(CFLAGS) -c $< -Fo$@
  
@@ -73,14 +78,19 @@
  $(RC) /fo $(RES_FILE) $(RC_FILE)
all: $(SERVICE_PROGNAME) $(WINLAUNCHER_PROGNAME)
all: $(SERVICE_PROGNAME) $(WINLAUNCHER_PROGNAME) $(LAUNCHER_ADMINISTRATOR_PROGNAME)
$(SERVICE_PROGNAME) : $(RES_FILE) $(SERVICE_OBJS)
  $(LINKER) /OUT:$(SERVICE_PROGNAME) $(RES_FILE) $(SERVICE_OBJS) $(LIBS)
  $(MT) -manifest "$(SERVICE_MANIFEST_FILE)" -outputresource:"$(SERVICE_PROGNAME)";#1
$(WINLAUNCHER_PROGNAME) : $(WINLAUNCHER_OBJS)
  $(LINKER) $(WINLAUNCHER_OBJS) /OUT:$(WINLAUNCHER_PROGNAME)
$(LAUNCHER_ADMINISTRATOR_PROGNAME) : $(WINLAUNCHER_OBJS)
  $(LINKER) $(WINLAUNCHER_OBJS) /OUT:$(LAUNCHER_ADMINISTRATOR_PROGNAME)
  $(MT) -manifest "$(LAUNCHER_ADMINISTRATOR_MANIFEST_FILE)" -outputresource:"$(LAUNCHER_ADMINISTRATOR_PROGNAME)";#1
clean:
  del $(SERVICE_OBJS) $(EVENTLOG_H) $(WINLAUNCHER_OBJS) $(RC_FILE) $(RES_FILE) $(SERVICE_PROGNAME) $(WINLAUNCHER_PROGNAME) core
  del $(SERVICE_OBJS) $(EVENTLOG_H) $(WINLAUNCHER_OBJS) $(RC_FILE) $(RES_FILE) $(SERVICE_PROGNAME) $(WINLAUNCHER_PROGNAME) $(LAUNCHER_ADMINISTRATOR_PROGNAME) core
opends/src/build-tools/windows/README
@@ -44,6 +44,16 @@
See the comments in service.c file and common.c for more information.
 WHAT is launcher_administrator.exe
 ========================
launcher_administrator.exe is a small windows executable that is intended to
be used by the command line files to launch operations that require
administrator privileges on Vista.  Basically is a wrapper containing a
manifest that specifies to require administrator privileges to be run.  This
is required if UAC is enabled on Vista so that we have a prompt for the user
asking for confirmation.
See the comments in winlauncher.c file and common.c for more information.
 INSTRUCTIONS TO COMPILE winlauncher.exe
 ========================
@@ -90,7 +100,7 @@
This will generate the binary winlauncher.exe.
 INSTRUCTIONS TO COMPILE opends_service.exe
 INSTRUCTIONS TO COMPILE opends_service.exe and administrator_launcher.exe
 ========================
service.c (the main code file for opends_service.exe) uses windows resources and
so 
opends/src/build-tools/windows/common.c
@@ -53,7 +53,8 @@
  STARTUPINFO startInfo; // info to pass to the new process
  DWORD processFlag; // background process flag
  debug("Attempting to create child process '%s' background=%d.", command, background);
  debug("Attempting to create child process '%s' background=%d.", command,
      background);
  // reset process info first
  ZeroMemory(procInfo, sizeof(PROCESS_INFORMATION));
@@ -84,7 +85,8 @@
  }
  else
  {
    debugError("Failed to create child process '%s'.  Last error = %d.", command, GetLastError());
    debugError("Failed to create child process '%s'.  Last error = %d.",
        command, GetLastError());
  }
  
  return createOk;
@@ -156,7 +158,8 @@
  {
    currentProcessPid = GetCurrentProcessId();
    noMessageLogged = FALSE;
    debug("--------------- FIRST LOG MESSAGE FROM '%s' ---------------", _pgmptr);
    debug("--------------- FIRST LOG MESSAGE FROM '%s' ---------------",
        _pgmptr);
  }
  // Time-stamp
@@ -211,7 +214,8 @@
    MAX_PATH
    ); 
  // Cut everything after the last slash, twice.  This will take us back to the instance root.
  // Cut everything after the last slash, twice.  This will take us back to the
  // instance root.
  // This logic assumes that we are in a directory above the instance root.
  lastSlash = strrchr(execName, '\\');
  lastSlash[0] = '\0';
opends/src/build-tools/windows/launcher_administrator.exe.manifest
New file
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="1.0.0.0"
     processorArchitecture="X86" name="launcher_administrator" type="win32"/>
  <description>Executable used to run code that requires administrator privileges</description>
  <!-- Identify the application security requirements. -->
  <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
    <ms_asmv2:security>
      <ms_asmv2:requestedPrivileges>
        <ms_asmv2:requestedExecutionLevel
          level="requireAdministrator"
          uiAccess="false"/>
        </ms_asmv2:requestedPrivileges>
       </ms_asmv2:security>
  </ms_asmv2:trustInfo>
</assembly>
opends/src/build-tools/windows/opends_service.exe.manifest
New file
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="1.0.0.0"
     processorArchitecture="X86" name="opends_service" type="win32"/>
  <description>Executable used to run OpenDS as a Windows Service</description>
  <!-- Identify the application security requirements. -->
  <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
    <ms_asmv2:security>
      <ms_asmv2:requestedPrivileges>
        <ms_asmv2:requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
        </ms_asmv2:requestedPrivileges>
       </ms_asmv2:security>
  </ms_asmv2:trustInfo>
</assembly>
opends/src/build-tools/windows/service.c
@@ -72,7 +72,7 @@
  }
  debug("registerServiceHandler returning '%d'", returnValue);
  return returnValue;
}  // registerServiceHandler
@@ -147,7 +147,8 @@
  );
  if (scm == NULL)
  {
    debugError("Failed to open the Service Control Manager.  Last error = %d", GetLastError());
    debugError("Failed to open the Service Control Manager.  Last error = %d",
        GetLastError());
    returnValue = SERVICE_RETURN_ERROR;
  }
  else
@@ -247,7 +248,8 @@
    );
    if (result != ERROR_SUCCESS)
    {
      debugError("RegSetValueEx('EventMessageFile') failed, result=%d.", result);
      debugError("RegSetValueEx('EventMessageFile') failed, result=%d.",
          result);
      success = FALSE;
    }
  }
@@ -290,7 +292,8 @@
    );
    if (result != ERROR_SUCCESS)
    {
      debugError("RegSetValueEx('CategoryMessageFile') failed, result=%d.", result);
      debugError("RegSetValueEx('CategoryMessageFile') failed, result=%d.",
          result);
      success = FALSE;
    }
  }
@@ -362,7 +365,8 @@
  );
  if (result != ERROR_SUCCESS)
  {
    debug("The registry key for service '%s' does not exist, so we do not need to remove it.", serviceName);
    debug("The registry key for service '%s' does not exist, so we do not need to remove it.",
        serviceName);
    // Assume that the registry key does not exist.
    returnValue = TRUE;
  }
@@ -429,14 +433,15 @@
  char* relativePath = "\\locks\\server.lock";
  char lockFile[MAX_PATH];
  debug("Determining if the server is running.");
  if (strlen(relativePath)+strlen(_instanceDir)+1 < MAX_PATH)
  {
    int fd;
    sprintf(lockFile, "%s%s", _instanceDir, relativePath);
    debug("When determining whether the server is running, the lock file name is '%s'.", lockFile);
    debug("When determining whether the server is running, the lock file name is '%s'.",
        lockFile);
    fd = _open(lockFile, _O_RDWR);
    if (fd != -1)
@@ -469,7 +474,8 @@
    }
    else
    {
      debug("Could not open lock file '%s', which means the server is not running.", lockFile);
      debug("Could not open lock file '%s', which means the server is not running.",
          lockFile);
      *running = FALSE;
      returnValue = SERVICE_RETURN_ERROR;
    }
@@ -499,7 +505,7 @@
  debug("doStartApplication called.");
  if (strlen(relativePath)+strlen(_instanceDir)+1 < COMMAND_SIZE)
  {
    sprintf(command, "\"%s%s\" --windowsNetStart", _instanceDir, relativePath);
@@ -511,8 +517,10 @@
      // Try to see if server is really running
      int nTries = 10;
      BOOL running = FALSE;
      debug("doStartApplication: the spawn of the process worked.  Command: '%s'", command);
      debug(
          "doStartApplication: the spawn of the process worked.  Command: '%s'",
          command);
      // Wait to be able to launch the java process in order it to free the lock
      // on the file.
      debug("Sleeping for 3 seconds to allow the process to free the lock.");
@@ -526,7 +534,8 @@
        }
        if (!running)
        {
          debug("Sleeping for 2 seconds to allow the process to free the lock.  %d tries remaining.", nTries);
          debug("Sleeping for 2 seconds to allow the process to free the lock.  %d tries remaining.",
              nTries);
          Sleep(2000);
        }
      }
@@ -543,7 +552,7 @@
    }
    else
    {
      returnValue = SERVICE_RETURN_ERROR;
      debug("doStartApplication: spawn failed.  Sent command: '%s'", command);
    }
@@ -577,9 +586,9 @@
      // Try to see if server is really stopped
      int nTries = 10;
      BOOL running = TRUE;
      debug("doStopApplication: the spawn of the process worked.");
      // Wait to be able to launch the java process in order it to free the lock
      // on the file.
      Sleep(3000);
@@ -625,7 +634,7 @@
// serviceBinPath  the path to the service binary.
// instanceDir the instanceDirectory.
// The string stored in serviceBinPath looks like
// <SERVER_ROOT>/lib/service.exe start <_instanceDir>
// <SERVER_ROOT>/lib/opends_service.exe start <_instanceDir>
// It is up to the caller of the function to allocate
// at least COMMAND_SIZE bytes in serviceBinPath.
// The function returns SERVICE_RETURN_OK if we could create the binary
@@ -652,7 +661,9 @@
  }
  else
  {
    debug("When determining the service bin path, the module file name is '%s'.", fileName);
    debug(
        "When determining the service bin path, the module file name is '%s'.",
        fileName);
    if (result == MAX_PATH)
    {
@@ -662,15 +673,16 @@
    }
    else
    {
      if ((strlen(fileName) + strlen(" start ") + strlen(_instanceDir) + 2 * strlen("\"\""))
        < COMMAND_SIZE)
      if ((strlen(fileName) + strlen(" start ") + strlen(_instanceDir) +
          2 * strlen("\"\"")) < COMMAND_SIZE)
      {
        sprintf(serviceBinPath, "\"%s\" start \"%s\"", fileName,
        _instanceDir);
      }
      else
      {
        char * msg = "The name of the resulting windows service command is too long.\n";
        char * msg =
          "The name of the resulting windows service command is too long.\n";
        debug(msg);
        // buffer was too small, executable name is probably not valid
        returnValue = SERVICE_RETURN_ERROR;
@@ -704,7 +716,8 @@
  strcpy(serviceName, "");
  debug("Attempting to get the service name assuming command to run is '%s'.", cmdToRun);
  debug("Attempting to get the service name assuming command to run is '%s'.",
      cmdToRun);
  returnValue = getServiceList(&serviceList, &nbServices);
@@ -733,7 +746,8 @@
            }
            else
            {
              debug("The service name found is too long: '%s'", curService.serviceName);
              debug("The service name found is too long: '%s'",
                  curService.serviceName);
            }
            break;
          }
@@ -748,7 +762,7 @@
  }
  debug("The service name was found to be '%s'.", serviceName);
  return returnValue;
}  // getServiceName
@@ -801,7 +815,7 @@
  debug("Updating the service status.  statusToSet=%d win32ExitCode=%d serviceExitCode=%d checkPoint=%d waitHint=%d",
        statusToSet, win32ExitCode, serviceExitCode,
        checkPoint, waitHint);
  if (statusToSet == SERVICE_START_PENDING)
  {
    debug("Service start pending.");
@@ -835,7 +849,8 @@
  if (!success)
  {
    debugError("Failed to set the service status.  Last error = %d.", GetLastError());
    debugError("Failed to set the service status.  Last error = %d.",
        GetLastError());
    returnValue = SERVICE_RETURN_ERROR;
  }
  else
@@ -872,7 +887,7 @@
  // __debugbreak();
  debug("serviceMain called.");
  code = createServiceBinPath(cmdToRun);
  if (code == SERVICE_RETURN_OK)
@@ -1170,8 +1185,8 @@
//
// scm is the SCM handler (must not be NULL)
// serviceName  the name of the service.
// It is up to the caller of the function to allocate at least COMMAND_SIZE bytes
// in binPathName.
// It is up to the caller of the function to allocate at least COMMAND_SIZE
// bytes in binPathName.
// The function returns SERVICE_RETURN_OK if we could create the binary
// path name and SERVICE_RETURN_ERROR otherwise.
// ---------------------------------------------------------------
@@ -1232,7 +1247,8 @@
        }
        else
        {
          debug("getBinaryPath: error calling QueryServiceConfig. Code [%d]", errCode);
          debug("getBinaryPath: error calling QueryServiceConfig. Code [%d]",
              errCode);
          break;
        }
      }
@@ -1245,7 +1261,8 @@
        }
        else
        {
          debug("getBinaryPath: the length of the binary path name is too big. serviceName='%s', binaryPath='%s'", serviceName, serviceConfig->lpBinaryPathName);
          debug("getBinaryPath: the length of the binary path name is too big. serviceName='%s', binaryPath='%s'",
              serviceName, serviceConfig->lpBinaryPathName);
        }
      }
    }
@@ -1330,7 +1347,8 @@
          if (lastError != ERROR_MORE_DATA)
          {
            returnValue = SERVICE_RETURN_ERROR;
            debug("getServiceList: second try generic error. Code [%d]", lastError);
            debug("getServiceList: second try generic error. Code [%d]",
                lastError);
          }
          else
          {
@@ -1384,7 +1402,8 @@
        }
        else
        {
          debug("Error getting binary path name of service: %s", l[i].serviceName);
          debug("Error getting binary path name of service: %s",
              l[i].serviceName);
        }
        curService++;
      }
@@ -1425,7 +1444,7 @@
  int i;
  debug("Determining if service name '%s' is in use.", serviceName);
  // go through the list of services and search for the service name
  if (getServiceList(&serviceList, &nbServices) == SERVICE_RETURN_OK)
  {
@@ -1456,7 +1475,8 @@
  }
  else
  {
    debugError("Could not determine if the service name '%s' is in use because listing the services failed.", serviceName);
    debugError("Could not determine if the service name '%s' is in use because listing the services failed.",
        serviceName);
    returnValue = SERVICE_RETURN_ERROR;
  }
  return returnValue;
@@ -1513,7 +1533,7 @@
  }
  debug("createServiceName returning serviceName='%s' and returnValue=%d",
        serviceName, returnValue);
        serviceName, returnValue);
  return returnValue;
} // createServiceName
@@ -1547,7 +1567,7 @@
  // create the service
  if (returnValue == SERVICE_RETURN_OK)
  {
    if (openScm(GENERIC_WRITE, &scm) != SERVICE_RETURN_OK)
    if (openScm(SC_MANAGER_ALL_ACCESS, &scm) != SERVICE_RETURN_OK)
    {
      returnValue = SERVICE_RETURN_ERROR;
      debug("createServiceInScm: openScm did not work.");
@@ -1583,7 +1603,8 @@
  if ((returnValue == SERVICE_RETURN_OK) && (myService == NULL))
  {
    DWORD errCode = GetLastError();
    debugError("Failed to create the service '%s'.  Last error = %d.", serviceName, errCode);
    debugError("Failed to create the service '%s'.  Last error = %d.",
        serviceName, errCode);
    if (errCode == ERROR_DUPLICATE_SERVICE_NAME)
    {
      returnValue = DUPLICATED_SERVICE_NAME;
@@ -1594,6 +1615,10 @@
    }
    else
    {
      if (errCode == ERROR_INVALID_HANDLE)
      {
        debugError("The handle seems to be invalid.");
      }
      returnValue = SERVICE_RETURN_ERROR;
    }
  }
@@ -1612,7 +1637,9 @@
    if (!success)
    {
      debugError("Failed to add a description to the service '%s'.  Last error = %d.", serviceName, GetLastError());
      debugError(
          "Failed to add a description to the service '%s'.  Last error = %d.",
          serviceName, GetLastError());
      returnValue = SERVICE_RETURN_ERROR;
    }
  }
@@ -1635,7 +1662,7 @@
  }
  debug("createServiceInScm returning %d.", returnValue);
  return returnValue;
} // createServiceInScm
@@ -1656,7 +1683,7 @@
  SERVICE_STATUS serviceStatus;
  debug("Removing service '%s' from the Service Control Manager.", serviceName);
  returnValue = openScm(GENERIC_WRITE, &scm);
  // open the service
@@ -1671,7 +1698,8 @@
    debug("After opening service myService=%d.", myService);
    if (myService == NULL)
    {
      debugError("Failed to open the service '%s'. Last error = %d", serviceName, GetLastError());
      debugError("Failed to open the service '%s'. Last error = %d",
          serviceName, GetLastError());
      returnValue = SERVICE_RETURN_ERROR;
    }
  }
@@ -1686,7 +1714,8 @@
    );
    if (!success)
    {
      debugError("Failed to query the status for service '%s'. Last error = %d", serviceName, GetLastError());
      debugError("Failed to query the status for service '%s'. Last error = %d",
          serviceName, GetLastError());
      returnValue = SERVICE_RETURN_ERROR;
    }
  }
@@ -1707,7 +1736,8 @@
      if (!success)
      {
        DWORD errCode = GetLastError();
        debugError("Failed to stop the service '%s'.  Last error = %d.", serviceName, errCode);
        debugError("Failed to stop the service '%s'.  Last error = %d.",
            serviceName, errCode);
        if (errCode == ERROR_SERVICE_MARKED_FOR_DELETE)
        {
          returnValue = SERVICE_MARKED_FOR_DELETION;
@@ -1733,7 +1763,8 @@
    if (!success)
    {
      DWORD errCode = GetLastError();
      debugError("Failed to delete the service '%s'.  Last error = %d.", serviceName, errCode);
      debugError("Failed to delete the service '%s'.  Last error = %d.",
          serviceName, errCode);
      if (errCode == ERROR_SERVICE_MARKED_FOR_DELETE)
      {
        returnValue = SERVICE_MARKED_FOR_DELETION;
@@ -1778,7 +1809,8 @@
  char cmdToRun[COMMAND_SIZE];
  ServiceReturnCode code;
  debug("Creating service displayName='%s' description='%s'.", displayName, description);
  debug("Creating service displayName='%s' description='%s'.", displayName,
      description);
  code = createServiceBinPath(cmdToRun);
  if (code == SERVICE_RETURN_OK)
@@ -1858,12 +1890,13 @@
  strcpy(serviceName, "");
  debug("Getting service state.");
  code = createServiceBinPath(cmdToRun);
  debug("Created the service bin path. code=%d.  cmdToRun='%s'.", code, cmdToRun);
  debug("Created the service bin path. code=%d.  cmdToRun='%s'.", code,
      cmdToRun);
  if (code == SERVICE_RETURN_OK)
  {
    code = getServiceName(cmdToRun, serviceName);
    if (code == SERVICE_RETURN_OK)
    {
      // There is a valid serviceName for the command to run, so
@@ -1875,7 +1908,7 @@
    else
    {
      returnCode = 1;
      debug("Service '%s' is disabled enabled.", serviceName);
      debug("Service '%s' is disabled.", serviceName);
    }
  }
  else
@@ -2072,7 +2105,7 @@
  char* subcommand;
  int returnCode = 0;
  int i;
  updateDebugFlag(argv, argc);
  debug("main called.");
@@ -2201,7 +2234,7 @@
  }
  debug("main returning %d.", returnCode);
  return returnCode;
} // main
opends/src/build-tools/windows/winlauncher.c
@@ -63,7 +63,7 @@
{
  struct stat finfo;
  BOOL returnValue = FALSE;
  if(stat(fileName, &finfo) < 0)
  {
    returnValue = FALSE;
@@ -89,7 +89,7 @@
  BOOL returnValue = FALSE;
  char pidFile[PATH_SIZE];
  int nTries = 10;
  debug("Attempting to delete the PID file from instanceDir='%s'.", instanceDir);
  // Sometimes the lock on the system in windows takes time to be released.
  if (getPidFile(instanceDir, pidFile, PATH_SIZE))
@@ -110,7 +110,7 @@
      }
    }
  }
  debug("deletePidFile('%s') returning %d.", instanceDir, returnValue);
  return returnValue;
}  // deletePidFile
@@ -128,7 +128,7 @@
  FILE *f;
  char buf[BUF_SIZE];
  int read;
  debug("Attempting to get the PID for the server rooted at '%s'.", instanceDir);
  if (getPidFile(instanceDir, pidFile, PATH_SIZE))
  {
@@ -137,7 +137,7 @@
      read = fread(buf, 1, sizeof(buf),f);
      debug("Read '%s' from the PID file '%s'.", buf, pidFile);
    }
    if (f != NULL)
    {
      fclose(f);
@@ -179,7 +179,7 @@
  FALSE,                          // handle is not inheritable
  pid
  );
  if (procHandle == NULL)
  {
    debug("The process with pid=%d has already terminated.", pid);
@@ -201,7 +201,7 @@
      debug("Successfully began termination process for (pid=%d).", pid);
      // wait for the process to end.
      processDead = FALSE;
      while ((nTries > 0) && !processDead)
      {
@@ -234,11 +234,11 @@
// otherwise.
// ----------------------------------------------------
BOOL createPidFile(const char* instanceDir, int pid)
{
{
  BOOL returnValue = FALSE;
  char pidFile[PATH_SIZE];
  FILE *f;
  debug("createPidFile(instanceDir='%s',pid=%d)", instanceDir, pid);
  if (getPidFile(instanceDir, pidFile, PATH_SIZE))
@@ -261,7 +261,7 @@
    debugError("Couldn't create the pid file because the pid file name could not be constructed.");
    returnValue = FALSE;
  }
  return returnValue;
}  // createPidFile
@@ -281,11 +281,11 @@
  BOOL overflow = FALSE;
  debug("Constructing full command line from arguments:");
  for (i = 0; (argv[i] != NULL); i++)
  for (i = 0; (argv[i] != NULL); i++)
  {
    debug(" argv[%d]: %s", i, argv[i]);
  }
  i = 0;
  while ((argv[i] != NULL) && !overflow)
  {
@@ -302,11 +302,11 @@
        overflow = TRUE;
      }
    }
    if (curarg[0] != '\0')
    {
      int argInd = 0;
      if (curarg[0] == '"')
      {
        // there is a quote: no need to add extra quotes
@@ -346,7 +346,7 @@
          overflow = TRUE;
        }
      }
    } else {
      if (curCmdInd + strlen("\"\"") < maxSize)
      {
@@ -360,15 +360,15 @@
    }
  }
  if (overflow)
  if (overflow)
  {
    debugError("Failed to construct the full commandline because the buffer wasn't big enough.");
  }
  else
  }
  else
  {
    debug("The full commandline is '%s'.", command);
  }
  return !overflow;
} // getCommandLine
@@ -397,13 +397,13 @@
{
  int returnValue;
  int childPid;
  char command[COMMAND_SIZE];
  if (getCommandLine(argv, command, COMMAND_SIZE))
  {
    childPid = spawn(command, TRUE);
    if (childPid > 0)
    {
      createPidFile(instanceDir, childPid);
@@ -420,7 +420,7 @@
    debugError("Couldn't start the child process because the full command line could not be constructed.");
    returnValue = -1;
  }
  return returnValue;
} // start
@@ -449,13 +449,13 @@
int stop(const char* instanceDir)
{
  int returnCode = -1;
  int childPid;
  debug("Attempting to stop the server running at root '%s'.", instanceDir);
  childPid = getPid(instanceDir);
  if (childPid != 0)
  {
    if (killProcess(childPid))
@@ -464,7 +464,7 @@
      deletePidFile(instanceDir);
    }
  }
  else
  else
  {
    debug("Could not stop the server running at root '%s' because the pid could not be located.", instanceDir);
  }
@@ -485,7 +485,7 @@
// prompt-window associated with it.
// Launch batch files from the prompt that generate a java process that does not
// block the prompt and that keeps running even if the prompt window is closed.
//
//
// This function expects the following parameter to be passed:
// the directory of the server we want to start and the
// command line that we want to execute (basically the java
@@ -495,19 +495,19 @@
// 2. Allow the administrator some flexibility in the way the
// server is started by leaving most of the logic in the command-line.
//
// Returns the pid of the process associated with the command if it could be
// Returns the pid of the process associated with the command if it could be
// launched and -1 otherwise.
// ----------------------------------------------------
int launch(char* argv[])
{
  int returnValue;
  char command[COMMAND_SIZE];
  if (getCommandLine(argv, command, COMMAND_SIZE))
  {
    returnValue = spawn(command, TRUE);
    if (returnValue <= 0)
    if (returnValue <= 0)
    {
      debugError("Failed to launch the child process '%s'.", command);
    }
@@ -521,18 +521,60 @@
    debugError("Couldn't launch the child process because the full command line could not be constructed.");
    returnValue = -1;
  }
  return returnValue;
} // launch
//----------------------------------------------------
// Function called when we want to launch a process and it to be run as
// administrator on Vista (the binary containing this function must have
// a manifest specifying that).
// Returns the exit code of the process associated with the command if it
// could be launched and -1 otherwise.
//----------------------------------------------------
int run(char* argv[])
{
  PROCESS_INFORMATION procInfo; // info on the new process
  BOOL createOk;
  DWORD exitCode;
  int returnValue = -1;
  int millisToWait = 30000;
  int waitedMillis = 0;
  char command[COMMAND_SIZE];
  if (getCommandLine(argv, command, COMMAND_SIZE))
  {
    createOk = createChildProcess((char*)command, TRUE, &procInfo);
    if(createOk)
    {
      GetExitCodeProcess(procInfo.hProcess, &exitCode);
      while (exitCode == STILL_ACTIVE)
      {
        GetExitCodeProcess(procInfo.hProcess, &exitCode);
        Sleep(500);
        waitedMillis += 500;
        if (waitedMillis > millisToWait)
        {
          break;
        }
      }
      returnValue = exitCode;
    }
  }
  return returnValue;
} // run
// ----------------------------------------------------
// main function called by the executable.  This code is
// called by the start-ds.bat, stop-ds.bat and statuspanel.bat batch files.
//
// The code assumes that the first passed argument is the subcommand to be
// executed and the second argument the directory of the server.  The rest
// of the arguments are the arguments specific to each subcommand (see the
// comments for the functions start, stop and launch).
// executed and for start and stop the second argument the directory of the
// server.
// The rest of the arguments are the arguments specific to each subcommand (see
// the comments for the functions start, stop and launch).
// ----------------------------------------------------
int main(int argc, char* argv[])
{
@@ -540,36 +582,44 @@
  char* subcommand = NULL;
  char* instanceDir = NULL;
  int i;
  debug("main called.");
  for (i = 0; i < argc; i++) {
    debug("  argv[%d] = '%s'", i, argv[i]);
  }
  if (argc < 3) {
    char * msg = "Expected command line args of [subcommand] [server directory], but got %d arguments.\n";
    char * msg =
      "Expected command line args of [subcommand], but got %d arguments.\n";
    debugError(msg, argc - 1);
    fprintf(stderr, msg, argc - 1);
      return -1;
  }
  subcommand = argv[1];
  instanceDir = argv[2];
  argv += 3;
  if (strcmp(subcommand, "start") == 0)
  {
    instanceDir = argv[2];
    argv += 3;
    returnCode = start(instanceDir, argv);
  }
  else if (strcmp(subcommand, "stop") == 0)
  {
    instanceDir = argv[2];
    argv += 3;
    returnCode = stop(instanceDir);
  }
  else if (strcmp(subcommand, "launch") == 0)
  {
    argv += 2;
    returnCode = launch(argv);
  }
  else if (strcmp(subcommand, "run") == 0)
  {
    argv += 2;
    returnCode = run(argv);
  }
  else
  {
    char * msg = "Unknown subcommand: [%s]\n";
opends/src/server/org/opends/server/tools/ConfigureWindowsService.java
@@ -36,6 +36,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.NullOutputStream;
import org.opends.server.util.SetupUtils;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.ArgumentParser;
import org.opends.server.util.args.BooleanArgument;
@@ -52,6 +53,22 @@
  * this machine.
  * This tool allows to enable and disable OpenDS to run as a Windows service
  * and allows to know if OpenDS is running as a Windows service or not.
  *
  * Some comments about Vista:
  * In Vista, when we launch the subcommands that require administrator
  * privileges (enable, disable and cleanup) we cannot use the administrator
  * launcher binary directly from Java (see
  * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6410605) so we use
  * winlauncher.exe.
  * When we launch subcommands that required administrator privileges
  * we must launch a binary containing the manifest that specifies that we
  * require administrator privileges (requireAdministrator value): if UAC is
  * enabled, the user will be asked for confirmation.
  * To minimize the number of confirmation that the user must provide when
  * launching the state subcommand we will use a binary whose manifest does
  * not contain the requireAdministrator value.
  *
  * See the files under src/build-tools/windows for more details.
  */
public class ConfigureWindowsService
{
@@ -62,6 +79,10 @@
    "org.opends.server.tools.ConfigureWindowsService";
  private static final String DEBUG_OPTION = "--debug";
  /**
   * Option to be used when calling the launchers.
   */
  public static final String LAUNCHER_OPTION = "run";
  private static int ERROR = 1;
@@ -333,7 +354,7 @@
        getBinaryFullPath(),
        "state",
        serverRoot
        };
    };
    try
    {
      Process p = Runtime.getRuntime().exec(cmd);
@@ -385,14 +406,35 @@
    String msg;
    String serverRoot = getServerRoot();
    String[] cmd = {
        getBinaryFullPath(),
        "create",
        serverRoot,
        getMessage(MSGID_WINDOWS_SERVICE_NAME, (Object[]) null),
        getMessage(MSGID_WINDOWS_SERVICE_DESCRIPTION, serverRoot),
        DEBUG_OPTION
        };
    String[] cmd;
    if (isVista())
    {
      cmd = new String[] {
          getLauncherBinaryFullPath(),
          LAUNCHER_OPTION,
          getLauncherAdministratorBinaryFullPath(),
          LAUNCHER_OPTION,
          getBinaryFullPath(),
          "create",
          serverRoot,
          getMessage(MSGID_WINDOWS_SERVICE_NAME, (Object[]) null),
          getMessage(MSGID_WINDOWS_SERVICE_DESCRIPTION, serverRoot),
          DEBUG_OPTION
      };
    }
    else
    {
      cmd = new String[] {
          getBinaryFullPath(),
          "create",
          serverRoot,
          getMessage(MSGID_WINDOWS_SERVICE_NAME, (Object[]) null),
          getMessage(MSGID_WINDOWS_SERVICE_DESCRIPTION, serverRoot),
          DEBUG_OPTION
      };
    }
    try
    {
      int resultCode = Runtime.getRuntime().exec(cmd).waitFor();
@@ -456,12 +498,29 @@
    int returnValue;
    String msg;
    String serverRoot = getServerRoot();
    String[] cmd = {
    String[] cmd;
    if (isVista())
    {
      cmd = new String[] {
          getLauncherBinaryFullPath(),
          LAUNCHER_OPTION,
          getLauncherAdministratorBinaryFullPath(),
          LAUNCHER_OPTION,
          getBinaryFullPath(),
          "remove",
          serverRoot,
          DEBUG_OPTION
      };
    }
    else
    {
      cmd = new String[] {
        getBinaryFullPath(),
        "remove",
        serverRoot,
        DEBUG_OPTION
        };
    }
    try
    {
      int resultCode = Runtime.getRuntime().exec(cmd).waitFor();
@@ -525,12 +584,29 @@
  {
    int returnValue;
    String msg;
    String[] cmd = {
        getBinaryFullPath(),
        "cleanup",
        serviceName,
        DEBUG_OPTION
        };
    String[] cmd;
    if (isVista())
    {
      cmd = new String[] {
          getLauncherBinaryFullPath(),
          LAUNCHER_OPTION,
          getLauncherAdministratorBinaryFullPath(),
          LAUNCHER_OPTION,
          getBinaryFullPath(),
          "cleanup",
          serviceName,
          DEBUG_OPTION
      };
    }
    else
    {
      cmd = new String[] {
          getBinaryFullPath(),
          "cleanup",
          serviceName,
          DEBUG_OPTION
      };
    }
    try
    {
      int resultCode = Runtime.getRuntime().exec(cmd).waitFor();
@@ -588,12 +664,13 @@
    String serviceName = null;
    String serverRoot = getServerRoot();
    String[] cmd = {
    String[] cmd = new String[] {
        getBinaryFullPath(),
        "state",
        serverRoot,
        DEBUG_OPTION
        };
    };
    try
    {
      int resultCode = -1;
@@ -711,7 +788,8 @@
  /**
   * Returns the full path of the executable used by this class to perform
   * operations related to the service.
   * operations related to the service.  This binaries file has the asInvoker
   * value in its manifest.
   * @return the full path of the executable used by this class to perform
   * operations related to the service.
   */
@@ -719,4 +797,41 @@
  {
    return getServerRoot()+"\\lib\\opends_service.exe";
  }
  /**
   * Returns the full path of the executable that has a manifest requiring
   * administrator privileges used by this class to perform
   * operations related to the service.
   * @return the full path of the executable that has a manifest requiring
   * administrator privileges used by this class to perform
   * operations related to the service.
   */
  public static String getLauncherAdministratorBinaryFullPath()
  {
    return getServerRoot()+"\\lib\\launcher_administrator.exe";
  }
  /**
   * Returns the full path of the executable that has a manifest requiring
   * administrator privileges used by this class to perform
   * operations related to the service.
   * @return the full path of the executable that has a manifest requiring
   * administrator privileges used by this class to perform
   * operations related to the service.
   */
  public static String getLauncherBinaryFullPath()
  {
    return getServerRoot()+"\\lib\\winlauncher.exe";
  }
  /**
   * Indicates whether the underlying operating system is Windows Vista.
   *
   * @return  {@code true} if the underlying operating system is Windows
   *          Vista, or {@code false} if not.
   */
  private static boolean isVista()
  {
    return SetupUtils.isVista();
  }
}
opends/src/server/org/opends/server/tools/StartWindowsService.java
@@ -31,6 +31,7 @@
import java.io.PrintStream;
import org.opends.server.types.NullOutputStream;
import org.opends.server.util.SetupUtils;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.messages.ToolMessages.*;
@@ -113,11 +114,27 @@
    }
    else
    {
      String[] cmd = {
          "net",
          "start",
          serviceName
          };
      String[] cmd;
      if (SetupUtils.isVista())
      {
        cmd= new String[] {
            ConfigureWindowsService.getLauncherBinaryFullPath(),
            ConfigureWindowsService.LAUNCHER_OPTION,
            ConfigureWindowsService.getLauncherAdministratorBinaryFullPath(),
            ConfigureWindowsService.LAUNCHER_OPTION,
            "net",
            "start",
            serviceName
        };
      }
      else
      {
        cmd= new String[] {
            "net",
            "start",
            serviceName
        };
      }
      /* Check if is a running service */
      try
      {
opends/src/server/org/opends/server/tools/StopWindowsService.java
@@ -31,6 +31,7 @@
import java.io.PrintStream;
import org.opends.server.types.NullOutputStream;
import org.opends.server.util.SetupUtils;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.messages.ToolMessages.*;
@@ -117,11 +118,27 @@
    }
    else
    {
      String[] cmd = {
          "net",
          "stop",
          serviceName
          };
      String[] cmd;
      if (SetupUtils.isVista())
      {
        cmd= new String[] {
            ConfigureWindowsService.getLauncherBinaryFullPath(),
            ConfigureWindowsService.LAUNCHER_OPTION,
            ConfigureWindowsService.getLauncherAdministratorBinaryFullPath(),
            ConfigureWindowsService.LAUNCHER_OPTION,
            "net",
            "stop",
            serviceName
        };
      }
      else
      {
        cmd= new String[] {
            "net",
            "stop",
            serviceName
        };
      }
      /* Check if is a running service */
      try
      {
opends/src/server/org/opends/server/util/SetupUtils.java
@@ -154,6 +154,26 @@
  }
  /**
   * Indicates whether the underlying operating system is Windows Vista.
   *
   * @return  {@code true} if the underlying operating system is Windows
   *          Vista, or {@code false} if not.
   */
  public static boolean isVista()
  {
    boolean isVista;
    String os = System.getProperty("os.name");
    if (os != null)
    {
     isVista = isWindows() && (os.toLowerCase().indexOf("vista") != -1);
    }
    else
    {
      isVista = false;
    }
    return isVista;
  }
  /**
   * Returns a String representation of the OS we are running.
   * @return a String representation of the OS we are running.
   */