All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snmp4j.agent.mo.snmp.UsmMIB Maven / Gradle / Ivy

/*_############################################################################
  _##
  _##  SNMP4J-Agent - UsmMIB.java
  _##
  _##  Copyright (C) 2005-2009  Frank Fock (SNMP4J.org)
  _##
  _##  Licensed under the Apache License, Version 2.0 (the "License");
  _##  you may not use this file except in compliance with the License.
  _##  You may obtain a copy of the License at
  _##
  _##      http://www.apache.org/licenses/LICENSE-2.0
  _##
  _##  Unless required by applicable law or agreed to in writing, software
  _##  distributed under the License is distributed on an "AS IS" BASIS,
  _##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  _##  See the License for the specific language governing permissions and
  _##  limitations under the License.
  _##
  _##########################################################################*/


package org.snmp4j.agent.mo.snmp;

import org.snmp4j.agent.*;
import org.snmp4j.agent.mo.*;
import org.snmp4j.agent.request.*;
import org.snmp4j.event.*;
import org.snmp4j.mp.*;
import org.snmp4j.security.*;
import org.snmp4j.smi.*;
import org.snmp4j.PDU;
import org.snmp4j.agent.mo.DefaultMOTable.ChangeSet;
import org.snmp4j.agent.mo.snmp.UsmMIB.UsmTableRow;
import org.snmp4j.log.LogAdapter;
import org.snmp4j.log.LogFactory;
import java.util.Vector;

/**
 * The UsmMIB implements the SNMP-USER-BASED-SM-MIB defined in
 * RFC 3414. The MIB implementation is backed by a {@link USM} instance.
 * The configuration of the user based security model can be changed
 * programatically by changing the underlying {@link USM} or via SNMP but at
 * least one user must be created programatically in order to allow any access
 * to the agent via SNMP.
 * 

* When modifying the USM after having created this MIB, you will have to * register this object as {@link UsmUserListener} to the USM. *

* By using SNMP, a new users can only be created by cloning it from an existing * user with the same or higher security level. * * @author Frank Fock * @version 1.2 */ public class UsmMIB implements MOGroup, CounterListener, MOValueValidationListener, MOTableRowListener, UsmUserListener { private static final LogAdapter logger = LogFactory.getLogger(UsmMIB.class); public static final OID noAuthProtocol = new OID(new int[] {1,3,6,1,6,3,10,1,1,1}); public static final OID noPrivProtocol = new OID(new int[] {1,3,6,1,6,3,10,1,2,1}); public static final OID usmUserSpinLockOID = new OID(new int[] { 1,3,6,1,6,3,15,1,2,1,0 }); public static final OID usmUserEntryOID = new OID(new int[] { 1,3,6,1,6,3,15,1,2,2,1 }); public static final int colUsmUserSecurityName = 0; public static final int colUsmUserCloneFrom = 1; public static final int colUsmUserAuthProtocol = 2; public static final int colUsmUserAuthKeyChange = 3; public static final int colUsmUserOwnAuthKeyChange = 4; public static final int colUsmUserPrivProtocol = 5; public static final int colUsmUserPrivKeyChange = 6; public static final int colUsmUserOwnPrivKeyChange = 7; public static final int colUsmUserPublic = 8; public static final int colUsmUserStorageType = 9; public static final int colUsmUserStatus = 10; // hidden virtual columns public static final int colUsmUserAuthPassword = 11; public static final int colUsmUserPrivPassword = 12; public static final int colUsmUserLocalizationEngineID = 13; public static final int colUsmUserAuthKey = 14; public static final int colUsmUserPrivKey = 15; private static final int[][] keyChangeColumns = { {colUsmUserAuthKeyChange, colUsmUserOwnAuthKeyChange}, {colUsmUserPrivKeyChange, colUsmUserOwnPrivKeyChange} }; private USM usm; private SecurityProtocols securityProtocols; private static final OID usmStatsPrefix = new OID(SnmpConstants.usmStatsUnsupportedSecLevels.getValue(), 0, SnmpConstants.usmStatsUnsupportedSecLevels.size()-2); private static final OID[] usmStatOIDs = new OID[] { SnmpConstants.usmStatsUnsupportedSecLevels, SnmpConstants.usmStatsNotInTimeWindows, SnmpConstants.usmStatsUnknownUserNames, SnmpConstants.usmStatsUnknownEngineIDs, SnmpConstants.usmStatsWrongDigests, SnmpConstants.usmStatsDecryptionErrors }; private MOScalar[] usmStats; private TestAndIncr usmUserSpinLock; private DefaultMOTable usmUserEntry; private UsmTableModel usmUserTableModel; private volatile boolean usmEventProcessing; /** * Creates a USM MIB implementation connected to the supplied USM. The MIB * contents will reflect any changes to the USM after completion of this * constructor if you register this object as {@link UsmUserListener} to the * USM! * @param usm * a User-based Security Model. * @param securityProtocols * the supported SecurityProtocols. */ public UsmMIB(USM usm, SecurityProtocols securityProtocols) { this.usm = usm; this.securityProtocols = securityProtocols; usm.getCounterSupport().addCounterListener(this); createUsmStats(); createUsmUser(); } private void createUsmUser() { usmUserSpinLock = new TestAndIncr(usmUserSpinLockOID); MOTableSubIndex[] usmUserSubIndexes = new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_OCTET_STRING, 5, 32), new MOTableSubIndex(SMIConstants.SYNTAX_OCTET_STRING, 1, 32) }; MOColumn[] usmUserColumns = new MOColumn[] { new SnmpAdminString(colUsmUserSecurityName + 3, MOAccessImpl.ACCESS_READ_ONLY, null, false), new UsmRowPointer(colUsmUserCloneFrom + 3, MOAccessImpl.ACCESS_READ_CREATE, null, true), new AutonomousType(colUsmUserAuthProtocol + 3, MOAccessImpl.ACCESS_READ_CREATE, noAuthProtocol, true), new UsmKeyChange(colUsmUserAuthKeyChange + 3, MOAccessImpl.ACCESS_READ_CREATE, UsmKeyChange.AUTH_KEY_CHANGE), new UsmOwnKeyChange(colUsmUserOwnAuthKeyChange + 3, MOAccessImpl.ACCESS_READ_CREATE, UsmKeyChange.AUTH_KEY_CHANGE), new AutonomousType(colUsmUserPrivProtocol + 3, MOAccessImpl.ACCESS_READ_CREATE, noPrivProtocol, true), new UsmKeyChange(colUsmUserPrivKeyChange + 3, MOAccessImpl.ACCESS_READ_CREATE, UsmKeyChange.PRIV_KEY_CHANGE), new UsmOwnKeyChange(colUsmUserOwnPrivKeyChange + 3, MOAccessImpl.ACCESS_READ_CREATE, UsmKeyChange.PRIV_KEY_CHANGE), new SnmpAdminString(colUsmUserPublic + 3, MOAccessImpl.ACCESS_READ_CREATE, new OctetString(), true, 0, 32), new StorageType(colUsmUserStorageType + 3, MOAccessImpl.ACCESS_READ_CREATE, new Integer32(StorageType.nonVolatile), true), new RowStatus(colUsmUserStatus + 3, MOAccessImpl.ACCESS_READ_CREATE) }; MOTableIndex usmUserIndex = new MOTableIndex(usmUserSubIndexes, false); usmUserTableModel = new UsmTableModel(usmUserIndex); usmUserEntry = new DefaultMOTable(usmUserEntryOID, usmUserIndex, usmUserColumns, usmUserTableModel) { protected void fireRowChanged(MOTableRowEvent event) { if (super.moTableRowListeners != null) { Vector listeners = super.moTableRowListeners; int count = listeners.size(); for (int i = 0; i < count; i++) { MOTableRowListener l = (MOTableRowListener) listeners.get(i); if ((!usmEventProcessing) || (!(l instanceof UsmMIB))) { l.rowChanged(event); } } } } }; ((AutonomousType) usmUserColumns[colUsmUserAuthProtocol]).addMOValueValidationListener(this); ((AutonomousType) usmUserColumns[colUsmUserPrivProtocol]).addMOValueValidationListener(this); ((UsmRowPointer) usmUserColumns[colUsmUserCloneFrom]).setTargetTable(usmUserEntry); usmUserEntry.addMOTableRowListener(this); } private void createUsmStats() { usmStats = new MOScalar[usmStatOIDs.length]; for (int i=0; i usmStatsPrefix.size())) { Counter32 current = (Counter32) usmStats[event.getOid().get(usmStatsPrefix.size())-1].getValue(); current.increment(); event.setCurrentValue((Counter32)current.clone()); } } public void validate(MOValueValidationEvent validationEvent) { if (validationEvent.getSource() instanceof MOColumn) { MOColumn col = (MOColumn) validationEvent.getSource(); switch (col.getColumnID()-4) { case colUsmUserAuthProtocol: { OID value = (OID)validationEvent.getNewValue(); if (!noAuthProtocol.equals(value)) { AuthenticationProtocol authProtocol = SecurityProtocols.getInstance(). getAuthenticationProtocol((OID) validationEvent.getNewValue()); if (authProtocol == null) { validationEvent.setValidationStatus(SnmpConstants. SNMP_ERROR_WRONG_VALUE); } } break; } case colUsmUserPrivProtocol: { OID value = (OID)validationEvent.getNewValue(); if (!noPrivProtocol.equals(value)) { PrivacyProtocol privProtocol = SecurityProtocols.getInstance().getPrivacyProtocol(value); if (privProtocol == null) { validationEvent.setValidationStatus(SnmpConstants. SNMP_ERROR_WRONG_VALUE); } } break; } } } } private Variable[] getValuesFromUsmUser(UsmUserEntry user) { Variable[] row = new Variable[usmUserEntry.getColumnCount()+5]; int n = 0; row[n++] = user.getUsmUser().getSecurityName(); row[n++] = null; row[n++] = user.getUsmUser().getAuthenticationProtocol(); row[n++] = null; row[n++] = null; row[n++] = user.getUsmUser().getPrivacyProtocol(); row[n++] = null; row[n++] = null; row[n++] = new OctetString(); row[n++] = new Integer32(StorageType.nonVolatile); row[n++] = new Integer32(RowStatus.active); row[n++] = user.getUsmUser().getAuthenticationPassphrase(); row[n++] = user.getUsmUser().getPrivacyPassphrase(); row[n++] = user.getUsmUser().getLocalizationEngineID(); row[n++] = (user.getAuthenticationKey() == null) ? null : new OctetString(user.getAuthenticationKey()); row[n++] = (user.getPrivacyKey() == null) ? null : new OctetString(user.getPrivacyKey()); return row; } private OID createIndex(OctetString engineID, OctetString userName) { if (engineID.length() == 0) { engineID = usm.getLocalEngineID(); } OID index = engineID.toSubIndex(false); index.append(userName.toSubIndex(false)); return index; } public synchronized void usmUserChange(UsmUserEvent event) { usmEventProcessing = true; switch (event.getType()) { case UsmUserEvent.USER_ADDED: { Variable[] values = getValuesFromUsmUser(event.getUser()); OID index = createIndex(event.getUser().getEngineID(), event.getUser().getUserName()); MOMutableRow2PC row = (MOMutableRow2PC) usmUserEntry.createRow(index, values); usmUserEntry.addRow(row); break; } case UsmUserEvent.USER_REMOVED: { if (event.getUser() == null) { usmUserTableModel.clear(); } else { OID index = createIndex(event.getUser().getEngineID(), event.getUser().getUserName()); usmUserEntry.removeRow(index); } } } usmEventProcessing = false; } private static byte[] getKey(UsmUserEntry entry, int authVsPriv) { return (authVsPriv == 0) ? entry.getAuthenticationKey() : entry.getPrivacyKey(); } public class UsmTableModel extends DefaultMOMutableTableModel { private MOTableIndex indexDef; public UsmTableModel(MOTableIndex indexDef) { super(); this.indexDef = indexDef; } public MOTableRow createRow(OID index, Variable[] values) { if (values.length < colUsmUserPrivKey + 1) { Variable[] h = new Variable[colUsmUserPrivKey + 1]; System.arraycopy(values, 0, h, 0, values.length); values = h; } return new UsmTableRow(this, index, values); } public MOTableIndex getIndexDef() { return indexDef; } } private static boolean isKeyChanged(MOTableRow changeSet, int keyChangeColumn) { OctetString value = (OctetString) changeSet.getValue(keyChangeColumn); if ((value != null) && (value.length() > 0)) { return true; } return false; } private static boolean isKeyChanged(MOTableRow changeSet) { return ((isKeyChanged(changeSet, colUsmUserOwnAuthKeyChange)) || (isKeyChanged(changeSet, colUsmUserAuthKeyChange)) || (isKeyChanged(changeSet, colUsmUserOwnPrivKeyChange)) || (isKeyChanged(changeSet, colUsmUserPrivKeyChange))); } public class UsmTableRow extends DefaultMOMutableRow2PC { private UsmTableModel tableModel; private boolean cloned = false; public UsmTableRow(UsmTableModel model, OID index, Variable[] values) { super(index, values); this.tableModel = model; } public void setCloned(boolean cloned) { this.cloned = cloned; } public boolean isCloned() { return cloned; } public MOTableIndex getIndexDef() { return tableModel.getIndexDef(); } public AuthenticationProtocol getAuthProtocol(MOTableRow changeSet) { OID authOID = getAuthProtocolOID(changeSet); AuthenticationProtocol a = securityProtocols.getAuthenticationProtocol(authOID); return a; } public PrivacyProtocol getPrivProtocol(MOTableRow changeSet) { OID privOID = getPrivProtocolOID(changeSet); PrivacyProtocol p = securityProtocols.getPrivacyProtocol(privOID); return p; } /** * Gets the OID of the privacy protocol defined by the given * change set. If the change set defines {@link #noPrivProtocol} * null is returned. * @param preparedChanges * a TableRow instance with UsmTableRow values. * @return * a privacy protocol OID or null if no * privacy protocol is defined by changeSet. */ public OID getPrivProtocolOID(MOTableRow preparedChanges) { OID privID = null; if (preparedChanges.getValue(colUsmUserCloneFrom) == null) { privID = (OID) preparedChanges.getValue(colUsmUserPrivProtocol); } if (privID == null) { privID = (OID) getValue(colUsmUserPrivProtocol); } if (noPrivProtocol.equals(privID)) { privID = null; } return privID; } public void prepare(SubRequest subRequest, MOTableRow preparedChanges, int column) { switch (column) { case colUsmUserAuthProtocol: { OID authProtocol = (OID) subRequest.getVariableBinding().getVariable(); if (!authProtocol.equals(noAuthProtocol)) { subRequest.getStatus().setErrorStatus(PDU.inconsistentValue); } else { OID privProtocol = null; Variable privProtocolVariable = preparedChanges.getValue(colUsmUserPrivProtocol); if (privProtocolVariable instanceof OID) { privProtocol = (OID) privProtocolVariable; } else if (privProtocolVariable == null) { privProtocol = (OID) getValue(colUsmUserPrivProtocol); } if ((privProtocol == null) || (!privProtocol.equals(noPrivProtocol))) { subRequest.getStatus().setErrorStatus(PDU.inconsistentValue); } } break; } case colUsmUserPrivProtocol: { OID privProtocol = (OID)subRequest.getVariableBinding().getVariable(); if (!privProtocol.equals(noPrivProtocol)) { subRequest.getStatus().setErrorStatus(PDU.inconsistentValue); } break; } } } private OID getCloneFromIndex(MOTableRow changeSet) { OID cloneFrom = (OID) changeSet.getValue(colUsmUserCloneFrom); if (cloneFrom == null) { cloneFrom = (OID) getValue(colUsmUserCloneFrom); } if ((cloneFrom == null) || (cloneFrom.size() <= usmUserEntryOID.size())) { return null; } return new OID(cloneFrom.getValue(), usmUserEntryOID.size()+1, cloneFrom.size() - (usmUserEntryOID.size()+1)); } public synchronized void commitRow(SubRequest subRequest, MOTableRow changeSet) { if (subRequest.hasError()) { return; } Variable[] indexValues = getIndexDef().getIndexValues(getIndex()); OctetString engineID = (OctetString) indexValues[0]; OctetString userName = (OctetString) indexValues[1]; UsmUserEntry oldUserEntry; OID cloneFromUserIndex = getCloneFromIndex(changeSet); if (cloneFromUserIndex != null) { Variable[] cloneFromIndexValues = getIndexDef().getIndexValues(cloneFromUserIndex); OctetString cloneFromEngineID = (OctetString) cloneFromIndexValues[0]; OctetString cloneFromUserName = (OctetString) cloneFromIndexValues[1]; oldUserEntry = usm.getUser(cloneFromEngineID, cloneFromUserName); // assign protocols if (oldUserEntry != null) { setValue(colUsmUserAuthProtocol, oldUserEntry.getUsmUser().getAuthenticationProtocol()); setValue(colUsmUserPrivProtocol, oldUserEntry.getUsmUser().getPrivacyProtocol()); } } else { oldUserEntry = usm.getUser(engineID, userName); } Integer32 newStatus = (Integer32)changeSet.getValue(colUsmUserStatus); if (((newStatus != null) && ((newStatus.getValue() == RowStatus.active) || (newStatus.getValue() == RowStatus.createAndGo))) || ((getValue(colUsmUserStatus) != null) && (((Integer32)getValue(colUsmUserStatus)).getValue() == RowStatus.active) && (isKeyChanged(changeSet)))) { if (cloneFromUserIndex != null) { // save undo value setUserObject(oldUserEntry); } if (oldUserEntry == null) { subRequest.getStatus().setErrorStatus(PDU.commitFailed); return; } OctetString[] newKeys = new OctetString[2]; OctetString[] oldKeys = new OctetString[2]; AuthenticationProtocol a = getAuthProtocol(changeSet); if (a != null) { for (int p=0; p<2; p++) { byte[] k = getKey(oldUserEntry, p); oldKeys[p] = null; if (k != null) { oldKeys[p] = new OctetString(k); for (int i = 0; i < keyChangeColumns[p].length; i++) { OctetString keyChange = (OctetString)getValue(keyChangeColumns[p][i]); if ((keyChange != null) && (keyChange.length() > 0)) { int keyLength = a.getDigestLength(); OctetString doKey = oldKeys[p]; if (p == 1) { // privacy protocol key change PrivacyProtocol privProtocol = getPrivProtocol(changeSet); keyLength = privProtocol.getMaxKeyLength(); } newKeys[p] = KeyChange.changeKey(a, doKey, keyChange, keyLength); break; // only one key change per protocol } } } } } UsmUserEntry newEntry = new UsmUserEntry(engineID.getValue(), userName, getAuthProtocolOID(changeSet), (newKeys[0] == null) ? ((oldKeys[0] == null) ? null : oldKeys[0].getValue()) : newKeys[0].getValue(), getPrivProtocolOID(changeSet), (newKeys[1] == null) ? ((oldKeys[1] == null) ? null : oldKeys[1].getValue()) : newKeys[1].getValue()); usm.updateUser(newEntry); setValue(colUsmUserCloneFrom, null); setValue(colUsmUserAuthKeyChange, null); setValue(colUsmUserOwnAuthKeyChange, null); setValue(colUsmUserPrivKeyChange, null); setValue(colUsmUserOwnPrivKeyChange, null); } if (newStatus != null) { switch (newStatus.getValue()) { case RowStatus.createAndWait: case RowStatus.createAndGo: { setValue(colUsmUserSecurityName, userName); break; } } } } /** * Gets the OID of the authentication protocol defined by the given * change set. If the change set defines {@link #noAuthProtocol} * null is returned. * @param changeSet * a TableRow instance with UsmTableRow values. * @return * an authentication protocol OID or null if no * authentication protocol is defined by changeSet. */ public OID getAuthProtocolOID(MOTableRow changeSet) { OID authID = null; if (changeSet.getValue(colUsmUserCloneFrom) == null) { authID = (OID) changeSet.getValue(colUsmUserAuthProtocol); } if (authID == null) { authID = (OID) getValue(colUsmUserAuthProtocol); } if (noAuthProtocol.equals(authID)) { authID = null; } return authID; } public void cleanupRow(SubRequest subRequest, ChangeSet changeSet) { setUserObject(null); } public void undoRow(SubRequest subRequest, ChangeSet changeSet) { if (getUserObject() != null) { usm.updateUser((UsmUserEntry)getUserObject()); } } public Variable getValue(int column) { if (column > colUsmUserStatus) { UsmUserEntry userEntry = getUserEntry(); if (userEntry != null) { switch (column) { case colUsmUserAuthPassword: setValue(column, userEntry.getUsmUser().getAuthenticationPassphrase()); break; case colUsmUserPrivPassword: setValue(column, userEntry.getUsmUser().getPrivacyPassphrase()); break; case colUsmUserLocalizationEngineID: setValue(column, (userEntry.getUsmUser().isLocalized()) ? userEntry.getUsmUser().getLocalizationEngineID() : null); break; case colUsmUserAuthKey: { byte[] key = userEntry.getAuthenticationKey(); setValue(column, (key == null) ? null : new OctetString(key)); break; } case colUsmUserPrivKey: { byte[] key = userEntry.getPrivacyKey(); setValue(column, (key == null) ? null : new OctetString(key)); break; } } } } return super.getValue(column); } public boolean containsHiddenValues() { for (int i=colUsmUserStatus+1; i colUsmUserLocalizationEngineID) && (row.getValue(colUsmUserAuthPassword) != null)) { UsmUser user = new UsmUser(idxValues[1], row.getAuthProtocolOID(row), (OctetString)row.getValue(colUsmUserAuthPassword), row.getPrivProtocolOID(row), (OctetString)row.getValue(colUsmUserPrivPassword), (OctetString)row.getValue(colUsmUserLocalizationEngineID)); usm.addUser(idxValues[1], idxValues[0], user); } else if (row.size() > colUsmUserPrivKey) { OctetString authKey = (OctetString)row.getValue(colUsmUserAuthKey); OctetString privKey = (OctetString)row.getValue(colUsmUserPrivKey); usm.addLocalizedUser(idxValues[0].getValue(), idxValues[1], row.getAuthProtocolOID(row), (authKey == null) ? null : authKey.getValue(), row.getPrivProtocolOID(row), (privKey == null) ? null : privKey.getValue()); } else { logger.warn("Cannot add user '"+idxValues[1]+ "' to the USM from USM-MIB because key "+ "information is missing"); } } } else if (event.getType() == MOTableRowEvent.DELETE) { UsmUserEntry entry = row.getUserEntry(); if (entry != null) { usm.removeUser(entry.getEngineID(), entry.getUserName()); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy