summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src')
-rwxr-xr-xcpp/src/iceserviceinstall/Install.cpp781
-rw-r--r--cpp/src/iceserviceinstall/Makefile.mak73
-rwxr-xr-xcpp/src/iceserviceinstall/MsiSupport.cpp274
-rwxr-xr-xcpp/src/iceserviceinstall/ServiceInstaller.cpp775
-rwxr-xr-xcpp/src/iceserviceinstall/ServiceInstaller.h77
5 files changed, 1220 insertions, 760 deletions
diff --git a/cpp/src/iceserviceinstall/Install.cpp b/cpp/src/iceserviceinstall/Install.cpp
index 75bbed7e7f9..6ea57893086 100755
--- a/cpp/src/iceserviceinstall/Install.cpp
+++ b/cpp/src/iceserviceinstall/Install.cpp
@@ -7,27 +7,10 @@
//
// **********************************************************************
-#define _WIN32_WINNT 0x0500
-
-#if defined(_MSC_VER) && _MSC_VER >= 1400
-# define _CRT_SECURE_NO_DEPRECATE 1 // C4996 '<C function>' was declared deprecated
-#endif
-
-#include <Ice/Application.h>
+#include <Ice/Ice.h>
#include <IceUtil/Options.h>
+#include <ServiceInstaller.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <Aclapi.h>
-#include <AccCtrl.h>
-
-#if defined(_MSC_VER) && _MSC_VERSION >= 1300
-//
-// The VC6 headers don't include Sddl.h
-//
-#include <Sddl.h>
-#endif
using namespace std;
using namespace Ice;
@@ -37,7 +20,6 @@ public:
virtual int run(int, char*[]);
Install();
- virtual ~Install();
bool pauseEnabled() const;
bool debug() const;
@@ -46,34 +28,8 @@ private:
void usage() const;
- void initializeSid(const string&);
-
- bool fileExists(const string&) const;
- void checkService(const string&, string&, string&) const;
- void grantPermissions(const string& path, SE_OBJECT_TYPE type = SE_FILE_OBJECT,
- bool inherit = false, bool fullControl = false) const;
- bool mkdir(const string&) const;
- string formatMessage(DWORD) const;
-
- void uninstallService(const string&) const;
- void installService(const string&, const string&, const string&, const string&,
- const string&, const string&, const string&) const;
-
- void addEventLogKey(const string&, const string&) const;
- void removeEventLogKey(const string&) const;
- string mangleKey(const string&) const;
- string createEventLogKey(const string&) const;
- string getIceDLLPath(const string&) const;
-
- string _icegridInstanceName;
- string _nodeName;
- string _glacier2InstanceName;
-
- SID* _sid;
- string _sidName;
-
- bool _pauseEnabled;
bool _debug;
+ bool _pauseEnabled;
};
int
@@ -98,13 +54,10 @@ Install::run(int argc, char* argv[])
opts.addOpt("v", "version");
opts.addOpt("u", "uninstall");
opts.addOpt("n", "nopause");
- opts.addOpt("", "debug");
- const string propNames[] = { "ImagePath", "DisplayName", "ObjectName", "Password",
- "Description", "DependOnRegistry" };
- const int propCount = 6;
+ vector<string> propNames = IceServiceInstaller::getPropertyNames();
- for(int i = 0; i < propCount; ++i)
+ for(size_t i = 0; i < propNames.size(); ++i)
{
opts.addOpt("", propNames[i], IceUtil::Options::NeedArg);
}
@@ -132,164 +85,56 @@ Install::run(int argc, char* argv[])
return EXIT_SUCCESS;
}
- _debug = opts.isSet("debug");
-
_pauseEnabled = !opts.isSet("nopause");
- PropertiesPtr properties = communicator()->getProperties();
+ if(commands.size() != 2)
+ {
+ usage();
+ return EXIT_FAILURE;
+ }
- for(int j = 0; j < propCount; ++j)
+ int serviceType = -1;
+ for(int i = 0; i < IceServiceInstaller::serviceCount; ++i)
{
- if(opts.isSet(propNames[j]))
+ if(commands[0] == IceServiceInstaller::serviceTypeToLowerString(i))
{
- properties->setProperty(propNames[j], opts.optArg(propNames[j]));
+ serviceType = i;
+ break; // for
}
}
- if(commands.size() != 2)
+ if(serviceType == -1)
{
- usage();
+ cerr << "Invalid service " << commands[0] << endl;
return EXIT_FAILURE;
}
- initializeSid(properties->getPropertyWithDefault("ObjectName",
- "NT Authority\\LocalService"));
-
- string service = commands[0];
string configFile = commands[1];
try
{
- PropertiesPtr serviceProperties = createProperties();
- serviceProperties->load(configFile);
+ IceServiceInstaller installer(serviceType, configFile, communicator());
- string serviceName;
- LocatorPrx defaultLocator = LocatorPrx::uncheckedCast(
- communicator()->stringToProxy(
- serviceProperties->getProperty("Ice.Default.Locator")));
-
- if(service == "icegridregistry")
+ if(opts.isSet("uninstall"))
{
- _icegridInstanceName =
- serviceProperties->getPropertyWithDefault("IceGrid.InstanceName", "IceGrid");
- serviceName = service + "." + _icegridInstanceName;
+ installer.uninstall();
}
else
{
- if(defaultLocator != 0)
- {
- _icegridInstanceName = defaultLocator->ice_getIdentity().category;
- }
+ PropertiesPtr properties = communicator()->getProperties();
- if(service == "icegridnode")
+ for(size_t j = 0; j < propNames.size(); ++j)
{
- if(_icegridInstanceName == "")
+ if(opts.isSet(propNames[j]))
{
- throw string("Ice.Default.Locator must be set in " + configFile);
+ properties->setProperty(propNames[j], opts.optArg(propNames[j]));
}
- _nodeName = serviceProperties->getProperty("IceGrid.Node.Name");
- if(_nodeName == "")
- {
- throw string("IceGrid.Node.Name must be set in " + configFile);
- }
- serviceName = service + "." + _icegridInstanceName + "." + _nodeName;
}
- else if(service == "glacier2router")
- {
- _glacier2InstanceName =
- serviceProperties->getPropertyWithDefault("Glacier2.InstanceName",
- "Glacier2");
- serviceName = service + "." + _glacier2InstanceName;
- }
- }
- string displayName;
- string description;
- checkService(service, displayName, description);
- displayName = properties->getPropertyWithDefault("DisplayName", displayName);
- description = properties->getPropertyWithDefault("Description", description);
+ _debug = properties->getPropertyAsInt("Debug") != 0;
- if(opts.isSet("uninstall"))
- {
- uninstallService(serviceName);
- return EXIT_SUCCESS;
- }
-
- string imagePath = properties->getProperty("ImagePath");
- if(imagePath == "")
- {
- char buffer[MAX_PATH];
- DWORD size = GetModuleFileName(0, buffer, MAX_PATH);
- if(size == 0)
- {
- throw "Can't get full path to self: " + formatMessage(GetLastError());
- }
- imagePath = string(buffer, size);
- imagePath.replace(imagePath.rfind('\\'), string::npos, string("\\")
- + service + ".exe");
+ installer.install(properties);
}
- if(!fileExists(imagePath))
- {
- throw imagePath + ": not found";
- }
-
- string dependency;
-
- if(service == "icegridregistry")
- {
- if(properties->getPropertyAsInt("DependOnRegistry") != 0)
- {
- throw string("The IceGrid registry service can't depend on itself");
- }
-
- string registryDataDir = serviceProperties->getProperty("IceGrid.Registry.Data");
- if(registryDataDir == "")
- {
- throw string("IceGrid.Registry.Data must be set in " + configFile);
- }
- if(!mkdir(registryDataDir))
- {
- grantPermissions(registryDataDir, SE_FILE_OBJECT, true, true);
- }
- }
- else if(service == "icegridnode")
- {
- string nodeDataDir = serviceProperties->getProperty("IceGrid.Node.Data");
- if(nodeDataDir == "")
- {
- throw string("IceGrid.Node.Data must be set in " + configFile);
- }
- if(!mkdir(nodeDataDir))
- {
- grantPermissions(nodeDataDir, SE_FILE_OBJECT, true, true);
- }
-
- grantPermissions(
- "MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
- SE_REGISTRY_KEY, true);
-
- if(properties->getPropertyAsInt("DependOnRegistry") != 0)
- {
- dependency = "icegridregistry." + _icegridInstanceName;
- }
- }
- else if(service == "glacier2router")
- {
- if(properties->getPropertyAsInt("DependOnRegistry") != 0)
- {
- if(_icegridInstanceName == "")
- {
- throw string("Ice.Default.Locator must be set in " + configFile
- + " when DependOnRegistry is not zero");
- }
- dependency = "icegridregistry." + _icegridInstanceName;
- }
- }
-
- grantPermissions(configFile);
-
- installService(serviceName, imagePath, configFile, displayName, description,
- dependency, properties->getProperty("Password"));
}
catch(const string& msg)
{
@@ -305,13 +150,9 @@ Install::run(int argc, char* argv[])
}
Install::Install() :
- _sid(0)
-{
-}
-
-Install::~Install()
+ _pauseEnabled(true),
+ _debug(false)
{
- free(_sid);
}
bool
@@ -356,569 +197,3 @@ Install::usage() const
;
}
-void
-Install::initializeSid(const string& name)
-{
- {
- DWORD sidSize = 32;
- _sid = static_cast<SID*>(malloc(sidSize));
- memset(_sid, 0, sidSize);
-
- DWORD domainNameSize = 32;
- char* domainName = static_cast<char*>(malloc(domainNameSize));
- memset(domainName, 0, domainNameSize);
-
- SID_NAME_USE nameUse;
- while(LookupAccountName(0, name.c_str(), _sid, &sidSize, domainName, &domainNameSize, &nameUse) == false)
- {
- DWORD res = GetLastError();
-
- if(res == ERROR_INSUFFICIENT_BUFFER)
- {
- _sid = static_cast<SID*>(realloc(_sid, sidSize));
- memset(_sid, 0, sidSize);
- domainName = static_cast<char*>(realloc(domainName, domainNameSize));
- memset(domainName, 0, domainNameSize);
- }
- else
- {
- free(_sid);
- _sid = 0;
- free(domainName);
-
- throw string("Could not retrieve Security ID for ") + name + ": "
- + formatMessage(res);
- }
- }
- free(domainName);
- }
-
- //
- // Now store in _sidName a 'normalized' name (for the CreateService call)
- //
-
- if(name.find('\\') != string::npos)
- {
- //
- // Keep this name; otherwise on XP, the localized name
- // ("NT AUTHORITY\LOCAL SERVICE" in English) shows up in the Services
- // snap-in instead of 'Local Service' (which is also a localized name,
- // but looks nicer).
- //
- _sidName = name;
- }
- else
- {
- char accountName[1024];
- DWORD accountNameLen = 1024;
-
- char domainName[1024];
- DWORD domainLen = 1024;
-
- SID_NAME_USE nameUse;
- if(LookupAccountSid(0, _sid, accountName, &accountNameLen, domainName,
- &domainLen, &nameUse) == false)
- {
- DWORD res = GetLastError();
- throw string("Could not retrieve full account name for ") + name + ": "
- + formatMessage(res);
- }
-
- _sidName = string(domainName) + "\\" + accountName;
- }
-
- if(_debug)
- {
- Trace trace(communicator()->getLogger(), appName());
-
-#if defined(_MSC_VER) && _MSC_VERSION >= 1300
- char* sidString = 0;
- ConvertSidToStringSid(_sid, &sidString);
- trace << "SID: " << sidString << "; ";
- LocalFree(sidString);
-#endif
- trace << "Full name: " << _sidName;
- }
-}
-
-bool
-Install::fileExists(const string& path) const
-{
- struct _stat buffer = { 0 };
- int err = _stat(path.c_str(), &buffer);
-
- if(err == 0)
- {
- if((buffer.st_mode & _S_IFREG) == 0)
- {
- throw path + " is not a regular file";
- }
- return true;
- }
- else
- {
- if(errno == ENOENT)
- {
- return false;
- }
- else
- {
- const char* msg = strerror(errno);
- throw string("Problem with ") + path + ": " + msg;
- }
- }
-}
-
-void
-Install::checkService(const string& service, string& displayName, string& description) const
-{
- if(service == "icegridregistry")
- {
- displayName = string("IceGrid registry (") + _icegridInstanceName + ")";
- description = "Location and deployment service for Ice applications";
- }
- else if(service == "icegridnode")
- {
- displayName = string("IceGrid node (") + _nodeName + " within "
- + _icegridInstanceName + ")";
- description = "Starts and monitors Ice servers";
- }
- else if(service == "glacier2router")
- {
- displayName = string("Glacier2 router (") + _glacier2InstanceName + ")";
- description = "Ice Firewall traversal service";
- }
- else
- {
- throw string("Invalid service");
- }
-}
-
-void
-Install::grantPermissions(const string& path, SE_OBJECT_TYPE type, bool inherit, bool fullControl) const
-{
- //
- // First retrieve the ACL for our file/directory/key
- //
- PACL acl = 0;
- PACL newAcl = 0;
- PSECURITY_DESCRIPTOR sd = 0;
- DWORD res = GetNamedSecurityInfo(const_cast<char*>(path.c_str()), type,
- DACL_SECURITY_INFORMATION,
- 0, 0, &acl, 0, &sd);
- if(res != ERROR_SUCCESS)
- {
- throw string("Could not retrieve securify info for ") + path + ": "
- + formatMessage(res);
- }
-
- try
- {
- //
- // Now check if _sid can read this file/dir/key
- //
- TRUSTEE trustee;
- BuildTrusteeWithSid(&trustee, _sid);
-
- ACCESS_MASK accessMask = 0;
- res = GetEffectiveRightsFromAcl(acl, &trustee, &accessMask);
-
- if(res != ERROR_SUCCESS)
- {
- throw string("Could not retrieve effective rights for ") + _sidName
- + " on " + path + ": " + formatMessage(res);
- }
-
- bool done = false;
-
- if(type == SE_FILE_OBJECT)
- {
- if(fullControl)
- {
- done = (accessMask & READ_CONTROL) && (accessMask & SYNCHRONIZE)
- && (accessMask & 0x1F) == 0x1F;
- }
- else
- {
- done = (accessMask & READ_CONTROL) && (accessMask & SYNCHRONIZE);
- }
- }
- else
- {
- done = (accessMask & READ_CONTROL);
- }
-
- if(done)
- {
- if(_debug)
- {
- Trace trace(communicator()->getLogger(), appName());
- trace << _sidName << " had already the desired permissions on " << path;
- }
- }
- else
- {
- EXPLICIT_ACCESS ea = { 0 };
-
- if(type == SE_FILE_OBJECT && fullControl)
- {
- ea.grfAccessPermissions = (accessMask | FILE_ALL_ACCESS);
- }
- else
- {
- ea.grfAccessPermissions = (accessMask | GENERIC_READ);
- }
- ea.grfAccessMode = GRANT_ACCESS;
- if(inherit)
- {
- ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
- }
- else
- {
- ea.grfInheritance = NO_INHERITANCE;
- }
- ea.Trustee = trustee;
-
- //
- // Create new ACL
- //
- PACL newAcl = 0;
- res = SetEntriesInAcl(1, &ea, acl, &newAcl);
- if(res != ERROR_SUCCESS)
- {
- throw string("Could not modify ACL for ") + path + ": " + formatMessage(res);
- }
-
- res = SetNamedSecurityInfo(const_cast<char*>(path.c_str()), type,
- DACL_SECURITY_INFORMATION,
- 0, 0, newAcl, 0);
- if(res != ERROR_SUCCESS)
- {
- throw string("Could not grant access to ") + _sidName
- + " on " + path + ": " + formatMessage(res);
- }
-
- if(_debug)
- {
- Trace trace(communicator()->getLogger(), appName());
- trace << "Granted access on " << path << " to " << _sidName;
- }
- }
- }
- catch(...)
- {
- LocalFree(acl);
- LocalFree(newAcl);
- throw;
- }
-
- LocalFree(acl);
- LocalFree(newAcl);
-}
-
-bool
-Install::mkdir(const string& path) const
-{
- if(CreateDirectory(path.c_str(), 0) == 0)
- {
- DWORD res = GetLastError();
- if(res == ERROR_ALREADY_EXISTS)
- {
- return false;
- }
- else if(res == ERROR_PATH_NOT_FOUND)
- {
- string parentPath = path;
- parentPath.erase(parentPath.rfind('\\'));
- mkdir(parentPath);
- return mkdir(path);
- }
- else
- {
- throw "Could not create directory " + path + ": " + formatMessage(res);
- }
- }
- else
- {
- grantPermissions(path, SE_FILE_OBJECT, true, true);
- return true;
- }
-}
-
-string
-Install::formatMessage(DWORD err) const
-{
- ostringstream os;
- char* msgBuf = 0;
- DWORD ok = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- 0,
- err,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- reinterpret_cast<char*>(&msgBuf),
- 0,
- 0);
-
- if(ok)
- {
- os << msgBuf;
- LocalFree(msgBuf);
- }
- else
- {
- os << "unknown error";
- }
-
- return os.str();
-}
-
-void
-Install::uninstallService(const string& serviceName) const
-{
- SC_HANDLE scm = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
- if(scm == 0)
- {
- DWORD res = GetLastError();
- throw string("Cannot open SCM: ") + formatMessage(res);
- }
-
- SC_HANDLE service = OpenService(scm, serviceName.c_str(), SERVICE_ALL_ACCESS);
- if(service == 0)
- {
- DWORD res = GetLastError();
- CloseServiceHandle(scm);
- throw string("Cannot open service: ") + formatMessage(res);
- }
-
- if(!DeleteService(service))
- {
- DWORD res = GetLastError();
- CloseServiceHandle(scm);
- CloseServiceHandle(service);
- throw string("Cannot open service: ") + formatMessage(res);
- }
-
- CloseServiceHandle(scm);
- CloseServiceHandle(service);
-
- removeEventLogKey(serviceName);
-}
-
-void
-Install::installService(const string& serviceName, const string& imagePath,
- const string& configFile, const string& displayName,
- const string& description, const string& dependency,
- const string& password) const
-{
- addEventLogKey(serviceName, getIceDLLPath(imagePath));
-
- SC_HANDLE scm = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
- if(scm == 0)
- {
- DWORD res = GetLastError();
- throw string("Cannot open SCM: ") + formatMessage(res);
- }
-
- string deps = dependency;
-
- if(deps.empty())
- {
- const string candidates[] = { "netprofm", "Nla" };
- const int candidatesLen = 2;
-
- for(int i = 0; i < candidatesLen; ++i)
- {
- SC_HANDLE service = OpenService(scm, candidates[i].c_str(), GENERIC_READ);
- if(service != 0)
- {
- deps = candidates[i];
- CloseServiceHandle(service);
- break; // for
- }
- }
- }
-
- deps += '\0'; // must be double-null terminated
-
- //
- // Get the full path of config file
- //
- char fullPath[MAX_PATH];
- if(GetFullPathName(configFile.c_str(), MAX_PATH, fullPath, 0) > MAX_PATH)
- {
- throw string("Could not compute the full path of ") + configFile;
- }
-
-
- string command = "\"" + imagePath + "\" --service " + serviceName
- + " --Ice.Config=\"" + fullPath + "\"";
-
- SC_HANDLE service = CreateService(
- scm,
- serviceName.c_str(),
- displayName.c_str(),
- SERVICE_ALL_ACCESS,
- SERVICE_WIN32_OWN_PROCESS,
- SERVICE_AUTO_START,
- SERVICE_ERROR_NORMAL,
- command.c_str(),
- 0,
- 0,
- deps.c_str(),
- _sidName.c_str(),
- password.c_str());
-
- if(service == 0)
- {
- DWORD res = GetLastError();
- CloseServiceHandle(scm);
- throw string("Cannot create service: ") + formatMessage(res);
- }
-
- //
- // Set description
- //
-
- SERVICE_DESCRIPTION sd = { const_cast<char*>(description.c_str()) };
-
- if(!ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &sd))
- {
- DWORD res = GetLastError();
- CloseServiceHandle(scm);
- CloseServiceHandle(service);
- throw string("Cannot set description: ") + formatMessage(res);
- }
-
-
- CloseServiceHandle(scm);
- CloseServiceHandle(service);
-}
-
-void
-Install::addEventLogKey(const string& serviceName, const string& resourceFile) const
-{
- HKEY key = 0;
- DWORD disposition = 0;
- LONG res = RegCreateKeyEx(HKEY_LOCAL_MACHINE, createEventLogKey(serviceName).c_str(),
- 0, "REG_SZ", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0,
- &key, &disposition);
- if(res != ERROR_SUCCESS)
- {
- throw "Could not create Event Log key in registry: " + formatMessage(res);
- }
-
- //
- // The event resources are bundled into this DLL, therefore
- // the "EventMessageFile" key should contain the path to this
- // DLL.
- //
- res = RegSetValueEx(key, "EventMessageFile", 0, REG_EXPAND_SZ,
- reinterpret_cast<const BYTE*>(resourceFile.c_str()),
- resourceFile.length() + 1);
-
- if(res == ERROR_SUCCESS)
- {
- //
- // The "TypesSupported" key indicates the supported event
- // types.
- //
- DWORD typesSupported = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE
- | EVENTLOG_INFORMATION_TYPE;
- res = RegSetValueEx(key, "TypesSupported", 0, REG_DWORD,
- reinterpret_cast<BYTE*>(&typesSupported), sizeof(typesSupported));
- }
-
- if(res != ERROR_SUCCESS)
- {
- RegCloseKey(key);
- throw "Could not set registry key: " + formatMessage(res);
- }
-
- res = RegCloseKey(key);
- if(res != ERROR_SUCCESS)
- {
- throw "Could not close registry key handle: " + formatMessage(res);
- }
-}
-
-void
-Install::removeEventLogKey(const string& serviceName) const
-{
- LONG res = RegDeleteKey(HKEY_LOCAL_MACHINE, createEventLogKey(serviceName).c_str());
- if(res != ERROR_SUCCESS)
- {
- throw "Could not remove registry key: " + formatMessage(res);
- }
-}
-
-string
-Install::mangleKey(const string& name) const
-{
- string result = name;
- //
- // The service name cannot contain backslashes.
- //
- string::size_type pos = 0;
- while((pos = result.find('\\', pos)) != string::npos)
- {
- result[pos] = '/';
- }
- return result;
-}
-
-string
-Install::createEventLogKey(const string& name) const
-{
- //
- // The registry key is:
- //
- // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application.
- //
- return "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\" + mangleKey(name);
-}
-
-string
-Install::getIceDLLPath(const string& imagePath) const
-{
- string imagePathDir = imagePath;
- imagePathDir.erase(imagePathDir.rfind('\\'));
-
- //
- // Get current 'DLL' version
- //
- int majorVersion = (ICE_INT_VERSION / 10000);
- int minorVersion = (ICE_INT_VERSION / 100) - majorVersion * 100;
- ostringstream os;
- os << majorVersion * 10 + minorVersion;
-
- int patchVersion = ICE_INT_VERSION % 100;
- if(patchVersion > 50)
- {
- os << 'b';
- if(patchVersion >= 52)
- {
- os << (patchVersion - 50);
- }
- }
- string version = os.str();
-
- string result = imagePathDir + '\\' + "ice" + version + ".dll";
-
- if(fileExists(result))
- {
- return result;
- }
- else
- {
- result = imagePathDir + '\\' + "ice" + version + "d.dll";
- if(fileExists(result))
- {
- return result;
- }
- else
- {
- throw string("Could not find Ice DLL");
- }
- }
-}
diff --git a/cpp/src/iceserviceinstall/Makefile.mak b/cpp/src/iceserviceinstall/Makefile.mak
index e20442869b6..ddd44e81f83 100644
--- a/cpp/src/iceserviceinstall/Makefile.mak
+++ b/cpp/src/iceserviceinstall/Makefile.mak
@@ -7,34 +7,79 @@
#
# **********************************************************************
+#!define HAS_MSI_SDK
+
top_srcdir = ..\..
+LIBNAME = $(top_srcdir)\lib\iceserviceinstaller$(LIBSUFFIX).lib
+DLLNAME = $(top_srcdir)\bin\iceserviceinstaller$(SOVERSION)$(LIBSUFFIX).dll
+
TOOL = $(top_srcdir)\bin\iceserviceinstall.exe
+!ifdef BUILD_UTILS
+
TARGETS = $(TOOL)
-OBJS = Install.obj
+!else
+
+TARGETS = $(LIBNAME) $(DLLNAME)
+
+!endif
+
+TOBJS = Install.obj
+
+OBJS = ServiceInstaller.obj \
+!ifdef HAS_MSI_SDK
+ MsiSupport.obj
+!endif
-SRCS = $(OBJS:.obj=.cpp)
+SRCS = $(TOBJS:.obj=.cpp) \
+ $(OBJS:.obj=.cpp)
!include $(top_srcdir)\config\Make.rules.mak
-CPPFLAGS = $(CPPFLAGS) -DWIN32_LEAN_AND_MEAN
+CPPFLAGS = -I. $(CPPFLAGS) -DWIN32_LEAN_AND_MEAN
+
+!ifdef HAS_MSI_SDK
+LINKWITH = $(LIBS) msi.lib
+!else
+LINKWITH = $(LIBS)
+!endif
+TLINKWITH = $(LIBS) iceserviceinstaller$(LIBSUFFIX).lib
+
+!ifndef BUILD_UTILS
+
+CPPFLAGS = $(CPPFLAGS) -DICE_SERVICE_INSTALLER_API_EXPORTS
+
+!endif
!if "$(CPP_COMPILER)" != "BCC2006" && "$(OPTIMIZE)" != "yes"
-PDBFLAGS = /pdb:$(TOOL:.exe=.pdb)
+PDBFLAGS = /pdb:$(DLLNAME:.dll=.pdb)
+TPDBFLAGS = /pdb:$(TOOL:.exe=.pdb)
!endif
+$(LIBNAME): $(DLLNAME)
-$(TOOL): $(OBJS)
- $(LINK) $(LD_EXEFLAGS) $(PDBFLAGS) $(OBJS) $(SETARGV) $(PREOUT)$@ $(PRELIBS)$(LIBS)
+$(DLLNAME): $(OBJS)
+ $(LINK) $(LD_DLLFLAGS) $(PDBFLAGS) $(OBJS) $(PREOUT)$@ $(PRELIBS)$(LINKWITH)
+ move $(DLLNAME:.dll=.lib) $(LIBNAME)
+ @if exist $@.manifest echo ^ ^ ^ Embedding manifest using $(MT) && \
+ $(MT) -nologo -manifest $@.manifest -outputresource:$@;#2 && del /q $@.manifest
+ @if exist $(DLLNAME:.dll=.exp) del /q $(DLLNAME:.dll=.exp)
+
+$(TOOL): $(TOBJS)
+ $(LINK) $(LD_EXEFLAGS) $(TPDBFLAGS) $(TOBJS) $(SETARGV) $(PREOUT)$@ $(PRELIBS)$(TLINKWITH)
@if exist $@.manifest echo ^ ^ ^ Embedding manifest using $(MT) && \
$(MT) -nologo -manifest $@.manifest security.manifest -outputresource:$@;#1 && del /q $@.manifest
+!ifdef BUILD_UTILS
+
clean::
del /q $(TOOL:.exe=.*)
install:: all
+ copy $(LIBNAME) $(install_libdir)
+ copy $(DLLNAME) $(install_bindir)
copy $(TOOL) $(install_bindir)
!if "$(OPTIMIZE)" != "yes"
@@ -42,15 +87,29 @@ install:: all
!if "$(CPP_COMPILER)" == "BCC2006"
install:: all
+ copy $(DLLNAME:.dll=.tds) $(install_bindir)
+ copy $(SVCDLLNAME:.dll=.tds) $(install_bindir)
copy $(TOOL:.exe=.tds) $(install_bindir)
!else
install:: all
- copy $(TOOOL:.exe=.pdb) $(install_bindir)
+ copy $(DLLNAME:.dll=.pdb) $(install_bindir)
+ copy $(SVCDLLNAME:.dll=.pdb) $(install_bindir)
+ copy $(TOOL:.exe=.pdb) $(install_bindir)
+
+!endif
!endif
+!else
+
+install:: all
+
+$(EVERYTHING)::
+ @$(MAKE) -nologo /f Makefile.mak BUILD_UTILS=1 $@
+
!endif
!include .depend
+
diff --git a/cpp/src/iceserviceinstall/MsiSupport.cpp b/cpp/src/iceserviceinstall/MsiSupport.cpp
new file mode 100755
index 00000000000..860e6425742
--- /dev/null
+++ b/cpp/src/iceserviceinstall/MsiSupport.cpp
@@ -0,0 +1,274 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <ServiceInstaller.h>
+#include <Msiquery.h>
+
+//
+// Provides the iceServiceInstall and iceServiceUninstall functions,
+// to be called from MSI installers
+//
+// They both read MSI properties with the following format:
+// <service>.<name>
+// where <service> is one of the service types (see ServiceInstaller.h)
+// and <name> is either "ConfigFile" or a property name (as provided
+// by the IceServiceInstaller class). If there is no <service>.ConfigFile
+// property, the service is skipped.
+//
+// Errors are logged using a custom MSI logger, that writes to the MSI
+// log file
+//
+
+using namespace std;
+using namespace Ice;
+
+namespace
+{
+
+UINT serviceInstall(MSIHANDLE handle, bool install);
+
+}
+
+extern "C"
+{
+
+ICE_SERVICE_INSTALLER_API
+UINT __stdcall iceServiceInstall(MSIHANDLE handle)
+{
+ return serviceInstall(handle, true);
+}
+
+ICE_SERVICE_INSTALLER_API
+UINT __stdcall iceServiceUninstall(MSIHANDLE handle)
+{
+ return serviceInstall(handle, false);
+}
+
+}
+
+namespace
+{
+//
+// Custom MSI logger
+//
+
+class MsiLogger : public Logger
+{
+public:
+
+ MsiLogger(MSIHANDLE);
+
+ virtual void print(const string&);
+ virtual void trace(const string&, const string&);
+ virtual void warning(const string&);
+ virtual void error(const string&);
+
+private:
+
+ void log(const string&, INSTALLMESSAGE);
+
+ MSIHANDLE _handle;
+};
+
+
+MsiLogger::MsiLogger(MSIHANDLE handle) :
+ _handle(handle)
+{
+}
+
+void
+MsiLogger::print(const string& msg)
+{
+ log(msg, INSTALLMESSAGE_INFO);
+}
+
+void
+MsiLogger::trace(const string& category, const string& msg)
+{
+ string s = "[ ";
+ if(!category.empty())
+ {
+ s += category + ": ";
+ }
+ s += msg + " ]";
+
+ string::size_type idx = 0;
+ while((idx = s.find("\n", idx)) != string::npos)
+ {
+ s.insert(idx + 1, " ");
+ ++idx;
+ }
+ log(s, INSTALLMESSAGE_INFO);
+}
+
+void
+MsiLogger::warning(const string& msg)
+{
+ log(msg, INSTALLMESSAGE_WARNING);
+}
+
+void
+MsiLogger::error(const string& msg)
+{
+ log(msg, INSTALLMESSAGE_ERROR);
+}
+
+void
+MsiLogger::log(const string& msg, INSTALLMESSAGE installMessage)
+{
+ PMSIHANDLE rec = MsiCreateRecord(1); // would 0 be more correct?
+
+ if(rec != 0)
+ {
+ if(MsiRecordSetString(rec, 0, msg.c_str()) == ERROR_SUCCESS)
+ {
+ MsiProcessMessage(_handle, installMessage, rec);
+ }
+ }
+}
+
+UINT serviceInstall(MSIHANDLE handle, bool install)
+{
+ //
+ // Create an custom logger
+ //
+ LoggerPtr msiLogger = new MsiLogger(handle);
+ setProcessLogger(msiLogger);
+ CommunicatorPtr communicator = 0;
+
+ UINT result = ERROR_SUCCESS;
+
+ try
+ {
+ communicator = initialize();
+ char buffer[4096];
+ const DWORD maxBufferSize = 4096;
+
+ UINT res = ERROR_SUCCESS;
+ string propName;
+
+ if(install)
+ {
+ //
+ // Let's see if the xxx.ConfigFile property is defined
+ //
+ const vector<string> propertyNames = IceServiceInstaller::getPropertyNames();
+
+ for(int st = 0; st < IceServiceInstaller::serviceCount; ++st)
+ {
+ const string prefix = IceServiceInstaller::serviceTypeToString(st) + ".";
+ propName = prefix + "ConfigFile";
+
+ DWORD bufferSize = maxBufferSize;
+ res = MsiGetProperty(handle, propName.c_str(), buffer, &bufferSize);
+
+ if(res == ERROR_SUCCESS)
+ {
+ if(bufferSize > 0)
+ {
+ IceServiceInstaller installer(st, buffer, communicator);
+
+ //
+ // Retrieve properties
+ //
+
+ PropertiesPtr properties = createProperties();
+
+ for(size_t i = 0; i < propertyNames.size(); ++i)
+ {
+ const string propName = prefix + propertyNames[i];
+
+ bufferSize = maxBufferSize;
+ res = MsiGetProperty(handle, propName.c_str(), buffer, &bufferSize);
+
+ if(res != ERROR_SUCCESS)
+ {
+ {
+ Error error(msiLogger);
+ error << "Can't read MSI property " << propName;
+ }
+ communicator->destroy();
+ return ERROR_INSTALL_FAILURE;
+ }
+
+ if(bufferSize > 0)
+ {
+ properties->setProperty(propName, buffer);
+ }
+ }
+
+ installer.install(properties);
+ }
+ }
+ else
+ {
+ break; // for
+ }
+ }
+ }
+ else
+ {
+ //
+ // uninstall in reverse order
+ //
+
+ //
+ // Let's see if the xxx.ConfigFile property is defined
+ //
+
+ for(int st = IceServiceInstaller::serviceCount; st >= 0; --st)
+ {
+ const string prefix = IceServiceInstaller::serviceTypeToString(st) + ".";
+ propName = prefix + "ConfigFile";
+
+ DWORD bufferSize = maxBufferSize;
+ res = MsiGetProperty(handle, propName.c_str(), buffer, &bufferSize);
+
+ if(res == ERROR_SUCCESS)
+ {
+ if(bufferSize > 0)
+ {
+ IceServiceInstaller installer(st, buffer, communicator);
+ installer.uninstall();
+ }
+ }
+ }
+ }
+
+ if(res != ERROR_SUCCESS)
+ {
+ //
+ // Report error, fail
+ //
+ {
+ Error error(msiLogger);
+ error << "Cant' read MSI property " << propName;
+ }
+
+ result = ERROR_INSTALL_FAILURE;
+ }
+ }
+ catch(const string& msg)
+ {
+ Error error(msiLogger);
+ error << msg;
+ }
+ catch(const Exception& ex)
+ {
+ Error error(msiLogger);
+ error << ex;
+ }
+
+ if(communicator != 0)
+ {
+ communicator->destroy();
+ }
+ return result;
+}
+}
diff --git a/cpp/src/iceserviceinstall/ServiceInstaller.cpp b/cpp/src/iceserviceinstall/ServiceInstaller.cpp
new file mode 100755
index 00000000000..ee0325665d5
--- /dev/null
+++ b/cpp/src/iceserviceinstall/ServiceInstaller.cpp
@@ -0,0 +1,775 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#define _WIN32_WINNT 0x0500
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE 1 // C4996 '<C function>' was declared deprecated
+#endif
+
+#include <ServiceInstaller.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <Aclapi.h>
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+//
+// The VC6 headers don't include Sddl.h
+//
+#include <Sddl.h>
+#endif
+
+using namespace std;
+using namespace Ice;
+
+IceServiceInstaller::IceServiceInstaller(int serviceType, const string& configFile,
+ const CommunicatorPtr& communicator) :
+ _serviceType(serviceType),
+ _configFile(configFile),
+ _communicator(communicator),
+ _serviceProperties(createProperties()),
+ _sid(0),
+ _debug(false)
+{
+
+ _serviceProperties->load(_configFile);
+
+ //
+ // Compute _serviceName
+ //
+ _defaultLocator = LocatorPrx::uncheckedCast(
+ _communicator->stringToProxy(
+ _serviceProperties->getProperty("Ice.Default.Locator")));
+
+ if(_serviceType == icegridregistry)
+ {
+ _icegridInstanceName =
+ _serviceProperties->getPropertyWithDefault("IceGrid.InstanceName", "IceGrid");
+ _serviceName = serviceTypeToLowerString(_serviceType) + "." + _icegridInstanceName;
+ }
+ else
+ {
+ if(_defaultLocator != 0)
+ {
+ _icegridInstanceName = _defaultLocator->ice_getIdentity().category;
+ }
+
+ if(_serviceType == icegridnode)
+ {
+ if(_icegridInstanceName == "")
+ {
+ throw string("Ice.Default.Locator must be set in " + _configFile);
+ }
+ _nodeName = _serviceProperties->getProperty("IceGrid.Node.Name");
+ if(_nodeName == "")
+ {
+ throw string("IceGrid.Node.Name must be set in " + _configFile);
+ }
+ _serviceName = serviceTypeToLowerString(_serviceType) + "." + _icegridInstanceName + "." + _nodeName;
+ }
+ else if(_serviceType == glacier2router)
+ {
+ _glacier2InstanceName =
+ _serviceProperties->getPropertyWithDefault("Glacier2.InstanceName",
+ "Glacier2");
+ _serviceName = serviceTypeToLowerString(_serviceType) + "." + _glacier2InstanceName;
+ }
+ else
+ {
+ throw string("Unknown service type");
+ }
+ }
+}
+
+
+IceServiceInstaller::~IceServiceInstaller()
+{
+ free(_sid);
+}
+
+void
+IceServiceInstaller::install(const PropertiesPtr& properties)
+{
+ _debug = properties->getPropertyAsInt("Debug") != 0;
+
+ initializeSid(properties->getPropertyWithDefault("ObjectName",
+ "NT Authority\\LocalService"));
+
+ const string defaultDisplayName[] =
+ {
+ string("IceGrid registry (") + _icegridInstanceName + ")",
+ string("IceGrid node (") + _nodeName + " within " + _icegridInstanceName + ")",
+ string("Glacier2 router (") + _glacier2InstanceName + ")"
+ };
+
+ const string defaultDescription[] =
+ {
+ "Location and deployment service for Ice applications",
+ "Starts and monitors Ice servers",
+ "Ice Firewall traversal service"
+ };
+
+ string displayName = properties->getPropertyWithDefault("DisplayName",
+ defaultDisplayName[_serviceType]);
+
+ string description = properties->getPropertyWithDefault("Description",
+ defaultDescription[_serviceType]);
+
+ string imagePath = properties->getProperty("ImagePath");
+
+ if(imagePath == "")
+ {
+ char buffer[MAX_PATH];
+ DWORD size = GetModuleFileName(0, buffer, MAX_PATH);
+ if(size == 0)
+ {
+ throw "Can't get full path to self: " + formatMessage(GetLastError());
+ }
+ imagePath = string(buffer, size);
+ imagePath.replace(imagePath.rfind('\\'), string::npos, string("\\")
+ + serviceTypeToLowerString(_serviceType) + ".exe");
+ }
+ if(!fileExists(imagePath))
+ {
+ throw imagePath + ": not found";
+ }
+
+ string dependency;
+
+ if(_serviceType == icegridregistry)
+ {
+ if(properties->getPropertyAsInt("DependOnRegistry") != 0)
+ {
+ throw string("The IceGrid registry service can't depend on itself");
+ }
+
+ string registryDataDir = _serviceProperties->getProperty("IceGrid.Registry.Data");
+ if(registryDataDir == "")
+ {
+ throw string("IceGrid.Registry.Data must be set in " + _configFile);
+ }
+ if(!mkdir(registryDataDir))
+ {
+ grantPermissions(registryDataDir, SE_FILE_OBJECT, true, true);
+ }
+ }
+ else if(_serviceType == icegridnode)
+ {
+ string nodeDataDir = _serviceProperties->getProperty("IceGrid.Node.Data");
+ if(nodeDataDir == "")
+ {
+ throw string("IceGrid.Node.Data must be set in " + _configFile);
+ }
+ if(!mkdir(nodeDataDir))
+ {
+ grantPermissions(nodeDataDir, SE_FILE_OBJECT, true, true);
+ }
+
+ grantPermissions(
+ "MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
+ SE_REGISTRY_KEY, true);
+
+ if(properties->getPropertyAsInt("DependOnRegistry") != 0)
+ {
+ dependency = "icegridregistry." + _icegridInstanceName;
+ }
+ }
+ else if(_serviceType == glacier2router)
+ {
+ if(properties->getPropertyAsInt("DependOnRegistry") != 0)
+ {
+ if(_icegridInstanceName == "")
+ {
+ throw string("Ice.Default.Locator must be set in " + _configFile
+ + " when DependOnRegistry is not zero");
+ }
+ dependency = "icegridregistry." + _icegridInstanceName;
+ }
+ }
+
+ grantPermissions(_configFile);
+
+ addEventLogKey(_serviceName, getIceDLLPath(imagePath));
+
+ SC_HANDLE scm = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
+ if(scm == 0)
+ {
+ DWORD res = GetLastError();
+ throw string("Cannot open SCM: ") + formatMessage(res);
+ }
+
+ string deps = dependency;
+
+ if(deps.empty())
+ {
+ const string candidates[] = { "netprofm", "Nla" };
+ const int candidatesLen = 2;
+
+ for(int i = 0; i < candidatesLen; ++i)
+ {
+ SC_HANDLE service = OpenService(scm, candidates[i].c_str(), GENERIC_READ);
+ if(service != 0)
+ {
+ deps = candidates[i];
+ CloseServiceHandle(service);
+ break; // for
+ }
+ }
+ }
+
+ deps += '\0'; // must be double-null terminated
+
+ //
+ // Get the full path of config file
+ //
+ char fullPath[MAX_PATH];
+ if(GetFullPathName(_configFile.c_str(), MAX_PATH, fullPath, 0) > MAX_PATH)
+ {
+ throw string("Could not compute the full path of ") + _configFile;
+ }
+
+ string command = "\"" + imagePath + "\" --service " + _serviceName
+ + " --Ice.Config=\"" + fullPath + "\"";
+
+ string password = properties->getProperty("Password");
+
+ SC_HANDLE service = CreateService(
+ scm,
+ _serviceName.c_str(),
+ displayName.c_str(),
+ SERVICE_ALL_ACCESS,
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_AUTO_START,
+ SERVICE_ERROR_NORMAL,
+ command.c_str(),
+ 0,
+ 0,
+ deps.c_str(),
+ _sidName.c_str(),
+ password.c_str());
+
+ if(service == 0)
+ {
+ DWORD res = GetLastError();
+ CloseServiceHandle(scm);
+ throw string("Cannot create service") + _serviceName + ": " + formatMessage(res);
+ }
+
+ //
+ // Set description
+ //
+
+ SERVICE_DESCRIPTION sd = { const_cast<char*>(description.c_str()) };
+
+ if(!ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &sd))
+ {
+ DWORD res = GetLastError();
+ CloseServiceHandle(scm);
+ CloseServiceHandle(service);
+ throw string("Cannot set description for service") + _serviceName + ": "
+ + formatMessage(res);
+ }
+
+ CloseServiceHandle(scm);
+ CloseServiceHandle(service);
+}
+
+void
+IceServiceInstaller::uninstall()
+{
+ SC_HANDLE scm = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
+ if(scm == 0)
+ {
+ DWORD res = GetLastError();
+ throw string("Cannot open SCM: ") + formatMessage(res);
+ }
+
+ SC_HANDLE service = OpenService(scm, _serviceName.c_str(), SERVICE_ALL_ACCESS);
+ if(service == 0)
+ {
+ DWORD res = GetLastError();
+ CloseServiceHandle(scm);
+ throw string("Cannot open service") + _serviceName + ": " + formatMessage(res);
+ }
+
+ if(!DeleteService(service))
+ {
+ DWORD res = GetLastError();
+ CloseServiceHandle(scm);
+ CloseServiceHandle(service);
+ throw string("Cannot delete service") + _serviceName + ": " + formatMessage(res);
+ }
+
+ CloseServiceHandle(scm);
+ CloseServiceHandle(service);
+
+ removeEventLogKey(_serviceName);
+}
+
+/* static */ vector<string>
+IceServiceInstaller::getPropertyNames()
+{
+ static const string propertyNames[] = { "ImagePath", "DisplayName", "ObjectName", "Password",
+ "Description", "DependOnRegistry", "Debug" };
+
+ vector<string> result(propertyNames, propertyNames + 7);
+
+ return result;
+}
+
+/*static*/ string
+IceServiceInstaller::serviceTypeToString(int serviceType)
+{
+ static const string serviceTypeArray[] = { "IceGridRegistry", "IceGridNode", "Glacier2Router" };
+
+ if(serviceType >=0 && serviceType < serviceCount)
+ {
+ return serviceTypeArray[serviceType];
+ }
+ else
+ {
+ return "Unknown service";
+ }
+}
+
+/*static*/ string
+IceServiceInstaller::serviceTypeToLowerString(int serviceType)
+{
+ static const string serviceTypeArray[] = { "icegridregistry", "icegridnode", "glacier2router" };
+
+ if(serviceType >=0 && serviceType < serviceCount)
+ {
+ return serviceTypeArray[serviceType];
+ }
+ else
+ {
+ return "Unknown service";
+ }
+}
+
+void
+IceServiceInstaller::initializeSid(const string& name)
+{
+ {
+ DWORD sidSize = 32;
+ _sid = static_cast<SID*>(malloc(sidSize));
+ memset(_sid, 0, sidSize);
+
+ DWORD domainNameSize = 32;
+ char* domainName = static_cast<char*>(malloc(domainNameSize));
+ memset(domainName, 0, domainNameSize);
+
+ SID_NAME_USE nameUse;
+ while(LookupAccountName(0, name.c_str(), _sid, &sidSize, domainName, &domainNameSize, &nameUse) == false)
+ {
+ DWORD res = GetLastError();
+
+ if(res == ERROR_INSUFFICIENT_BUFFER)
+ {
+ _sid = static_cast<SID*>(realloc(_sid, sidSize));
+ memset(_sid, 0, sidSize);
+ domainName = static_cast<char*>(realloc(domainName, domainNameSize));
+ memset(domainName, 0, domainNameSize);
+ }
+ else
+ {
+ free(_sid);
+ _sid = 0;
+ free(domainName);
+
+ throw string("Could not retrieve Security ID for ") + name + ": "
+ + formatMessage(res);
+ }
+ }
+ free(domainName);
+ }
+
+ //
+ // Now store in _sidName a 'normalized' name (for the CreateService call)
+ //
+
+ if(name.find('\\') != string::npos)
+ {
+ //
+ // Keep this name; otherwise on XP, the localized name
+ // ("NT AUTHORITY\LOCAL SERVICE" in English) shows up in the Services
+ // snap-in instead of 'Local Service' (which is also a localized name,
+ // but looks nicer).
+ //
+ _sidName = name;
+ }
+ else
+ {
+ char accountName[1024];
+ DWORD accountNameLen = 1024;
+
+ char domainName[1024];
+ DWORD domainLen = 1024;
+
+ SID_NAME_USE nameUse;
+ if(LookupAccountSid(0, _sid, accountName, &accountNameLen, domainName,
+ &domainLen, &nameUse) == false)
+ {
+ DWORD res = GetLastError();
+ throw string("Could not retrieve full account name for ") + name + ": "
+ + formatMessage(res);
+ }
+
+ _sidName = string(domainName) + "\\" + accountName;
+ }
+
+ if(_debug)
+ {
+ Trace trace(_communicator->getLogger(), "IceServiceInstaller");
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+ char* sidString = 0;
+ ConvertSidToStringSid(_sid, &sidString);
+ trace << "SID: " << sidString << "; ";
+ LocalFree(sidString);
+#endif
+ trace << "Full name: " << _sidName;
+ }
+}
+
+bool
+IceServiceInstaller::fileExists(const string& path) const
+{
+ struct _stat buffer = { 0 };
+ int err = _stat(path.c_str(), &buffer);
+
+ if(err == 0)
+ {
+ if((buffer.st_mode & _S_IFREG) == 0)
+ {
+ throw path + " is not a regular file";
+ }
+ return true;
+ }
+ else
+ {
+ if(errno == ENOENT)
+ {
+ return false;
+ }
+ else
+ {
+ const char* msg = strerror(errno);
+ throw string("Problem with ") + path + ": " + msg;
+ }
+ }
+}
+
+void
+IceServiceInstaller::grantPermissions(const string& path, SE_OBJECT_TYPE type, bool inherit, bool fullControl) const
+{
+ //
+ // First retrieve the ACL for our file/directory/key
+ //
+ PACL acl = 0;
+ PACL newAcl = 0;
+ PSECURITY_DESCRIPTOR sd = 0;
+ DWORD res = GetNamedSecurityInfo(const_cast<char*>(path.c_str()), type,
+ DACL_SECURITY_INFORMATION,
+ 0, 0, &acl, 0, &sd);
+ if(res != ERROR_SUCCESS)
+ {
+ throw string("Could not retrieve securify info for ") + path + ": "
+ + formatMessage(res);
+ }
+
+ try
+ {
+ //
+ // Now check if _sid can read this file/dir/key
+ //
+ TRUSTEE trustee;
+ BuildTrusteeWithSid(&trustee, _sid);
+
+ ACCESS_MASK accessMask = 0;
+ res = GetEffectiveRightsFromAcl(acl, &trustee, &accessMask);
+
+ if(res != ERROR_SUCCESS)
+ {
+ throw string("Could not retrieve effective rights for ") + _sidName
+ + " on " + path + ": " + formatMessage(res);
+ }
+
+ bool done = false;
+
+ if(type == SE_FILE_OBJECT)
+ {
+ if(fullControl)
+ {
+ done = (accessMask & READ_CONTROL) && (accessMask & SYNCHRONIZE)
+ && (accessMask & 0x1F) == 0x1F;
+ }
+ else
+ {
+ done = (accessMask & READ_CONTROL) && (accessMask & SYNCHRONIZE);
+ }
+ }
+ else
+ {
+ done = (accessMask & READ_CONTROL);
+ }
+
+ if(done)
+ {
+ if(_debug)
+ {
+ Trace trace(_communicator->getLogger(), "IceServiceInstaller");
+ trace << _sidName << " had already the desired permissions on " << path;
+ }
+ }
+ else
+ {
+ EXPLICIT_ACCESS ea = { 0 };
+
+ if(type == SE_FILE_OBJECT && fullControl)
+ {
+ ea.grfAccessPermissions = (accessMask | FILE_ALL_ACCESS);
+ }
+ else
+ {
+ ea.grfAccessPermissions = (accessMask | GENERIC_READ);
+ }
+ ea.grfAccessMode = GRANT_ACCESS;
+ if(inherit)
+ {
+ ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
+ }
+ else
+ {
+ ea.grfInheritance = NO_INHERITANCE;
+ }
+ ea.Trustee = trustee;
+
+ //
+ // Create new ACL
+ //
+ PACL newAcl = 0;
+ res = SetEntriesInAcl(1, &ea, acl, &newAcl);
+ if(res != ERROR_SUCCESS)
+ {
+ throw string("Could not modify ACL for ") + path + ": " + formatMessage(res);
+ }
+
+ res = SetNamedSecurityInfo(const_cast<char*>(path.c_str()), type,
+ DACL_SECURITY_INFORMATION,
+ 0, 0, newAcl, 0);
+ if(res != ERROR_SUCCESS)
+ {
+ throw string("Could not grant access to ") + _sidName
+ + " on " + path + ": " + formatMessage(res);
+ }
+
+ if(_debug)
+ {
+ Trace trace(_communicator->getLogger(), "IceServiceInstaller");
+ trace << "Granted access on " << path << " to " << _sidName;
+ }
+ }
+ }
+ catch(...)
+ {
+ LocalFree(acl);
+ LocalFree(newAcl);
+ throw;
+ }
+
+ LocalFree(acl);
+ LocalFree(newAcl);
+}
+
+bool
+IceServiceInstaller::mkdir(const string& path) const
+{
+ if(CreateDirectory(path.c_str(), 0) == 0)
+ {
+ DWORD res = GetLastError();
+ if(res == ERROR_ALREADY_EXISTS)
+ {
+ return false;
+ }
+ else if(res == ERROR_PATH_NOT_FOUND)
+ {
+ string parentPath = path;
+ parentPath.erase(parentPath.rfind('\\'));
+ mkdir(parentPath);
+ return mkdir(path);
+ }
+ else
+ {
+ throw "Could not create directory " + path + ": " + formatMessage(res);
+ }
+ }
+ else
+ {
+ grantPermissions(path, SE_FILE_OBJECT, true, true);
+ return true;
+ }
+}
+
+string
+IceServiceInstaller::formatMessage(DWORD err) const
+{
+ ostringstream os;
+ char* msgBuf = 0;
+ DWORD ok = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ 0,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ reinterpret_cast<char*>(&msgBuf),
+ 0,
+ 0);
+
+ if(ok)
+ {
+ os << msgBuf;
+ LocalFree(msgBuf);
+ }
+ else
+ {
+ os << "unknown error";
+ }
+
+ return os.str();
+}
+
+void
+IceServiceInstaller::addEventLogKey(const string& serviceName, const string& resourceFile) const
+{
+ HKEY key = 0;
+ DWORD disposition = 0;
+ LONG res = RegCreateKeyEx(HKEY_LOCAL_MACHINE, createEventLogKey(serviceName).c_str(),
+ 0, "REG_SZ", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0,
+ &key, &disposition);
+ if(res != ERROR_SUCCESS)
+ {
+ throw "Could not create Event Log key in registry: " + formatMessage(res);
+ }
+
+ //
+ // The event resources are bundled into this DLL, therefore
+ // the "EventMessageFile" key should contain the path to this
+ // DLL.
+ //
+ res = RegSetValueEx(key, "EventMessageFile", 0, REG_EXPAND_SZ,
+ reinterpret_cast<const BYTE*>(resourceFile.c_str()),
+ resourceFile.length() + 1);
+
+ if(res == ERROR_SUCCESS)
+ {
+ //
+ // The "TypesSupported" key indicates the supported event
+ // types.
+ //
+ DWORD typesSupported = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE
+ | EVENTLOG_INFORMATION_TYPE;
+ res = RegSetValueEx(key, "TypesSupported", 0, REG_DWORD,
+ reinterpret_cast<BYTE*>(&typesSupported), sizeof(typesSupported));
+ }
+
+ if(res != ERROR_SUCCESS)
+ {
+ RegCloseKey(key);
+ throw "Could not set registry key: " + formatMessage(res);
+ }
+
+ res = RegCloseKey(key);
+ if(res != ERROR_SUCCESS)
+ {
+ throw "Could not close registry key handle: " + formatMessage(res);
+ }
+}
+
+void
+IceServiceInstaller::removeEventLogKey(const string& serviceName) const
+{
+ LONG res = RegDeleteKey(HKEY_LOCAL_MACHINE, createEventLogKey(serviceName).c_str());
+ if(res != ERROR_SUCCESS)
+ {
+ throw "Could not remove registry key: " + formatMessage(res);
+ }
+}
+
+string
+IceServiceInstaller::mangleKey(const string& name) const
+{
+ string result = name;
+ //
+ // The service name cannot contain backslashes.
+ //
+ string::size_type pos = 0;
+ while((pos = result.find('\\', pos)) != string::npos)
+ {
+ result[pos] = '/';
+ }
+ return result;
+}
+
+string
+IceServiceInstaller::createEventLogKey(const string& name) const
+{
+ //
+ // The registry key is:
+ //
+ // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application.
+ //
+ return "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\" + mangleKey(name);
+}
+
+string
+IceServiceInstaller::getIceDLLPath(const string& imagePath) const
+{
+ string imagePathDir = imagePath;
+ imagePathDir.erase(imagePathDir.rfind('\\'));
+
+ //
+ // Get current 'DLL' version
+ //
+ int majorVersion = (ICE_INT_VERSION / 10000);
+ int minorVersion = (ICE_INT_VERSION / 100) - majorVersion * 100;
+ ostringstream os;
+ os << majorVersion * 10 + minorVersion;
+
+ int patchVersion = ICE_INT_VERSION % 100;
+ if(patchVersion > 50)
+ {
+ os << 'b';
+ if(patchVersion >= 52)
+ {
+ os << (patchVersion - 50);
+ }
+ }
+ string version = os.str();
+
+ string result = imagePathDir + '\\' + "ice" + version + ".dll";
+
+ if(fileExists(result))
+ {
+ return result;
+ }
+ else
+ {
+ result = imagePathDir + '\\' + "ice" + version + "d.dll";
+ if(fileExists(result))
+ {
+ return result;
+ }
+ else
+ {
+ throw string("Could not find Ice DLL");
+ }
+ }
+}
diff --git a/cpp/src/iceserviceinstall/ServiceInstaller.h b/cpp/src/iceserviceinstall/ServiceInstaller.h
new file mode 100755
index 00000000000..ef35cca4b4d
--- /dev/null
+++ b/cpp/src/iceserviceinstall/ServiceInstaller.h
@@ -0,0 +1,77 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#ifndef ICE_SERVICE_INSTALLER_H
+#define ICE_SERVICE_INSTALLER_H
+
+#ifdef ICE_SERVICE_INSTALLER_API_EXPORTS
+# define ICE_SERVICE_INSTALLER_API ICE_DECLSPEC_EXPORT
+#else
+# define ICE_SERVICE_INSTALLER_API ICE_DECLSPEC_IMPORT
+#endif
+
+#include <Ice/Ice.h>
+
+#include <AccCtrl.h>
+
+class ICE_SERVICE_INSTALLER_API IceServiceInstaller
+{
+public:
+
+ static const int icegridregistry = 0;
+ static const int icegridnode = 1;
+ static const int glacier2router = 2;
+ static const int serviceCount = 3;
+
+ IceServiceInstaller(int, const std::string&, const Ice::CommunicatorPtr&);
+ ~IceServiceInstaller();
+
+ void install(const Ice::PropertiesPtr&);
+
+ void uninstall();
+
+ static std::vector<std::string> getPropertyNames();
+ static std::string serviceTypeToString(int);
+ static std::string serviceTypeToLowerString(int);
+
+private:
+
+ void initializeSid(const std::string&);
+
+ bool fileExists(const std::string&) const;
+ void grantPermissions(const std::string& path, SE_OBJECT_TYPE type = SE_FILE_OBJECT,
+ bool inherit = false, bool fullControl = false) const;
+ bool mkdir(const std::string&) const;
+ std::string formatMessage(DWORD) const;
+
+ void addEventLogKey(const std::string&, const std::string&) const;
+ void removeEventLogKey(const std::string&) const;
+ std::string mangleKey(const std::string&) const;
+ std::string createEventLogKey(const std::string&) const;
+ std::string getIceDLLPath(const std::string&) const;
+
+ int _serviceType;
+ std::string _configFile;
+ Ice::CommunicatorPtr _communicator;
+
+ Ice::PropertiesPtr _serviceProperties;
+ std::string _serviceName;
+ Ice::LocatorPrx _defaultLocator;
+
+ std::string _icegridInstanceName;
+ std::string _nodeName;
+ std::string _glacier2InstanceName;
+
+ SID* _sid;
+ std::string _sidName;
+
+ bool _debug;
+};
+
+#endif