/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2006-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.capsd;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import jcifs.netbios.NbtAddress;
import jcifs.smb.SmbAuthException;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.core.utils.ThreadCategory;
import org.opennms.netmgt.config.CapsdConfigFactory;
import org.opennms.netmgt.config.capsd.SmbAuth;
/**
* This class is designed to collect the necessary SMB information from the
* target address and store the collected information. When the class is
* initially constructed no information is collected.
*
* @author <a href="mailto:weave@oculan.com">Weave </a>
* @author <a href="mailto:mike@opennms.org">Mike </a>
* @author <a href="http://www.opennms.org">OpenNMS </a>
*
*/
final class IfSmbCollector implements Runnable {
/**
* The MAC address that is returned from a Samba server
*/
private static final String SAMBA_MAC = "00:00:00:00:00:00";
/**
* The target internet address to test for SMB support
*/
private final InetAddress m_target;
/**
* This value is set of the node supports SMB.
*/
private boolean m_isSamba;
/**
* The collected media access control address.
*/
private String m_mac;
/**
* The domain name.
*/
private String m_domain;
/**
* The primary NetBIOS address.
*/
private NbtAddress m_addr;
/**
* The list of all the NetBIOS addresses for the target IP.
*/
private NbtAddress[] m_allAddrs;
/**
* The list of available shares on the SMB box, if any
*/
private String[] m_shares;
/**
* True if the box has MS Exchange running. This is set in the constructor.
*/
private final boolean m_hasExchange;
/**
* This method is used to convert a 6 byte MAC address into a colon
* separated string.
*
* @param mac
* The 6 byte MAC address
*
* @return The formatted MAC address.
*/
private String toMacString(byte[] mac) {
StringBuffer mbuf = new StringBuffer();
for (int i = 0; i < mac.length; i++) {
mbuf.append((int) (mac[i] >> 4) & 0x0f).append((int) mac[i] & 0x0f);
if (i != 5)
mbuf.append(':');
}
return mbuf.toString();
}
/**
* Constructs a new SMB collector targeted at the passed address. The
* presence of an Exchange server is set to false.
*
* @param target
* The target IP address.
*
*/
IfSmbCollector(InetAddress target) {
m_target = target;
m_isSamba = false;
m_mac = null;
m_addr = null;
m_domain = null;
m_allAddrs = null;
m_shares = null;
m_hasExchange = false;
}
/**
* Constructs a new SMB collector targeted at the passed address. The
* presence of an Exchange server is set to passed value.
*
* @param target
* The target IP address.
* @param hasExchange
* Sets the presence or absence of an exchange server.
*
*/
IfSmbCollector(InetAddress target, boolean hasExchange) {
m_target = target;
m_isSamba = false;
m_mac = null;
m_addr = null;
m_domain = null;
m_allAddrs = null;
m_shares = null;
m_hasExchange = hasExchange;
}
/**
* Returns the current target of this collection.
*/
InetAddress getTarget() {
return m_target;
}
/**
* Returns true if the target is a SAMBA server.
*/
boolean isSamba() {
return m_isSamba;
}
/**
* Returns the MAC address, if present.
*/
String getMAC() {
return m_mac;
}
/**
* Returns the primary NetBIOS address for the target if it was recovered.
*/
NbtAddress getNbtAddress() {
return m_addr;
}
/**
* Retrns the NetBIOS name associated with the primary NetBIOS address.
*/
String getNbtName() {
if (m_addr != null)
return m_addr.getHostName().trim();
else
return null;
}
/**
* Returns the domain name associated with this NetBIOS address
*/
String getDomainName() {
return m_domain;
}
/**
* Returns the list of all NetBIOS names recovered from the target node.
*/
NbtAddress[] getAllNbtAddresses() {
return m_allAddrs;
}
/**
* Returns the list of all available shares on the target if the call
* succeeded. If the call failed then a null or empty list is return.
*/
String[] getShares() {
return m_shares;
}
/**
* Returns the presence of an exchange server. This is the same value as set
* in the class' constructor.
*/
boolean hasExchange() {
return m_hasExchange;
}
/**
* This method inspects the provided netBIOS name for control characters
* (chars w/ decimal value less than 20/ <SPACE>
*
* @param nbName
* NetBIOS name to check
*
* @return true if string contains control chars, false otherwise.
*/
boolean containsCtrlChars(String nbName) {
byte[] bytes = nbName.getBytes();
for (int i = 0; i < bytes.length; i++) {
if (bytes[i] < 20)
return true;
}
return false;
}
/**
* The main execution method used to collect the SMB information for the
* collector.
*/
public void run() {
ThreadCategory log = ThreadCategory.getInstance(getClass());
try {
m_addr = NbtAddress.getByName(InetAddressUtils.str(m_target));
// If the retrieved SMB name is equal to the IP address
// of the host, the it is safe to assume that the interface
// does not support SMB
//
if (m_addr.getHostName().equals(InetAddressUtils.str(m_target))) {
if (log.isDebugEnabled())
log.debug("IfSmbCollector: failed to retrieve SMB name for " + InetAddressUtils.str(m_target));
m_addr = null;
}
} catch (UnknownHostException e) {
if (log.isDebugEnabled())
log.debug("IfSmbCollector: UnknownHostException: failed to retrieve SMB name, reason:" + e.getMessage());
m_addr = null;
}
if (m_addr != null && containsCtrlChars(m_addr.getHostName())) {
log.warn("IfSmbCollector: Retrieved SMB name for address " + InetAddressUtils.str(m_target) + " contains control chars: '" + m_addr.getHostName() + "', discarding.");
m_addr = null;
}
if (m_addr != null) {
if (log.isDebugEnabled())
log.debug("IfSmbCollector: SMB name of " + InetAddressUtils.str(m_target) + " is: " + m_addr.getHostName());
try {
// Attempt to resolve the Media Access Control Address
//
byte[] mac = m_addr.getMacAddress();
m_mac = toMacString(mac);
if (m_mac.equals(SAMBA_MAC)) {
m_isSamba = true;
m_mac = null;
}
} catch (UnknownHostException e) {
if (log.isDebugEnabled())
log.debug("IfSmbCollector: failed to get MAC for " + InetAddressUtils.str(m_target) + " due to address failure", e);
}
// Domain name
//
try {
// next collect all the NetBIOS names from the target system
//
m_allAddrs = NbtAddress.getAllByAddress(m_addr);
m_domain = SmbUtils.getAuthenticationDomainName(m_allAddrs, m_addr.getHostName());
if (log.isDebugEnabled())
log.debug("IfSmbCollector: domain name: '" + m_domain + "'");
} catch (UnknownHostException e) {
if (log.isDebugEnabled())
log.debug("IfSmbCollector: failed to get all the addresses for the interface " + InetAddressUtils.str(m_target), e);
}
// get the SMB authentication object
//
SmbAuth authentication = null;
if (m_domain != null)
authentication = CapsdConfigFactory.getInstance().getSmbAuth(m_domain);
if (authentication == null)
authentication = CapsdConfigFactory.getInstance().getSmbAuth(m_addr.getHostName());
if (log.isDebugEnabled())
log.debug("IfSmbCollector: SMB authenticator: " + authentication);
// If SMB is not set in capsd-configuration, authentication could be
// null. Then stop
// SMB collectio.
if (authentication == null)
return;
/*
* --------------------------------------------------------------------- /*
* Commenting the share enumeration code out for now...saw a
* scenario /* where a thread blocked indefinitely waiting for the
* jCIFS code to /* return. Will be doing additional testing to try
* and figure out /* what the problem is but for now will be
* commenting this code out. /* THe only thing we lose is
* potentially the OS of the remote box /
*/
// Try to enumerate all the shares on the
// remote target.
//
try {
String smbUrl = SmbUtils.getSmbURL(authentication, m_addr.getHostName());
if (log.isDebugEnabled())
log.debug("IfSmbCollector: smbUrl = " + smbUrl);
SmbFile sfile = new SmbFile(smbUrl);
if (log.isDebugEnabled())
log.debug("IfSmbCollector: got SmbFile object, retrieving share list...");
m_shares = sfile.list();
if (log.isDebugEnabled())
log.debug("IfSmbCollector: shares list retrieved...");
} catch (MalformedURLException e) {
if (log.isDebugEnabled())
log.debug("IfSmbCollector: failed to get SMB resource and OS name for host " + InetAddressUtils.str(m_target), e);
} catch (SmbAuthException e) {
if (log.isDebugEnabled())
log.debug("IfSmbCollector: unable to list SMB shares, authentication failed, reason: " + e.getMessage());
} catch (SmbException e) {
if (log.isDebugEnabled())
log.debug("IfSmbCollector: unable to list SMB shares, reason: " + e.getMessage());
}
/*---------------------------------------------------------------------*/
} // end if(addr != null)
} // end run
}