/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.hq.autoinventory.scanimpl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperic.util.PluginLoader; import org.hyperic.util.StringUtil; import org.hyperic.util.config.ConfigOption; import org.hyperic.util.config.ConfigResponse; import org.hyperic.util.timer.StopWatch; import org.hyperic.hq.product.PluginException; import org.hyperic.hq.product.ServerDetector; import org.hyperic.hq.product.RegistryServerDetector; import org.hyperic.hq.autoinventory.AutoinventoryException; import org.hyperic.hq.autoinventory.ServerSignature; import org.hyperic.sigar.win32.RegistryKey; import org.hyperic.sigar.win32.Win32Exception; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * This implementation of ScanMethod knows how to scan the Windows Registry. * It can be configurated to scan the whole registry or only certain keys * while ignoring others. */ public class WindowsRegistryScan extends ScanMethodBase { private ConfigResponse platformConfig; private Log _log = LogFactory.getLog(WindowsRegistryScan.class.getName()); public WindowsRegistryScan () { // we'll give the registry a reliability factor of 7 _authorityLevel = 7; } protected ConfigOption[] getOptionsArray(){ return new ConfigOption[] { }; } public String getName () { return "RegistryScan"; } public String getDisplayName () { return "Registry Scan"; } public String getDescription () { return "Scan the Windows registry"; } private String getPluginName(Object detector) { //XXX these plugins should extend GenericPlugin //like everything else and then use the //GenericPlugin.getName() method. String name = detector.getClass().getName(); int ix = name.lastIndexOf("."); return name.substring(ix+1, name.length()); } public void scan (ConfigResponse platformConfig, ServerDetector[] serverDetectors) throws AutoinventoryException { this.platformConfig = platformConfig; String scanName = "Windows Registry Scan"; HashMap detectorMap = new HashMap(); StopWatch timer = null, totalTimer = null; boolean isDebug = _log.isDebugEnabled(); if (isDebug) { totalTimer = new StopWatch(); timer = new StopWatch(); } _log.debug(scanName + " starting..."); _state.setScanStatus(this, "scan started"); //build a map of RegistryKeys => [detectors] //in the case where multiple detectors want to scan //the same keys, for example WebLogic 7.0 and 8.1 //will scan the same keys. for (int i=0; i<serverDetectors.length; i++) { if (!(serverDetectors[i] instanceof RegistryServerDetector)) { continue; } RegistryServerDetector detector = (RegistryServerDetector)serverDetectors[i]; List keys = detector.getRegistryScanKeys(); for (int j=0; j<keys.size(); j++) { String key = (String)keys.get(j); List detectors = (List)detectorMap.get(key); if (detectors == null) { detectors = new ArrayList(); detectorMap.put(key, detectors); } detectors.add(detector); } } for (Iterator it = detectorMap.entrySet().iterator(); it.hasNext();) { if (_scanner.getIsInterrupted()) { _log.info("Scanner interrupted."); return; } Map.Entry entry = (Map.Entry)it.next(); String key = (String)entry.getKey(); List detectors = (List)entry.getValue(); String status = "scanning: " + key + " with " + detectors.size() + " detectors"; _state.setScanStatus(this, status); if (isDebug) { timer.reset(); } recursiveSearch(detectors, key); if (isDebug) { _log.debug(status + " (took " + timer + ")"); } } if (isDebug) { _log.debug(scanName + " completed, took: " + totalTimer); } _state.setScanStatus(this, scanName + " completed"); } private RegistryKey openRootKey(String key) { try { return RegistryKey.LocalMachine.openSubKey(key); } catch (Win32Exception e) { _log.debug("Could not open registry key '" + key + "': " + e.getMessage()); return null; } } private void recursiveSearch(List detectors, String key) { RegistryKey start; if (!key.endsWith("*")) { if ((start = openRootKey(key)) == null) { return; } searchKey(detectors, start); return; } //simple pattern match for now is all the existing plugins need. //for example if given: //"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MySQL*" //only dig into subkeys of "...\\Uninstall" that startWith("MySQL") String root; int ix = key.lastIndexOf("\\"); if (ix != -1) { root = key.substring(0, ix); key = key.substring(ix+1, key.length()-1); } else { _log.error("Malformed key pattern: " + key); return; } if ((start = openRootKey(root)) == null) { return; } _log.debug("Narrowing search of '" + root + "' to ^" + key + "*"); String[] keyNames = start.getSubKeyNames(); for (int i=0; i<keyNames.length; i++) { RegistryKey subkey; if (!keyNames[i].startsWith(key)) { //skip search of these keys continue; } try { subkey = start.openSubKey(keyNames[i]); } catch (Win32Exception e) { _log.debug("Could not open registry key '" + key + "'"); continue; } searchKey(detectors, subkey); } } // A couple of helper functions to recursively search the registry. private void searchValues(List detectors, RegistryKey curr) { List detectedServers; for (int i=0; i<detectors.size(); i++) { RegistryServerDetector detector = (RegistryServerDetector)detectors.get(i); ServerSignature sig = ((ServerDetector)detector).getServerSignature(); String[] patterns = sig.getRegistryMatchPatterns(); for (int j=0; j<patterns.length; j++) { String matchValue; try { matchValue = curr.getStringValue(patterns[j]); if (matchValue != null) { //trim possible trailing NULL byte matchValue = matchValue.trim(); } } catch (Win32Exception e) { //ok, key does not exist. continue; } String msg = "Error running " + getPluginName(detector) + ": "; PluginLoader.setClassLoader(detector); try { detectedServers = detector.getServerResources(this.platformConfig, matchValue, curr); } catch (PluginException e) { _log.error(msg + e.getMessage(), e); continue; } catch (Exception e) { detectedServers = null; _log.error("Unexpected " + msg + e.getMessage(), e); } catch (NoClassDefFoundError e) { //this is possible in the case of running the agent //with the IBM WebSphere 4 jre on a machine that //has WebLogic servers that will be detected since //the WebLogic code uses jdk 1.4 xml apis. //however, this is very unlikely in the real world //and regardless, not possible to monitor WebLogic //using the IBM 1.3 jdk anyhow. detectedServers = null; _log.error("NoClassDefFoundError " + msg + e.getMessage(), e); } finally { PluginLoader.resetClassLoader(detector); } if (detectedServers != null && detectedServers.size() > 0) { // Add servers to stat // We had a match, save the path and server value. _log.debug("DETECTED SERVERS=" + StringUtil.listToString(detectedServers)); _state.addServers(this, detectedServers); } } } } private void searchKey(List detectors, RegistryKey curr) { searchValues(detectors, curr); searchNextKey(detectors, curr); } private void searchNextKey(List detectors, RegistryKey curr) { String[] keyNames = curr.getSubKeyNames(); for (int i = 0; i < keyNames.length; i++) { RegistryKey next = null; try { next = curr.openSubKey(keyNames[i]); } catch (Win32Exception e) { _log.debug("Unable to open registry key: " + keyNames[i]); continue; } searchValues(detectors, next); searchNextKey(detectors, next); } } }