001: /*_############################################################################
002: _##
003: _## SNMP4J - UsmTimeTable.java
004: _##
005: _## Copyright (C) 2003-2008 Frank Fock and Jochen Katz (SNMP4J.org)
006: _##
007: _## Licensed under the Apache License, Version 2.0 (the "License");
008: _## you may not use this file except in compliance with the License.
009: _## You may obtain a copy of the License at
010: _##
011: _## http://www.apache.org/licenses/LICENSE-2.0
012: _##
013: _## Unless required by applicable law or agreed to in writing, software
014: _## distributed under the License is distributed on an "AS IS" BASIS,
015: _## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: _## See the License for the specific language governing permissions and
017: _## limitations under the License.
018: _##
019: _##########################################################################*/
020:
021: package org.snmp4j.security;
022:
023: import java.io.*;
024: import java.util.*;
025:
026: import org.snmp4j.log.*;
027: import org.snmp4j.mp.*;
028: import org.snmp4j.smi.*;
029:
030: /**
031: * The <code>UsmTimeTable</code> class is a singleton that stores USM user
032: * information as part of the Local Configuration Datastore (LCD).
033: *
034: * @author Frank Fock
035: * @version 1.2
036: */
037: public class UsmTimeTable implements Serializable {
038:
039: private static final long serialVersionUID = -1538321547688349797L;
040:
041: private static final LogAdapter logger = LogFactory
042: .getLogger(UsmTimeTable.class);
043:
044: private Hashtable table = new Hashtable(10);
045: private long lastLocalTimeChange = System.currentTimeMillis();
046: private UsmTimeEntry localTime;
047:
048: public UsmTimeTable(OctetString localEngineID, int engineBoots) {
049: setLocalTime(new UsmTimeEntry(localEngineID, engineBoots, 0));
050: }
051:
052: public void addEntry(final UsmTimeEntry entry) {
053: table.put(entry.getEngineID(), entry);
054: }
055:
056: public UsmTimeEntry getEntry(final OctetString engineID) {
057: return (UsmTimeEntry) table.get(engineID);
058: }
059:
060: public UsmTimeEntry getLocalTime() {
061: UsmTimeEntry entry = new UsmTimeEntry(localTime.getEngineID(),
062: localTime.getEngineBoots(), getEngineTime());
063: entry.setTimeDiff(entry.getTimeDiff() * (-1)
064: + localTime.getTimeDiff());
065: return entry;
066: }
067:
068: private void setLocalTime(UsmTimeEntry localTime) {
069: this .localTime = localTime;
070: lastLocalTimeChange = System.currentTimeMillis();
071: }
072:
073: /**
074: * Sets the number of engine boots.
075: * @param engineBoots
076: * the number of engine boots.
077: * @since 1.2
078: */
079: public void setEngineBoots(int engineBoots) {
080: this .localTime.setEngineBoots(engineBoots);
081: }
082:
083: /**
084: * Returns the number of seconds since the value of
085: * the engineBoots object last changed. When incrementing this object's value
086: * would cause it to exceed its maximum, engineBoots is incremented as if a
087: * re-initialization had occurred, and this
088: * object's value consequently reverts to zero.
089: *
090: * @return
091: * a positive integer value denoting the number of seconds since
092: * the engineBoots value has been changed.
093: * @since 1.2
094: */
095: public int getEngineTime() {
096: return (int) (((System.currentTimeMillis() - lastLocalTimeChange) / 1000) % 2147483648L);
097: }
098:
099: /**
100: * The number of times that the SNMP engine has (re-)initialized itself
101: * since snmpEngineID was last configured.
102: * @return
103: * the number of SNMP engine reboots.
104: */
105: public int getEngineBoots() {
106: return localTime.getEngineBoots();
107: }
108:
109: public synchronized UsmTimeEntry getTime(OctetString engineID) {
110: if (localTime.getEngineID().equals(engineID)) {
111: return getLocalTime();
112: }
113: UsmTimeEntry found = (UsmTimeEntry) table.get(engineID);
114: if (found == null) {
115: return null;
116: }
117: return new UsmTimeEntry(engineID, found.getEngineBoots(), found
118: .getTimeDiff()
119: + (int) (System.currentTimeMillis() / 1000));
120: }
121:
122: /**
123: * Removes the specified engine ID from the time cache.
124: * @param engineID
125: * the engine ID of the remote SNMP engine to remove from this time cache.
126: */
127: public void removeEntry(final OctetString engineID) {
128: table.remove(engineID);
129: }
130:
131: public synchronized int checkEngineID(OctetString engineID,
132: boolean discoveryAllowed) {
133: if (table.get(engineID) != null) {
134: return SnmpConstants.SNMPv3_USM_OK;
135: } else if (discoveryAllowed) {
136: addEntry(new UsmTimeEntry(engineID, 0, 0));
137: return SnmpConstants.SNMPv3_USM_OK;
138: }
139: return SnmpConstants.SNMPv3_USM_UNKNOWN_ENGINEID;
140: }
141:
142: public synchronized int checkTime(final UsmTimeEntry entry) {
143: int now = (int) (System.currentTimeMillis() / 1000);
144: if (localTime.getEngineID().equals(entry.getEngineID())) {
145: /* Entry found, we are authoritative */
146: if ((localTime.getEngineBoots() == 2147483647)
147: || (localTime.getEngineBoots() != entry
148: .getEngineBoots())
149: || (Math.abs(now + localTime.getTimeDiff()
150: - entry.getLatestReceivedTime()) > 150)) {
151: if (logger.isDebugEnabled()) {
152: logger
153: .debug("CheckTime: received message outside time window (authorative):"
154: + ((localTime.getEngineBoots() != entry
155: .getEngineBoots()) ? "engineBoots differ"
156: : ""
157: + (Math
158: .abs(now
159: + localTime
160: .getTimeDiff()
161: - entry
162: .getLatestReceivedTime()))
163: + " > 150"));
164: }
165: return SnmpConstants.SNMPv3_USM_NOT_IN_TIME_WINDOW;
166: } else {
167: if (logger.isDebugEnabled()) {
168: logger.debug("CheckTime: time ok (authorative)");
169: }
170: return SnmpConstants.SNMPv3_USM_OK;
171: }
172: } else {
173: UsmTimeEntry time = (UsmTimeEntry) table.get(entry
174: .getEngineID());
175: if (time == null) {
176: return SnmpConstants.SNMPv3_USM_UNKNOWN_ENGINEID;
177: }
178: if ((entry.getEngineBoots() < time.getEngineBoots())
179: || ((entry.getEngineBoots() == time
180: .getEngineBoots()) && (time.getTimeDiff()
181: + now > entry.getLatestReceivedTime() + 150))
182: || (time.getEngineBoots() == 2147483647)) {
183: if (logger.isDebugEnabled()) {
184: logger
185: .debug("CheckTime: received message outside time window (non authorative)");
186: }
187: return SnmpConstants.SNMPv3_USM_NOT_IN_TIME_WINDOW;
188: } else {
189: if ((entry.getEngineBoots() > time.getEngineBoots())
190: || ((entry.getEngineBoots() == time
191: .getEngineBoots()) && (entry
192: .getLatestReceivedTime() > time
193: .getLatestReceivedTime()))) {
194: /* time ok, update values */
195: time.setEngineBoots(entry.getEngineBoots());
196: time.setLatestReceivedTime(entry
197: .getLatestReceivedTime());
198: time.setTimeDiff(entry.getLatestReceivedTime()
199: - now);
200: }
201: if (logger.isDebugEnabled()) {
202: logger
203: .debug("CheckTime: time ok (non authorative)");
204: }
205: return SnmpConstants.SNMPv3_USM_OK;
206: }
207: }
208: }
209: }
|