KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > snmp4j > agent > mo > snmp > UsmMIB


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

20
21
22 package org.snmp4j.agent.mo.snmp;
23
24 import org.snmp4j.agent.*;
25 import org.snmp4j.agent.mo.*;
26 import org.snmp4j.agent.request.*;
27 import org.snmp4j.event.*;
28 import org.snmp4j.mp.*;
29 import org.snmp4j.security.*;
30 import org.snmp4j.smi.*;
31 import org.snmp4j.PDU;
32 import org.snmp4j.agent.mo.DefaultMOTable.ChangeSet;
33
34 /**
35  * The <code>UsmMIB</code> implements the SNMP-USER-BASED-SM-MIB defined in
36  * RFC 3414. The MIB implementation is backed by a {@link USM} instance.
37  * The configuration of the user based security model can be changed
38  * programatically by changing the underlying {@link USM} or via SNMP but at
39  * least one user must be created programatically in order to allow any access
40  * to the agent via SNMP.
41  * <p>
42  * When modifying the USM after having created this MIB, you will have to
43  * register this object as {@link UsmUserListener} to the USM.
44  * <p>
45  * By using SNMP, a new users can only be created by cloning it from an existing
46  * user with the same or higher security level.
47  *
48  * @author Frank Fock
49  * @version 1.0
50  */

51 public class UsmMIB
52     implements
53     MOGroup,
54     CounterListener,
55     MOValueValidationListener,
56     UsmUserListener {
57
58   private static final OID noAuthProtocol =
59       new OID(new int[] {1,3,6,1,6,3,10,1,1,1});
60   private static final OID noPrivProtocol =
61       new OID(new int[] {1,3,6,1,6,3,10,1,2,1});
62
63   private static final OID usmUserSpinLockOID =
64       new OID(new int[] { 1,3,6,1,6,3,15,1,2,1,0 });
65   private static final OID usmUserEntryOID =
66       new OID(new int[] { 1,3,6,1,6,3,15,1,2,2,1 });
67
68
69   static final int colUsmUserSecurityName = 0;
70   static final int colUsmUserCloneFrom = 1;
71   static final int colUsmUserAuthProtocol = 2;
72   static final int colUsmUserAuthKeyChange = 3;
73   static final int colUsmUserOwnAuthKeyChange = 4;
74   static final int colUsmUserPrivProtocol = 5;
75   static final int colUsmUserPrivKeyChange = 6;
76   static final int colUsmUserOwnPrivKeyChange = 7;
77   static final int colUsmUserPublic = 8;
78   static final int colUsmUserStorageType = 9;
79   static final int colUsmUserStatus = 10;
80
81   private static final int[][] keyChangeColumns =
82       { {colUsmUserAuthKeyChange, colUsmUserOwnAuthKeyChange},
83         {colUsmUserPrivKeyChange, colUsmUserOwnPrivKeyChange}
84   };
85   private USM usm;
86   private SecurityProtocols securityProtocols;
87
88   private static final OID usmStatsPrefix =
89       new OID(SnmpConstants.usmStatsUnsupportedSecLevels.getValue(), 0,
90               SnmpConstants.usmStatsUnsupportedSecLevels.size()-2);
91
92   private static final OID[] usmStatOIDs = new OID[] {
93       SnmpConstants.usmStatsUnsupportedSecLevels,
94       SnmpConstants.usmStatsNotInTimeWindows,
95       SnmpConstants.usmStatsUnknownUserNames,
96       SnmpConstants.usmStatsUnknownEngineIDs,
97       SnmpConstants.usmStatsWrongDigests,
98       SnmpConstants.usmStatsDecryptionErrors
99   };
100
101   private MOScalar[] usmStats;
102   private TestAndIncr usmUserSpinLock;
103   private DefaultMOTable usmUserEntry;
104   private UsmTableModel usmUserTableModel;
105
106   /**
107    * Creates a USM MIB implementation connected to the supplied USM. The MIB
108    * contents will reflect any changes to the USM after completion of this
109    * constructor if you register this object as {@link UsmUserListener} to the
110    * USM!
111    * @param usm
112    * a User-based Security Model.
113    * @param securityProtocols
114    * the supported <code>SecurityProtocols</code>.
115    */

116   public UsmMIB(USM usm, SecurityProtocols securityProtocols) {
117     this.usm = usm;
118     this.securityProtocols = securityProtocols;
119     usm.getCounterSupport().addCounterListener(this);
120     createUsmStats();
121     createUsmUser();
122   }
123
124   private void createUsmUser() {
125     usmUserSpinLock = new TestAndIncr(usmUserSpinLockOID);
126     MOTableSubIndex[] usmUserSubIndexes = new MOTableSubIndex[] {
127         new MOTableSubIndex(SMIConstants.SYNTAX_OCTET_STRING, 5, 32),
128         new MOTableSubIndex(SMIConstants.SYNTAX_OCTET_STRING, 1, 32)
129     };
130     MOColumn[] usmUserColumns = new MOColumn[] {
131         new SnmpAdminString(colUsmUserSecurityName + 3,
132                             MOAccessImpl.ACCESS_READ_ONLY,
133                             null, false),
134         new UsmRowPointer(colUsmUserCloneFrom + 3,
135                           MOAccessImpl.ACCESS_READ_CREATE,
136                           null, true),
137         new AutonomousType(colUsmUserAuthProtocol + 3,
138                            MOAccessImpl.ACCESS_READ_CREATE,
139                            noAuthProtocol, true),
140         new UsmKeyChange(colUsmUserAuthKeyChange + 3,
141                          MOAccessImpl.ACCESS_READ_CREATE,
142                          UsmKeyChange.AUTH_KEY_CHANGE),
143         new UsmOwnKeyChange(colUsmUserOwnAuthKeyChange + 3,
144                             MOAccessImpl.ACCESS_READ_CREATE,
145                             UsmKeyChange.AUTH_KEY_CHANGE),
146         new AutonomousType(colUsmUserPrivProtocol + 3,
147                            MOAccessImpl.ACCESS_READ_CREATE,
148                            noPrivProtocol, true),
149         new UsmKeyChange(colUsmUserPrivKeyChange + 3,
150                          MOAccessImpl.ACCESS_READ_CREATE,
151                          UsmKeyChange.PRIV_KEY_CHANGE),
152         new UsmOwnKeyChange(colUsmUserOwnPrivKeyChange + 3,
153                             MOAccessImpl.ACCESS_READ_CREATE,
154                             UsmKeyChange.PRIV_KEY_CHANGE),
155         new SnmpAdminString(colUsmUserPublic + 3,
156                             MOAccessImpl.ACCESS_READ_CREATE,
157                             new OctetString(), true, 0, 32),
158         new StorageType(colUsmUserStorageType + 3,
159                         MOAccessImpl.ACCESS_READ_CREATE,
160                         new Integer32(StorageType.nonVolatile), true),
161         new RowStatus(colUsmUserStatus + 3, MOAccessImpl.ACCESS_READ_CREATE)
162     };
163     MOTableIndex usmUserIndex = new MOTableIndex(usmUserSubIndexes, false);
164     usmUserTableModel = new UsmTableModel(usmUserIndex);
165     usmUserEntry = new DefaultMOTable(usmUserEntryOID, usmUserIndex,
166                                       usmUserColumns, usmUserTableModel);
167     ((AutonomousType)
168      usmUserColumns[colUsmUserAuthProtocol]).addMOValueValidationListener(this);
169     ((AutonomousType)
170      usmUserColumns[colUsmUserPrivProtocol]).addMOValueValidationListener(this);
171     ((UsmRowPointer)
172      usmUserColumns[colUsmUserCloneFrom]).setTargetTable(usmUserEntry);
173   }
174
175   private void createUsmStats() {
176     usmStats = new MOScalar[usmStatOIDs.length];
177     for (int i=0; i<usmStats.length; i++) {
178       usmStats[i] = new MOScalar(usmStatOIDs[i], MOAccessImpl.ACCESS_READ_ONLY,
179                                  new Counter32(0));
180     }
181   }
182
183   public void registerMOs(MOServer server, OctetString context) throws
184       DuplicateRegistrationException {
185     for (int i=0; i < usmStats.length; i++) {
186       server.register(usmStats[i], context);
187     }
188     server.register(usmUserSpinLock, context);
189     server.register(usmUserEntry, context);
190   }
191
192   public void unregisterMOs(MOServer server, OctetString context) {
193     for (int i=0; i < usmStats.length; i++) {
194       server.unregister(usmStats[i], context);
195     }
196     server.unregister(usmUserSpinLock, context);
197     server.unregister(usmUserEntry, context);
198   }
199
200   public void incrementCounter(CounterEvent event) {
201     if ((event.getOid().startsWith(usmStatsPrefix)) &&
202         (event.getOid().size() > usmStatsPrefix.size())) {
203       Counter32 current = (Counter32)
204            usmStats[event.getOid().get(usmStatsPrefix.size())-1].getValue();
205       current.increment();
206       event.setCurrentValue((Counter32)current.clone());
207     }
208   }
209
210
211   public void validate(MOValueValidationEvent validationEvent) {
212     if (validationEvent.getSource() instanceof MOColumn) {
213       MOColumn col = (MOColumn) validationEvent.getSource();
214       switch (col.getColumnID()-4) {
215         case colUsmUserAuthProtocol: {
216           OID value = (OID)validationEvent.getNewValue();
217           if (!noAuthProtocol.equals(value)) {
218             AuthenticationProtocol authProtocol =
219                 SecurityProtocols.getInstance().
220                 getAuthenticationProtocol((OID) validationEvent.getNewValue());
221             if (authProtocol == null) {
222               validationEvent.setValidationStatus(SnmpConstants.
223                                                   SNMP_ERROR_WRONG_VALUE);
224             }
225           }
226           break;
227         }
228         case colUsmUserPrivProtocol: {
229           OID value = (OID)validationEvent.getNewValue();
230           if (!noPrivProtocol.equals(value)) {
231             PrivacyProtocol privProtocol =
232                 SecurityProtocols.getInstance().getPrivacyProtocol(value);
233             if (privProtocol == null) {
234               validationEvent.setValidationStatus(SnmpConstants.
235                                                   SNMP_ERROR_WRONG_VALUE);
236             }
237           }
238           break;
239         }
240       }
241     }
242   }
243
244   private Variable[] getValuesFromUsmUser(UsmUserEntry user) {
245     Variable[] row = new Variable[usmUserEntry.getColumnCount()];
246     int n = 0;
247     row[n++] = user.getUsmUser().getSecurityName();
248     row[n++] = null;
249     row[n++] = user.getUsmUser().getAuthenticationProtocol();
250     row[n++] = null;
251     row[n++] = null;
252     row[n++] = user.getUsmUser().getPrivacyProtocol();
253     row[n++] = null;
254     row[n++] = null;
255     row[n++] = new OctetString();
256     row[n++] = new Integer32(StorageType.nonVolatile);
257     row[n++] = new Integer32(RowStatus.active);
258     return row;
259   }
260
261   private OID createIndex(OctetString engineID, OctetString userName) {
262     if (engineID.length() == 0) {
263       engineID = usm.getLocalEngineID();
264     }
265     OID index = engineID.toSubIndex(false);
266     index.append(userName.toSubIndex(false));
267     return index;
268   }
269
270   public void usmUserChange(UsmUserEvent event) {
271     switch (event.getType()) {
272       case UsmUserEvent.USER_ADDED: {
273         Variable[] values = getValuesFromUsmUser(event.getUser());
274         OID index = createIndex(event.getUser().getEngineID(),
275                                 event.getUser().getUserName());
276         MOMutableRow2PC row = (MOMutableRow2PC)
277             usmUserTableModel.createRow(index, values);
278         usmUserTableModel.addRow(row);
279         break;
280       }
281       case UsmUserEvent.USER_REMOVED: {
282         OID index = createIndex(event.getUser().getEngineID(),
283                                 event.getUser().getUserName());
284         usmUserTableModel.removeRow(index);
285       }
286     }
287   }
288
289   private static byte[] getKey(UsmUserEntry entry, int authVsPriv) {
290     return (authVsPriv == 0) ?
291         entry.getAuthenticationKey() :
292         entry.getPrivacyKey();
293   }
294
295   public class UsmTableModel extends DefaultMOMutableTableModel {
296
297     private MOTableIndex indexDef;
298
299     public UsmTableModel(MOTableIndex indexDef) {
300       super();
301       this.indexDef = indexDef;
302     }
303
304     public MOTableRow createRow(OID index, Variable[] values) {
305       return new UsmTableRow(this, index, values);
306     }
307
308     public MOTableIndex getIndexDef() {
309       return indexDef;
310     }
311   }
312
313   private static boolean isKeyChanged(MOTableRow changeSet, int keyChangeColumn) {
314     OctetString value = (OctetString) changeSet.getValue(keyChangeColumn);
315     if ((value != null) && (value.length() > 0)) {
316       return true;
317     }
318     return false;
319   }
320
321   private static boolean isKeyChanged(MOTableRow changeSet) {
322     return ((isKeyChanged(changeSet, colUsmUserOwnAuthKeyChange)) ||
323             (isKeyChanged(changeSet, colUsmUserAuthKeyChange)) ||
324             (isKeyChanged(changeSet, colUsmUserOwnPrivKeyChange)) ||
325             (isKeyChanged(changeSet, colUsmUserPrivKeyChange)));
326   }
327
328   public class UsmTableRow extends DefaultMOMutableRow2PC {
329
330     private UsmTableModel tableModel;
331     private boolean cloned = false;
332
333     public UsmTableRow(UsmTableModel model, OID index, Variable[] values) {
334       super(index, values);
335       this.tableModel = model;
336     }
337
338     public void setCloned(boolean cloned) {
339       this.cloned = cloned;
340     }
341
342     public boolean isCloned() {
343       return cloned;
344     }
345
346     public MOTableIndex getIndexDef() {
347       return tableModel.getIndexDef();
348     }
349
350     public AuthenticationProtocol getAuthProtocol(MOTableRow changeSet)
351     {
352       OID authOID = getAuthProtocolOID(changeSet);
353       AuthenticationProtocol a =
354           securityProtocols.getAuthenticationProtocol(authOID);
355       return a;
356     }
357
358     public PrivacyProtocol getPrivProtocol(MOTableRow changeSet)
359     {
360       OID privOID = getPrivProtocolOID(changeSet);
361       PrivacyProtocol p =
362           securityProtocols.getPrivacyProtocol(privOID);
363       return p;
364     }
365
366     public OID getPrivProtocolOID(MOTableRow preparedChanges)
367     {
368       OID privID = null;
369       if (preparedChanges.getValue(colUsmUserCloneFrom) == null) {
370         privID = (OID) preparedChanges.getValue(colUsmUserPrivProtocol);
371       }
372       if (privID == null) {
373         privID = (OID) getValue(colUsmUserPrivProtocol);
374       }
375       return privID;
376     }
377
378     public void prepare(SubRequest subRequest,
379                         MOTableRow preparedChanges, int column) {
380       switch (column) {
381         case colUsmUserAuthProtocol: {
382           OID authProtocol = (OID) subRequest.getVariableBinding().getVariable();
383           if (!authProtocol.equals(noAuthProtocol)) {
384             subRequest.getStatus().setErrorStatus(PDU.inconsistentValue);
385           }
386           else {
387             OID privProtocol = null;
388             Variable privProtocolVariable =
389                 preparedChanges.getValue(colUsmUserPrivProtocol);
390             if (privProtocolVariable instanceof OID) {
391               privProtocol = (OID) privProtocolVariable;
392             }
393             else if (privProtocolVariable == null) {
394               privProtocol = (OID) getValue(colUsmUserPrivProtocol);
395             }
396             if ((privProtocol == null) ||
397                 (!privProtocol.equals(noPrivProtocol))) {
398               subRequest.getStatus().setErrorStatus(PDU.inconsistentValue);
399             }
400           }
401           break;
402         }
403         case colUsmUserPrivProtocol: {
404           OID privProtocol = (OID)subRequest.getVariableBinding().getVariable();
405           if (!privProtocol.equals(noPrivProtocol)) {
406             subRequest.getStatus().setErrorStatus(PDU.inconsistentValue);
407           }
408           break;
409         }
410       }
411     }
412
413     private OID getCloneFromIndex(MOTableRow changeSet) {
414       OID cloneFrom = (OID) changeSet.getValue(colUsmUserCloneFrom);
415       if (cloneFrom == null) {
416         cloneFrom = (OID) getValue(colUsmUserCloneFrom);
417       }
418       if ((cloneFrom == null) || (cloneFrom.size() <= usmUserEntryOID.size())) {
419         return null;
420       }
421       return new OID(cloneFrom.getValue(), usmUserEntryOID.size()+1,
422                      cloneFrom.size() - (usmUserEntryOID.size()+1));
423     }
424
425     public synchronized void commitRow(SubRequest subRequest,
426                                        MOTableRow changeSet) {
427       if (subRequest.hasError()) {
428         return;
429       }
430       Variable[] indexValues = getIndexDef().getIndexValues(getIndex());
431       OctetString engineID = (OctetString) indexValues[0];
432       OctetString userName = (OctetString) indexValues[1];
433       UsmUserEntry oldUserEntry;
434       OID cloneFromUserIndex = getCloneFromIndex(changeSet);
435       if (cloneFromUserIndex != null) {
436         Variable[] cloneFromIndexValues =
437             getIndexDef().getIndexValues(cloneFromUserIndex);
438         OctetString cloneFromEngineID = (OctetString) cloneFromIndexValues[0];
439         OctetString cloneFromUserName = (OctetString) cloneFromIndexValues[1];
440
441         oldUserEntry = usm.getUser(cloneFromEngineID, cloneFromUserName);
442         // assign protocols
443
if (oldUserEntry != null) {
444           setValue(colUsmUserAuthProtocol,
445                    oldUserEntry.getUsmUser().getAuthenticationProtocol());
446           setValue(colUsmUserPrivProtocol,
447                    oldUserEntry.getUsmUser().getPrivacyProtocol());
448         }
449       }
450       else {
451         oldUserEntry = usm.getUser(engineID, userName);
452       }
453       Integer32 newStatus =
454           (Integer32)changeSet.getValue(colUsmUserStatus);
455       if (((newStatus != null) &&
456            ((newStatus.getValue() == RowStatus.active) ||
457             (newStatus.getValue() == RowStatus.createAndGo))) ||
458           ((getValue(colUsmUserStatus) != null) &&
459            (((Integer32)getValue(colUsmUserStatus)).getValue() == RowStatus.active) &&
460            (isKeyChanged(changeSet)))) {
461         if (cloneFromUserIndex != null) {
462           // save undo value
463
setUserObject(oldUserEntry);
464         }
465         if (oldUserEntry == null) {
466           subRequest.getStatus().setErrorStatus(PDU.commitFailed);
467           return;
468         }
469         OctetString[] newKeys = new OctetString[2];
470         OctetString[] oldKeys = new OctetString[2];
471
472         AuthenticationProtocol a = getAuthProtocol(changeSet);
473         if (a != null) {
474           for (int p=0; p<2; p++) {
475             oldKeys[p] = new OctetString(getKey(oldUserEntry, p));
476             for (int i = 0; i < keyChangeColumns[p].length; i++) {
477               OctetString keyChange =
478                   (OctetString)getValue(keyChangeColumns[p][i]);
479               if ((keyChange != null) && (keyChange.length() > 0)) {
480                 int keyLength = a.getDigestLength();
481
482
483                 if (p == 1) {
484                   // privacy protocol key change
485
PrivacyProtocol privProtocol = getPrivProtocol(changeSet);
486                   keyLength =
487                       Math.min(keyLength, privProtocol.getMaxKeyLength());
488                 }
489                 newKeys[p] =
490                     KeyChange.changeKey(a, oldKeys[p],
491                                         keyChange, keyLength);
492                 break; // only one key change per protocol
493
}
494             }
495           }
496         }
497         UsmUserEntry newEntry =
498             new UsmUserEntry(engineID.getValue(), userName,
499                              getAuthProtocolOID(changeSet),
500                              (newKeys[0] == null) ?
501                              ((oldKeys[0] == null) ? null : oldKeys[0].getValue())
502                              : newKeys[0].getValue(),
503                              getPrivProtocolOID(changeSet),
504                              (newKeys[1] == null) ?
505                              ((oldKeys[1] == null) ? null : oldKeys[1].getValue())
506                              : newKeys[1].getValue());
507         usm.updateUser(newEntry);
508         setValue(colUsmUserCloneFrom, null);
509         setValue(colUsmUserAuthKeyChange, null);
510         setValue(colUsmUserOwnAuthKeyChange, null);
511         setValue(colUsmUserPrivKeyChange, null);
512         setValue(colUsmUserOwnPrivKeyChange, null);
513       }
514       if (newStatus != null) {
515         switch (newStatus.getValue()) {
516           case RowStatus.createAndWait:
517           case RowStatus.createAndGo: {
518             setValue(colUsmUserSecurityName, userName);
519             break;
520           }
521         }
522       }
523     }
524
525     public OID getAuthProtocolOID(MOTableRow changeSet) {
526       OID authID = null;
527       if (changeSet.getValue(colUsmUserCloneFrom) == null) {
528         authID = (OID) changeSet.getValue(colUsmUserAuthProtocol);
529       }
530       if (authID == null) {
531         authID = (OID) getValue(colUsmUserAuthProtocol);
532       }
533       return authID;
534     }
535
536     public void cleanupRow(SubRequest subRequest, ChangeSet changeSet) {
537       setUserObject(null);
538     }
539
540     public void undoRow(SubRequest subRequest, ChangeSet changeSet) {
541       if (getUserObject() != null) {
542         usm.updateUser((UsmUserEntry)getUserObject());
543       }
544     }
545
546   }
547
548   class UsmRowPointer extends RowPointer {
549
550     public UsmRowPointer(int columnID, MOAccess access, OID defaultValue,
551                          boolean mutableInService) {
552       super(columnID, access, defaultValue, mutableInService);
553     }
554
555
556
557     public void prepare(SubRequest subRequest, MOTableRow row,
558                         MOTableRow changeSet, int column) {
559       super.prepare(subRequest, row, changeSet, column);
560       if (!subRequest.hasError()) {
561         OID rowPointer = (OID) subRequest.getVariableBinding().getVariable();
562         MOTableCellInfo cell = getTargetTable().getCellInfo(rowPointer);
563         if (cell.getIndex().equals(row.getIndex())) {
564           // cannot clone from self
565
subRequest.getStatus().setErrorStatus(PDU.inconsistentValue);
566         }
567       }
568     }
569
570     public Variable getValue(MOTableRow row, int column) {
571       return SnmpConstants.zeroDotZero;
572     }
573   }
574
575   public void rowStatusChanged(RowStatusEvent event) {
576   }
577 }
578
Popular Tags