/*
* 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-2010], 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.snmp;
import java.io.*; // stub
import org.snmp4j.PDU;
import org.snmp4j.ScopedPDU;
import org.snmp4j.UserTarget;
import org.snmp4j.log.Log4jLogFactory;
import org.snmp4j.log.LogFactory;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivAES128;
import org.snmp4j.security.PrivAES192;
import org.snmp4j.security.PrivAES256;
import org.snmp4j.security.PrivDES;
import org.snmp4j.security.Priv3DES;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
/**
* Implements the SNMPSession interface for SNMPv3 sessions by extending the
* SNMPSession_v2c implementation. SNMPv3 is only different from v1 or v2c in
* the way that a session is initialized.
*/
class SNMPSession_v3
extends SNMPSession_v2c
{
static {
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);
if ("true".equals(System.getProperty("snmpLogging"))) {
LogFactory.setLogFactory(new Log4jLogFactory());
}
}
SNMPSession_v3() {
this.version = SnmpConstants.version3;
}
protected PDU newPDU() {
ScopedPDU pdu = new ScopedPDU();
return pdu;
}
private OctetString createOctetString(String val) {
if (val == null || val.length() == 0) {
return null;
}
return new OctetString(val);
}
private OID getPrivProtocol(String defVal) throws SNMPException {
String val = System.getProperty("snmpPrivacyType", defVal);
if (val == null
|| val.equalsIgnoreCase("none")
|| val.length() == 0) {
return null;
}
if (val.equals("DES")) {
return PrivDES.ID;
} else if (val.equals("3DES")) {
return Priv3DES.ID;
} else if (val.equals("AES128") || val.equals("AES-128") || val.equals("AES")) {
return PrivAES128.ID;
} else if (val.equals("AES192") || val.equals("AES-192")) {
return PrivAES192.ID;
} else if (val.equals("AES256") || val.equals("AES-256")) {
return PrivAES256.ID;
} else {
throw new SNMPException("Privacy protocol " + val + " not supported");
}
}
private OID getAuthProtocol(String authMethod) {
if (authMethod == null
|| authMethod.equalsIgnoreCase("none")
|| authMethod.length() == 0) {
return null;
} else if (authMethod.equalsIgnoreCase("md5")) {
return AuthMD5.ID;
} else if (authMethod.equalsIgnoreCase("sha")) {
return AuthSHA.ID;
} else {
throw new IllegalArgumentException("unknown authentication protocol: " + authMethod);
}
}
void init(String host, String port, String transport, String user,
String authType, String authPassword,
String privType, String privPassword, String retries, String timeout)
throws SNMPException
{
OID authProtocol = getAuthProtocol(authType);
OID privProtocol = getPrivProtocol(privType);
OctetString securityName = createOctetString(user);
OctetString authPassphrase = createOctetString(authPassword);
OctetString privPassphrase = createOctetString(privPassword);
UserTarget target = new UserTarget();
target.setSecurityName(securityName);
if (authPassphrase != null) {
if (privPassphrase != null) {
target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
} else {
target.setSecurityLevel(SecurityLevel.AUTH_NOPRIV);
}
} else {
target.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
}
this.target = target;
initSession(host, port, transport, retries, timeout);
// Need this check for unidirectional agents
if (this.target.getAddress() == null) {
throw new SNMPException("Invalid SNMP address "
+ transport + ":" + host + "/" + port);
}
// Need to add user by engineID.
byte[] engineID = this.session.discoverAuthoritativeEngineID(
this.target.getAddress(),
this.target.getTimeout());
UsmUser usmUser = new UsmUser(securityName,
authProtocol, authPassphrase,
privProtocol, privPassphrase);
USM usm = this.session.getUSM();
// Need to call addUser each time, even if user name exists,
// in case the user credentials change.
usm.addUser(securityName,
(engineID == null) ? null : new OctetString(engineID),
usmUser);
}
/**
* Remote SNMPv3 engines will send back a Report PDU
* if there is a problem with the request.
*/
protected void validateResponsePDU(String name, PDU response)
throws SNMPException {
super.validateResponsePDU(name, response);
if (response.getType() == PDU.REPORT) {
processReport(response);
}
}
private void processReport(PDU report)
throws SNMPException {
if (report.size() < 1) {
throw new SNMPException("REPORT PDU does not contain a variable binding.");
}
VariableBinding vb = report.get(0);
OID oid = vb.getOid();
if (SnmpConstants.usmStatsUnsupportedSecLevels.equals(oid)) {
throw new SNMPException("Unsupported Security Level.");
} else if (SnmpConstants.usmStatsNotInTimeWindows.equals(oid)) {
throw new SNMPException("Message not within time window.");
} else if (SnmpConstants.usmStatsUnknownUserNames.equals(oid)) {
throw new SNMPException("Unknown user name.");
} else if (SnmpConstants.usmStatsUnknownEngineIDs.equals(oid)) {
throw new SNMPException("Unknown engine id.");
} else if (SnmpConstants.usmStatsWrongDigests.equals(oid)) {
throw new SNMPException("Invalid authentication digest.");
} else if (SnmpConstants.usmStatsDecryptionErrors.equals(oid)) {
throw new SNMPException("Decryption error.");
} else if (SnmpConstants.snmpUnknownSecurityModels.equals(oid)) {
throw new SNMPException("Unknown security model.");
} else if (SnmpConstants.snmpInvalidMsgs.equals(oid)) {
throw new SNMPException("Invalid message.");
} else if (SnmpConstants.snmpUnknownPDUHandlers.equals(oid)) {
throw new SNMPException("Unknown PDU handler.");
} else if (SnmpConstants.snmpUnavailableContexts.equals(oid)) {
throw new SNMPException("Unavailable context.");
} else if (SnmpConstants.snmpUnknownContexts.equals(oid)) {
throw new SNMPException("Unknown context.");
} else {
throw new SNMPException("REPORT PDU contains unknown OID (" + oid + ").");
}
}
}