/****************************************************************************** # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT .IN NO EVENT SHALL NOVELL OR THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE # USE OR OTHER DEALINGS IN THE SOFTWARE. Name : Novell_HostsProvider.cpp Description : This sample instruments the /etc/hosts file on a Linux system Author : Ramandeep Kaur, Jon Carey Date : 28th April, 2005 **********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace OpenWBEM; using namespace WBEMFlags; using std::cerr; using std::endl; namespace { //---------------------------------------------------------------- // parsing class for /etc/hosts //---------------------------------------------------------------- typedef Map SettingsMap; class EtcHosts { public: /* * return All the settings from /etc/hosts as a key value map. */ static SettingsMap getSettings(); /* * Sets a setting in the /etc/hosts file. If the setting is not * found, it is added. else it is modified. */ static void setSetting(const String& key, const String& value); /* * Deletes a setting from the /etc/hosts file. */ static void deleteSetting(const String& key); /* * return the value for a given setting in /etc/hosts. An empty * string on return indicates the setting was not found. */ static String getSettingValue(const String& key); }; class NovellHostsProvider : public CppAssociatorProviderIFC ,public CppMethodProviderIFC { public: String getStringKey(const CIMObjectPath& op, const String& propName) { String rv; CIMProperty kprop = op.getKey(propName); if(kprop) { CIMValue cv = kprop.getValue(); if(cv) { if(cv.getType() == CIMDataType::STRING) { cv.get(rv); rv.trim(); } } } return rv; } String getStringProp(const CIMInstance& inst, const String& propName, bool throwIfAbsent) { String rv; CIMValue cv = inst.getPropertyValue(propName); if(cv) { if(cv.getType() == CIMDataType::STRING) { cv.get(rv); } else { rv = cv.toString(); } } else { if(throwIfAbsent) { OW_THROWCIMMSG(CIMException::INVALID_PARAMETER, ( "Property: %1 is required", propName).c_str()); } } return rv; } virtual void enumInstanceNames( const ProviderEnvironmentIFCRef& env, const String& ns, const String& className, CIMObjectPathResultHandlerIFC& result, const CIMClass& cimClass) { if(className.equalsIgnoreCase("Novell_HostsConfiguration")) { CIMObjectPath cop("Novell_HostsConfiguration", ns); cop.setKeyValue("Name", CIMValue(String("etchosts"))); result.handle(cop); } else if(className.equalsIgnoreCase("Novell_HostsSetting")) { CIMObjectPath cop("Novell_HostsSetting", ns); SettingsMap sm = EtcHosts::getSettings(); SettingsMap::iterator smit = sm.begin(); while(smit != sm.end()) { cop.setKeyValue("IPaddress", CIMValue(smit->first)); result.handle(cop); smit++; } } } //////////////////////////////////////////////////////////////////////////// virtual void enumInstances( const ProviderEnvironmentIFCRef& env, const String& ns, const String& className, CIMInstanceResultHandlerIFC& result, ELocalOnlyFlag localOnly, EDeepFlag deep, EIncludeQualifiersFlag includeQualifiers, EIncludeClassOriginFlag includeClassOrigin, const StringArray* propertyList, const CIMClass& requestedClass, const CIMClass& cimClass ) { if(className.equalsIgnoreCase("Novell_HostsConfiguration")) { CIMInstance ci = cimClass.newInstance(); ci.setProperty("Name", CIMValue(String("etchosts"))); result.handle(ci.clone(localOnly, includeQualifiers, includeClassOrigin, propertyList)); } else if(className.equalsIgnoreCase("Novell_HostsSetting")) { CIMInstance ci = cimClass.newInstance(); SettingsMap sm = EtcHosts::getSettings(); SettingsMap::iterator smit = sm.begin(); while(smit != sm.end()) { ci.setProperty("IPAddress", CIMValue(smit->first)); ci.setProperty("FullHostName", CIMValue(smit->second)); result.handle(ci.clone(localOnly, includeQualifiers, includeClassOrigin, propertyList)); smit++; } } } //////////////////////////////////////////////////////////////////////////// virtual CIMInstance getInstance( const ProviderEnvironmentIFCRef& env, const String& ns, const CIMObjectPath& instanceName, ELocalOnlyFlag localOnly, EIncludeQualifiersFlag includeQualifiers, EIncludeClassOriginFlag includeClassOrigin, const StringArray* propertyList, const CIMClass& cimClass ) { String className = cimClass.getName(); if(className.equalsIgnoreCase("Novell_HostsConfiguration")) { String name = getStringKey(instanceName, "Name"); if(name != "etchosts") { OW_THROWCIMMSG(CIMException::NOT_FOUND, ("Object not found: %1", instanceName.toString()).c_str()); } CIMInstance ci = cimClass.newInstance(); ci.setProperty("Name", CIMValue(String("etchosts"))); return ci.clone(localOnly, includeQualifiers, includeClassOrigin, propertyList); } else if(className.equalsIgnoreCase("Novell_HostsSetting")) { String key = getStringKey(instanceName, "IPAddress"); if(key.length() == 0) { OW_THROWCIMMSG(CIMException::INVALID_PARAMETER, ("Invalid Object path: %1", instanceName.toString()).c_str()); } String value = EtcHosts::getSettingValue(key); if(value.length() == 0) { OW_THROWCIMMSG(CIMException::NOT_FOUND, ("Object not found: %1", instanceName.toString()).c_str()); } CIMInstance ci = cimClass.newInstance(); ci.setProperty("IPAddress", CIMValue(key)); ci.setProperty("FullHostName", CIMValue(value)); return ci.clone(localOnly, includeQualifiers, includeClassOrigin, propertyList); } else { OW_THROWCIMMSG(CIMException::NOT_FOUND, ("Object not found: %1", instanceName.toString()).c_str()); } return CIMInstance(CIMNULL); } //////////////////////////////////////////////////////////////////////////// virtual CIMObjectPath createInstance( const ProviderEnvironmentIFCRef& env, const String& ns, const CIMInstance& cimInstance ) { String className = cimInstance.getClassName(); if(className.equalsIgnoreCase("Novell_HostsConfiguration")) { OW_THROWCIMMSG(CIMException::NOT_SUPPORTED, "You can't create instances of this class"); } else if(className.equalsIgnoreCase("Novell_HostsSetting")) { String name = getStringProp(cimInstance, "IPAddress", true); String value = EtcHosts::getSettingValue(name); if(value.length() != 0) { OW_THROWCIMMSG(CIMException::ALREADY_EXISTS, ("Object already exists: %1", name).c_str()); } value = getStringProp(cimInstance, "FullHostName", true); EtcHosts::setSetting(name, value); CIMObjectPath cop("Novell_HostsSetting", ns); cop.setKeyValue("IPAddess", CIMValue(name)); return cop; } else { OW_THROWCIMMSG(CIMException::FAILED, ("Novell_HostsProvider does not support creation of" " %1 objects", className).c_str()); } } //////////////////////////////////////////////////////////////////////////// virtual void modifyInstance( const ProviderEnvironmentIFCRef& env, const String& ns, const CIMInstance& modifiedInstance, const CIMInstance& previousInstance, EIncludeQualifiersFlag includeQualifiers, const StringArray* propertyList, const CIMClass& theClass) { String className = theClass.getName(); if(className.equalsIgnoreCase("Novell_HostsConfiguration")) { OW_THROWCIMMSG(CIMException::NOT_SUPPORTED, "You can't modify instances of this class"); } else if(className.equalsIgnoreCase("Novell_HostsSetting")) { CIMInstance mci = modifiedInstance.createModifiedInstance( previousInstance, includeQualifiers, propertyList, theClass); String name = getStringProp(mci, "IPAddress", true); String value = EtcHosts::getSettingValue(name); if(value.length() == 0) { OW_THROWCIMMSG(CIMException::NOT_FOUND, ("Object not found for modification: %1", name).c_str()); } value = getStringProp(mci, "FullHostName", true); if(value.length() == 0) { OW_THROWCIMMSG(CIMException::INVALID_PARAMETER, "FullHostName property must be given"); } EtcHosts::setSetting(name, value); } else { OW_THROWCIMMSG(CIMException::FAILED, ("Novell_HostsProvider does not support modification of" " %1 objects", className).c_str()); } } //////////////////////////////////////////////////////////////////////////// virtual void deleteInstance( const ProviderEnvironmentIFCRef& env, const String& ns, const CIMObjectPath& cop) { String className = cop.getClassName(); if(className.equalsIgnoreCase("Novell_HostsConfiguration")) { OW_THROWCIMMSG(CIMException::NOT_SUPPORTED, "You can't delete instances of this class"); } else if(className.equalsIgnoreCase("Novell_HostsSetting")) { String key = getStringKey(cop, "IPAddress"); if(key.length() == 0) { OW_THROWCIMMSG(CIMException::INVALID_PARAMETER, ("Invalid Object path: %1", cop.toString()).c_str()); } String value = EtcHosts::getSettingValue(key); if(value.length() == 0) { OW_THROWCIMMSG(CIMException::NOT_FOUND, ("Object not found: %1", cop.toString()).c_str()); } EtcHosts::deleteSetting(key); } else { OW_THROWCIMMSG(CIMException::FAILED, ("Novell_HostsProvider does not support deletion of" " %1 objects", className).c_str()); } } //////////////////////////////////////////////////////////////////////////// virtual void associators( const ProviderEnvironmentIFCRef& env, CIMInstanceResultHandlerIFC& result, const String& ns, const CIMObjectPath& objectName, const String& assocClass, const String& resultClass, const String& role, const String& resultRole, EIncludeQualifiersFlag includeQualifiers, EIncludeClassOriginFlag includeClassOrigin, const StringArray* propertyList) { if(assocClass.equalsIgnoreCase("Novell_HostsSettingContext")) { CIMOMHandleIFCRef lch = env->getCIMOMHandle(); String objClass = objectName.getClassName(); if(objClass.equalsIgnoreCase("Novell_HostsConfiguration")) { CIMClass cc = lch->getClass(ns, "Novell_HostsSetting", E_NOT_LOCAL_ONLY, E_INCLUDE_QUALIFIERS, E_INCLUDE_CLASS_ORIGIN); enumInstances(env, ns, "Novell_HostsSetting", result, E_NOT_LOCAL_ONLY, E_DEEP, includeQualifiers, includeClassOrigin, propertyList, cc, cc); } else if(objClass.equalsIgnoreCase("Novell_HostsSetting")) { CIMClass cc = lch->getClass(ns, "Novell_HostsConfiguration", E_NOT_LOCAL_ONLY, E_INCLUDE_QUALIFIERS, E_INCLUDE_CLASS_ORIGIN); enumInstances(env, ns, "Novell_HostsConfiguration", result, E_NOT_LOCAL_ONLY, E_DEEP, includeQualifiers, includeClassOrigin, propertyList, cc, cc); } } } //////////////////////////////////////////////////////////////////////////// virtual void associatorNames( const ProviderEnvironmentIFCRef& env, CIMObjectPathResultHandlerIFC& result, const String& ns, const CIMObjectPath& objectName, const String& assocClass, const String& resultClass, const String& role, const String& resultRole) { cerr<<" AssociatorNames "<getCIMOMHandle(); String objClass = objectName.getClassName(); if(objClass.equalsIgnoreCase("Novell_HostsConfiguration")) { cerr<<" AssociatorNames::COnfig "<getClass(ns, "Novell_HostsSetting", E_NOT_LOCAL_ONLY, E_INCLUDE_QUALIFIERS, E_INCLUDE_CLASS_ORIGIN); enumInstanceNames(env, ns, "Novell_HostsSetting", result, cc); } else if(objClass.equalsIgnoreCase("Novell_HostsSetting")) { cerr<<" AssociatorNames::Setting "<getClass(ns, "Novell_HostsConfiguration", E_NOT_LOCAL_ONLY, E_INCLUDE_QUALIFIERS, E_INCLUDE_CLASS_ORIGIN); enumInstanceNames(env, ns, "Novell_HostsConfiguration", result, cc); } } } //////////////////////////////////////////////////////////////////////////// virtual void references( const ProviderEnvironmentIFCRef& env, CIMInstanceResultHandlerIFC& result, const String& ns, const CIMObjectPath& objectName, const String& resultClass, const String& role, EIncludeQualifiersFlag includeQualifiers, EIncludeClassOriginFlag includeClassOrigin, const StringArray* propertyList) { if(resultClass.equalsIgnoreCase("Novell_HostsSettingContext")) { CIMOMHandleIFCRef lch = env->getCIMOMHandle(); CIMClass cc = lch->getClass(ns, "Novell_HostsSettingContext", E_NOT_LOCAL_ONLY, E_INCLUDE_QUALIFIERS, E_INCLUDE_CLASS_ORIGIN); CIMInstance ci = cc.newInstance(); CIMObjectPath configOp("Novell_HostsConfiguration", ns); configOp.setKeyValue("Name", CIMValue(String("etchosts"))); ci.setProperty("Context", CIMValue(configOp)); String objClass = objectName.getClassName(); if(objClass.equalsIgnoreCase("Novell_HostsConfiguration")) { CIMObjectPath settingOp("Novell_HostsSetting", ns); SettingsMap sm = EtcHosts::getSettings(); SettingsMap::iterator smit = sm.begin(); while(smit != sm.end()) { settingOp.setKeyValue("IPAddress", CIMValue(smit->first)); ci.setProperty("Setting", CIMValue(settingOp)); result.handle(ci.clone(E_NOT_LOCAL_ONLY, includeQualifiers, includeClassOrigin, propertyList)); smit++; } } else if(objClass.equalsIgnoreCase("Novell_HostsSetting")) { String key = getStringKey(objectName, "IPAddess"); if(key.length() == 0) { OW_THROWCIMMSG(CIMException::INVALID_PARAMETER, ("Invalid Object path: %1", objectName.toString()).c_str()); } ci.setProperty("Setting", CIMValue(objectName)); result.handle(ci.clone(E_NOT_LOCAL_ONLY, includeQualifiers, includeClassOrigin, propertyList)); } } } //////////////////////////////////////////////////////////////////////////// virtual void referenceNames( const ProviderEnvironmentIFCRef& env, CIMObjectPathResultHandlerIFC& result, const String& ns, const CIMObjectPath& objectName, const String& resultClass, const String& role) { if(resultClass.equalsIgnoreCase("Novell_HostsSettingContext")) { CIMObjectPath resultOp("Novell_HostsSettingContext", ns); CIMObjectPath configOp("Novell_HostsConfiguration", ns); configOp.setKeyValue("Name", CIMValue(String("etchosts"))); resultOp.setKeyValue("Context", CIMValue(configOp)); String objClass = objectName.getClassName(); if(objClass.equalsIgnoreCase("Novell_HostsConfiguration")) { CIMObjectPath settingOp("Novell_HostsSetting", ns); SettingsMap sm = EtcHosts::getSettings(); SettingsMap::iterator smit = sm.begin(); while(smit != sm.end()) { settingOp.setKeyValue("IPAddress", CIMValue(smit->first)); resultOp.setKeyValue("Setting", CIMValue(settingOp)); result.handle(resultOp); smit++; } } else if(objClass.equalsIgnoreCase("Novell_HostsSetting")) { String key = getStringKey(objectName, "IPAddress"); if(key.length() == 0) { OW_THROWCIMMSG(CIMException::INVALID_PARAMETER, ("Invalid Object path: %1", objectName.toString()).c_str()); } resultOp.setKeyValue("Setting", CIMValue(objectName)); result.handle(resultOp); } } } //////////////////////////////////////////////////////////////////////////// virtual CIMValue invokeMethod( const ProviderEnvironmentIFCRef& env, const String& ns, const CIMObjectPath& path, const String& methodName, const CIMParamValueArray& in, CIMParamValueArray& out ) { if(methodName.equalsIgnoreCase("gettime")) { DateTime dt(::time(NULL)); CIMDateTime cdt(dt); return CIMValue(cdt.toString()); } else OW_THROWCIMMSG(CIMException::FAILED, ("Provider does not support method: %1", methodName).c_str()); } //////////////////////////////////////////////////////////////////////////// virtual void getInstanceProviderInfo( InstanceProviderInfo& info) { info.addInstrumentedClass("Novell_HostsConfiguration"); info.addInstrumentedClass("Novell_HostsSetting"); } //////////////////////////////////////////////////////////////////////////// virtual void getMethodProviderInfo( MethodProviderInfo& info) { StringArray methods; methods.append("gettime"); MethodProviderInfo::ClassInfo ci("Novell_HostsConfiguration", StringArray(), methods); info.addInstrumentedClass(ci); } //////////////////////////////////////////////////////////////////////////// virtual void getAssociatorProviderInfo( AssociatorProviderInfo& info) { info.addInstrumentedClass("Novell_HostsSettingContext"); } }; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // PARSING Code ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// #define ETCHOSTSFILE "/etc/hosts" ////////////////////////////////////////////////////////////////////////////// SettingsMap EtcHosts::getSettings() { std::ifstream ifs(ETCHOSTSFILE); if (!ifs) { cerr << "Failed to open "ETCHOSTSFILE << endl; return SettingsMap(); } SettingsMap sm; StringArray toks; StringBuffer sbfr; while(ifs) { sbfr.getLine(ifs, true); if (!ifs) break; sbfr.trim(); // If empty line of comment, ignore it. if(sbfr.length() < 1 || sbfr.startsWith('#')) continue; toks = sbfr.toString().tokenize(); if(toks.size() != 2) { // Not a key value pair. continue; } sm[toks[0].trim()] = toks[1].trim(); } ifs.close(); return sm; } ////////////////////////////////////////////////////////////////////////////// #define TEMPFILE_NAME "/tmp/demofile" void EtcHosts::setSetting(const String& key, const String& value) { bool found = false; ::unlink(TEMPFILE_NAME); std::ofstream ofs(TEMPFILE_NAME); if (!ofs) { cerr << "Failed to create "TEMPFILE_NAME << endl; return; } std::ifstream ifs(ETCHOSTSFILE); if (!ifs) { cerr << "Failed to open "ETCHOSTSFILE << endl; ofs.close(); return; } StringArray toks; StringBuffer sbfr; String line; while(ifs) { sbfr.getLine(ifs, true); if (!ifs) break; line = sbfr.toString(); sbfr.trim(); // If empty line of comment, ignore it. if(sbfr.length() < 1 || sbfr.startsWith('#')) { ofs << line << '\n'; continue; } toks = sbfr.toString().tokenize(); if(toks.size() != 2) { // Not a key value pair. ofs << line << '\n'; continue; } toks[0].trim(); if(toks[0].equalsIgnoreCase(key)) { ofs << key << "\t\t" << value << '\n'; found = true; } else { ofs << line << '\n'; } } ifs.close(); if(!found) { ofs << key << "\t\t" << value << '\n'; } ofs.close(); ::unlink(ETCHOSTSFILE); ::rename(TEMPFILE_NAME, ETCHOSTSFILE); } ////////////////////////////////////////////////////////////////////////////// void EtcHosts::deleteSetting(const String& key) { bool found = false; ::unlink(TEMPFILE_NAME); std::ofstream ofs(TEMPFILE_NAME); if (!ofs) { cerr << "Failed to create "TEMPFILE_NAME << endl; return; } std::ifstream ifs(ETCHOSTSFILE); if (!ifs) { cerr << "Failed to open "ETCHOSTSFILE << endl; ofs.close(); return; } StringArray toks; StringBuffer sbfr; String line; while(ifs) { sbfr.getLine(ifs, true); if (!ifs) break; line = sbfr.toString(); sbfr.trim(); // Ignore the empty line of comments if(sbfr.length() < 1 || sbfr.startsWith('#')) { ofs << line << '\n'; continue; } toks = sbfr.toString().tokenize(); if(toks.size() != 2) { // Not a key value pair. ofs << line << '\n'; continue; } toks[0].trim(); if(!toks[0].equalsIgnoreCase(key)) { ofs << line << '\n'; } } ifs.close(); ofs.close(); ::unlink(ETCHOSTSFILE); ::rename(TEMPFILE_NAME, ETCHOSTSFILE); } ////////////////////////////////////////////////////////////////////////////// String EtcHosts::getSettingValue(const String& key) { String value; std::ifstream ifs(ETCHOSTSFILE); if (!ifs) { cerr << "Failed to open /etc/hosts file " << endl; ifs.close(); return value; } StringArray toks; StringBuffer sbfr; while(ifs) { sbfr.getLine(ifs, true); if (!ifs) { break; } sbfr.trim(); // If empty line of comment, ignore it. if(sbfr.length() < 1 || sbfr.startsWith('#')) { continue; } toks = sbfr.toString().tokenize(); if(toks.size() != 2) { // Not a key value pair. continue; } toks[0].trim(); if(toks[0].equalsIgnoreCase(key)) { value = toks[1]; break; } } ifs.close(); return value; } OW_PROVIDERFACTORY(NovellHostsProvider, novellhostsprovider);