diff options
Diffstat (limited to 'cpp/src')
-rwxr-xr-x | cpp/src/iceserviceinstall/Install.cpp | 781 | ||||
-rw-r--r-- | cpp/src/iceserviceinstall/Makefile.mak | 73 | ||||
-rwxr-xr-x | cpp/src/iceserviceinstall/MsiSupport.cpp | 274 | ||||
-rwxr-xr-x | cpp/src/iceserviceinstall/ServiceInstaller.cpp | 775 | ||||
-rwxr-xr-x | cpp/src/iceserviceinstall/ServiceInstaller.h | 77 |
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 |