/*
* 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-2013], 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.plugin.sharepoint;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xpath.XPathAPI;
import org.hyperic.sigar.win32.MetaBase;
import org.hyperic.sigar.win32.Win32Exception;
import org.hyperic.util.exec.Execute;
import org.hyperic.util.exec.ExecuteWatchdog;
import org.hyperic.util.exec.PumpStreamHandler;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class IisMetaBase {
private static final Log log =
LogFactory.getLog(IisMetaBase.class.getName());
private static final String IIS_MKEY = "/LM/W3SVC";
private static final int MD_SSL_ACCESS_PERM = 6030;
private static final int MD_ACCESS_SSL = 0x00000008;
protected static final String APPCMD = "C:/Windows/System32/inetsrv/appcmd.exe";
private String id;
private String ip;
private String hostname;
private String port;
private String path;
private boolean requireSSL = false;
private String name;
@Override
public String toString() {
return "IisMetaBase{" + "id=" + id + ", name=" + name + ", ip=" + ip + ", hostname=" + hostname + ", port=" + port + ", path=" + path + ", requireSSL=" + requireSSL + '}';
}
public String toUrlString() throws MalformedURLException {
URL url = new URL(requireSSL ? "https" : "http", ip, Integer.parseInt(port), "/");
String urlStr = url.toString();
log.debug("web: '" + this + "'");
log.debug("urlStr: '" + urlStr + "'");
return urlStr;
}
public static Map<String, IisMetaBase> getWebSites()
throws Win32Exception {
if (new File(APPCMD).exists()) {
try {
return getWebSitesViaAppCmd(); //IIS7
} catch (Exception e) {
log.debug(APPCMD + ": " + e, e);
throw new Win32Exception(e.getMessage());
}
} else {
return getWebSitesViaMetaBase();
}
}
private static boolean parseBinding(IisMetaBase info, String entry) {
if (entry == null) {
return false;
}
int ix = entry.indexOf(":");
if (ix == -1) {
return false;
}
//binding format:
//"listen ip:port:host header"
info.ip = entry.substring(0, ix);
entry = entry.substring(ix + 1);
ix = entry.indexOf(":");
info.port = entry.substring(0, ix);
//if host header is defined, URLMetric
//will add Host: header with this value.
info.hostname = entry.substring(ix + 1);
if ((info.hostname != null)
&& (info.hostname.length() == 0)) {
info.hostname = null;
}
if ((info.ip == null)
|| (info.ip.length() == 0)
|| (info.ip.equals("*"))) {
//not bound to a specific ip
info.ip = "localhost";
}
return true;
}
//IIS7 does not use MetaBase
private static Map getWebSitesViaAppCmd()
throws Exception {
final String[] cmd = {
APPCMD, "list", "config",
"-section:system.applicationHost/sites"
};
Map websites = new HashMap();
ByteArrayOutputStream output =
new ByteArrayOutputStream();
ExecuteWatchdog wdog =
new ExecuteWatchdog(5 * 1000);
Execute exec =
new Execute(new PumpStreamHandler(output), wdog);
exec.setCommandline(cmd);
try {
int exitStatus = exec.execute();
if (exitStatus != 0 || wdog.killedProcess()) {
log.debug(Arrays.asList(cmd) + ": " + output);
return websites;
}
} catch (Exception e) {
log.debug(Arrays.asList(cmd) + ": " + e);
return websites;
}
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document config =
db.parse(new ByteArrayInputStream(output.toString().getBytes("UTF-8")));
NodeList sites =
XPathAPI.selectNodeList(config, "//sites/site");
for (int i = 0; i < sites.getLength(); i++) {
Element site = (Element) sites.item(i);
String name = site.getAttribute("name");
IisMetaBase info = new IisMetaBase();
info.id = site.getAttribute("id");
String sitePath = "//site[@name=\"" + name + "\"]/";
String bindPath = sitePath + "bindings/binding[1]";
String docPath =
sitePath + "application[1]/virtualDirectory[1]/@physicalPath";
Element binding =
(Element) XPathAPI.selectSingleNode(site, bindPath);
if (binding == null) {
log.debug("No bindings defined for: " + name);
continue;
}
String proto = binding.getAttribute("protocol");
if (proto != null) {
if ("https".equals(proto.toString().trim())) {
info.requireSSL = true;
}
}
String bindInfo = binding.getAttribute("bindingInformation");
if (!parseBinding(info, bindInfo)) {
log.debug("Failed to parse bindingInformation="
+ bindInfo + " for: " + name);
continue;
}
Object docRoot = XPathAPI.eval(site, docPath);
if (docRoot != null) {
info.path = docRoot.toString();
}
log.debug(name + "=" + info);
websites.put(name, info);
}
return websites;
}
private static Map<String, IisMetaBase> getWebSitesViaMetaBase()
throws Win32Exception {
String keys[];
Map websites = new HashMap();
MetaBase mb = new MetaBase();
try {
mb.OpenSubKey(IIS_MKEY);
keys = mb.getSubKeyNames();
} finally {
mb.close();
}
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
int id;
if (!Character.isDigit(key.charAt(0))) {
continue;
}
try {
id = Integer.parseInt(key);
} catch (NumberFormatException e) {
continue;
}
String subkey = IIS_MKEY + "/" + id;
MetaBase srv = null;
try {
srv = new MetaBase();
srv.OpenSubKey(subkey);
String[] bindings = null;
IisMetaBase info = new IisMetaBase();
//IIS 6.0+Windows 2003 has Administration website
//that requires SSL by default.
//Any Web Site can be configured to required ssl.
try {
int flags = srv.getIntValue(MD_SSL_ACCESS_PERM);
info.requireSSL = (flags & MD_ACCESS_SSL) != 0;
if (info.requireSSL) {
bindings =
srv.getMultiStringValue(MetaBase.MD_SECURE_BINDINGS);
}
} catch (Win32Exception e) {
}
if (bindings == null) {
bindings =
srv.getMultiStringValue(MetaBase.MD_SERVER_BINDINGS);
}
info.id = key;
if (bindings.length == 0) {
continue;
}
if (!parseBinding(info, bindings[0])) {
continue;
}
String name =
srv.getStringValue(MetaBase.MD_SERVER_COMMENT);
info.setName(name);
websites.put(name, info);
//XXX this is bogus, else locks the metabase
//because OpenSubKey does not close the key
//thats already open.
srv.close();
srv = null;
srv = new MetaBase();
srv.OpenSubKey(subkey + "/ROOT");
String docroot =
srv.getStringValue(3001);
info.path = docroot;
} catch (Win32Exception e) {
} finally {
if (srv != null) {
srv.close();
}
}
}
return websites;
}
public static void main(String[] args) throws Exception {
Map websites = IisMetaBase.getWebSites();
System.out.println(websites);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}