/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2008-2009 Sun Microsystems, Inc.
* Portions Copyright 2013 ForgeRock AS.
*/
package org.opends.server.snmp;
import com.sun.management.comm.CommunicatorServer;
import java.io.File;
import org.opends.server.loggers.debug.DebugLogger;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.DebugLogLevel;
import static org.opends.server.loggers.debug.DebugLogger.*;
import com.sun.management.comm.SnmpV3AdaptorServer;
import com.sun.management.snmp.InetAddressAcl;
import com.sun.management.snmp.SnmpEngineParameters;
import com.sun.management.snmp.UserAcl;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.SortedSet;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.opends.messages.Message;
import org.opends.server.admin.std.server.SNMPConnectionHandlerCfg;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.ResultCode;
import org.opends.server.util.StaticUtils;
import org.opends.server.util.Validator;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
/**
* The SNMPClassLoaderProvider.
*/
public class SNMPClassLoaderProvider {
/**
* The debug log tracer for this class.
*/
private static final DebugTracer TRACER = DebugLogger.getTracer();
/**
* The current configuration state.
*/
private SNMPConnectionHandlerCfg currentConfig;
/**
* MBeanServer of OpenDS.
*/
private MBeanServer server;
/**
* MIB to manage.
*/
private DIRECTORY_SERVER_MIBImpl dsMib;
/**
* ObjectName of the MIB2605.
*/
private ObjectName mibObjName;
/**
* ObjectName of the SnmpAdaptor.
*/
private ObjectName snmpObjName;
/**
* SNMP Port Number for SNMP requests.
*/
private int snmpPort = 161;
/**
* Default SNMP trap port Number for SNMP Traps.
*/
private int snmpTrapPort = 162;
/**
* Registration of the SNMP MBeans.
*/
private boolean registeredSNMPMBeans = false;
/**
* The unique name for this connection handler.
*/
private String connectionHandlerName;
/**
* ObjectName of the UsmMIB.
*/
private ObjectName UsmObjName;
private SnmpV3AdaptorServer snmpAdaptor;
private String contextName;
private boolean sentTraps = true;
/**
* Default constructor.
*/
public SNMPClassLoaderProvider() {
// No implementation required
}
/**
* Initialization.
* @param configuration The configuration
* @throws java.lang.Exception if the SNMP connection handler
* could not be initialized
*/
public void initializeConnectionHandler(
SNMPConnectionHandlerCfg configuration) throws Exception {
// Keep the connection handler configuration
this.currentConfig = configuration;
// Get the Directory Server JMX MBeanServer
this.server = DirectoryServer.getJMXMBeanServer();
// Initialize the Connection Handler with the given configuration
this.initializeConnectionHandler();
}
/**
* Applies the configuration changes to this change listener.
*
* @param configuration
* The new configuration containing the changes.
* @return Returns information about the result of changing the
* configuration.
*/
public ConfigChangeResult applyConfigurationChange(
SNMPConnectionHandlerCfg configuration) {
try {
// Register/UnRegister SNMP MBeans
if ((this.registeredSNMPMBeans) &&
(!configuration.isRegisteredMbean())) {
this.unregisterSnmpMBeans();
this.registeredSNMPMBeans = configuration.isRegisteredMbean();
} else if ((!this.registeredSNMPMBeans) &&
(configuration.isRegisteredMbean())) {
this.unregisterSnmpMBeans();
this.registeredSNMPMBeans = configuration.isRegisteredMbean();
}
// PortNumber/Version
if ((this.snmpPort != configuration.getListenPort())) {
this.server.unregisterMBean(this.snmpObjName);
this.snmpAdaptor.stop();
this.snmpPort = configuration.getListenPort();
this.snmpAdaptor = this.getSnmpAdaptor(configuration);
// Creates and starts the SNMP Adaptor
this.snmpObjName = new ObjectName(
SNMPConnectionHandlerDefinitions.SNMP_DOMAIN +
"class=SnmpAdaptorServer,protocol=snmp," +
"port=" + snmpPort);
this.server.registerMBean(this.snmpAdaptor, this.snmpObjName);
this.snmpAdaptor.start();
// Send a coldStart SNMP Trap on the new trap port if required
if (this.snmpTrapPort != configuration.getTrapPort()) {
this.snmpTrapPort = configuration.getTrapPort();
this.snmpAdaptor.setTrapPort(snmpTrapPort);
this.snmpAdaptor.snmpV1Trap(0, 0, null);
}
}
} catch (Exception ex) {
if (debugEnabled()) {
TRACER.debugCaught(DebugLogLevel.ERROR, ex);
}
}
// Check if the security file
// If security file have changed, changeConfiguration not
// Supported.
return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
/**
* Gets the ObjectName of the crated USM MIB MBean.
* @return The UsmMIB ObjectName
*/
public ObjectName getUsmMIBName() {
return this.UsmObjName;
}
// private methods
private void initializeConnectionHandler() throws Exception {
// Compute the connectionHandler name
this.connectionHandlerName = "SNMP Connection Handler " +
this.currentConfig.getListenPort();
// Gets the configuration parameters
this.snmpPort = this.currentConfig.getListenPort();
this.snmpTrapPort = this.currentConfig.getTrapPort();
this.registeredSNMPMBeans = this.currentConfig.isRegisteredMbean();
this.contextName = this.currentConfig.getCommunity();
// Creates all the required objects for SNMP MIB 2605 Support
try {
// Creates and starts the SNMP Adaptor
this.snmpObjName = new ObjectName(
SNMPConnectionHandlerDefinitions.SNMP_DOMAIN +
"class=SnmpAdaptorServer,protocol=snmp,port=" + snmpPort);
// Create the SNMP Adaptor with the appropriated parameters
this.snmpAdaptor = this.getSnmpAdaptor(this.currentConfig);
if (this.snmpAdaptor == null) {
throw new Exception(
ERR_SNMP_CONNHANDLER_BAD_CONFIGURATION.get().toString());
}
// Create the Usm MIB to allow user management
if (this.registeredSNMPMBeans) {
this.UsmObjName = new ObjectName(
SNMPConnectionHandlerDefinitions.SNMP_DOMAIN +
"type=USM_MIB");
try {
this.snmpAdaptor.registerUsmMib(server, this.UsmObjName);
} catch (Exception ex) {
throw new Exception(
ERR_SNMP_CONNHANDLER_BAD_CONFIGURATION.get().toString());
}
}
this.snmpAdaptor.start();
// Test the snmpAdaptor State
while (this.snmpAdaptor.getState() == CommunicatorServer.STARTING) {
Thread.sleep(1000);
}
// Check if the snmpAdaptor is online
if (this.snmpAdaptor.getState() != CommunicatorServer.ONLINE) {
throw new Exception(
ERR_SNMP_CONNHANDLER_BAD_CONFIGURATION.get().toString());
}
// Check the trap destinations before trying to sent traps
this.sentTraps =
checkTrapsDestinations(
this.currentConfig.getTrapsDestination());
if (this.sentTraps == false) {
Message message =
ERR_SNMP_CONNHANDLER_NO_VALID_TRAP_DESTINATIONS.get();
logError(message);
} else {
// Send a coldStart SNMP Trap.
this.snmpAdaptor.setTrapPort(snmpTrapPort);
this.snmpAdaptor.snmpV1Trap(
null,
this.currentConfig.getTrapsCommunity(),
0,
0,
null);
}
// Create an instance of the customized MIB
this.mibObjName = new ObjectName(
SNMPConnectionHandlerDefinitions.SNMP_DOMAIN +
"class=DIRECTORY_SERVER_MIB");
this.dsMib = new DIRECTORY_SERVER_MIBImpl(
this.registeredSNMPMBeans, this.mibObjName);
this.dsMib.preRegister(this.server, this.mibObjName);
// Register the DS MIB into the defined context
this.dsMib.setSnmpAdaptor(snmpAdaptor, this.contextName);
this.server.registerMBean(this.snmpAdaptor, snmpObjName);
} catch (Exception ex) {
throw new Exception(
ERR_SNMP_CONNHANDLER_BAD_CONFIGURATION.get().toString());
}
}
/**
* Finalize.
*/
public void finalizeConnectionHandler() {
try {
if (this.sentTraps == true) {
// Send a trap when stop
this.snmpAdaptor.snmpV1Trap(
null,
this.currentConfig.getTrapsCommunity(),
0,
0,
null);
}
String[] names = this.snmpAdaptor.getMibs();
// Stop the SNMP Adaptor
this.snmpAdaptor.stop();
this.server.unregisterMBean(this.snmpObjName);
if (this.server.isRegistered(this.mibObjName)) {
this.server.unregisterMBean(this.mibObjName);
}
this.server.unregisterMBean(new ObjectName(
SNMPConnectionHandlerDefinitions.SNMP_DOMAIN +
"type=group,name=DsMib"));
// Unregister the created SNMP MBeans
if (this.registeredSNMPMBeans) {
this.unregisterSnmpMBeans();
this.server.unregisterMBean(this.UsmObjName);
}
} catch (Exception ex) {
if (debugEnabled()) {
TRACER.debugCaught(DebugLogLevel.ERROR, ex);
}
}
}
private void unregisterSnmpMBeans() {
for (ObjectName name : this.dsMib.getMib().getEntriesObjectNames()) {
try {
this.server.unregisterMBean(name);
} catch (Exception ex) {
}
}
}
private SnmpV3AdaptorServer getSnmpAdaptor(
SNMPConnectionHandlerCfg configuration) {
Validator.ensureNotNull(configuration);
SnmpV3AdaptorServer adaptor = null;
try {
// Set the USM security file
String usmConfigPath = configuration.getSecurityAgentFile();
File file = StaticUtils.getFileForPath(usmConfigPath);
if ((!file.isFile()) || (!file.exists())) {
return null;
}
System.setProperty("jdmk.security.file", file.getAbsolutePath());
// Create the Security Parameters for the engine
SnmpEngineParameters engineParameters = new SnmpEngineParameters();
// Set V3 Security parameters
engineParameters.activateEncryption();
// Create the UACL controller
UserAcl uacls = (UserAcl) new SNMPUserAcl(configuration);
engineParameters.setUserAcl(uacls);
// V1/V2 Security parameters
InetAddressAcl acls =
(InetAddressAcl) new SNMPInetAddressAcl(configuration);
adaptor = new SnmpV3AdaptorServer(engineParameters, null, acls,
configuration.getListenPort(), null);
// Enable the community to context translation for V1/V2 to V3
adaptor.enableCommunityStringAtContext();
return adaptor;
} catch (Exception ex) {
TRACER.debugError("Could not instanciate the SNMP Adaptor");
return null;
}
}
private boolean checkTrapsDestinations(SortedSet<String> destinations) {
// If the traps destinations is empty, the traps have to be sent
// to localhost
if ((destinations == null) || (destinations.isEmpty())) {
return true;
}
boolean found = false;
for (String dest : destinations) {
try {
InetAddress addr = InetAddress.getByName(dest);
found = true;
} catch (UnknownHostException ex) {
Message message = ERR_SNMP_CONNHANDLER_TRAPS_DESTINATION.get(
dest);
logError(message);
}
}
return found;
}
}