blob: 81d4a2102e994db7f5a2898374d334aa8468a986 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package com.sun.jmx.snmp;
26
27// java imports
28//
29import java.util.Vector;
30import java.util.logging.Level;
31import java.net.InetAddress;
32
33// import debug stuff
34//
35import static com.sun.jmx.defaults.JmxProperties.SNMP_LOGGER;
36import com.sun.jmx.snmp.internal.SnmpMsgProcessingSubSystem;
37import com.sun.jmx.snmp.internal.SnmpSecurityModel;
38import com.sun.jmx.snmp.internal.SnmpDecryptedPdu;
39import com.sun.jmx.snmp.internal.SnmpSecurityCache;
40
41import com.sun.jmx.snmp.SnmpMsg;
42import com.sun.jmx.snmp.SnmpPdu;
43import com.sun.jmx.snmp.SnmpStatusException;
44import com.sun.jmx.snmp.SnmpTooBigException;
45import com.sun.jmx.snmp.SnmpScopedPduBulk;
46import com.sun.jmx.snmp.BerException;
47import com.sun.jmx.snmp.SnmpScopedPduRequest;
48import com.sun.jmx.snmp.BerDecoder;
49import com.sun.jmx.snmp.SnmpDefinitions;
50import com.sun.jmx.snmp.SnmpEngineId;
51import com.sun.jmx.snmp.SnmpScopedPduPacket;
52import com.sun.jmx.snmp.BerEncoder;
53import com.sun.jmx.snmp.SnmpPduRequestType;
54import com.sun.jmx.snmp.SnmpPduBulkType;
55
56/**
57 * Is a partially decoded representation of an SNMP V3 packet.
58 * <P>
59 * This class can be used when developing customized manager or agent.
60 * <P>
61 * The <CODE>SnmpV3Message</CODE> class is directly mapped onto the
62 * message syntax defined in RFC 2572.
63 * <BLOCKQUOTE>
64 * <PRE>
65 * SNMPv3Message ::= SEQUENCE {
66 * msgVersion INTEGER ( 0 .. 2147483647 ),
67 * -- administrative parameters
68 * msgGlobalData HeaderData,
69 * -- security model-specific parameters
70 * -- format defined by Security Model
71 * msgSecurityParameters OCTET STRING,
72 * msgData ScopedPduData
73 * }
74 * HeaderData ::= SEQUENCE {
75 * msgID INTEGER (0..2147483647),
76 * msgMaxSize INTEGER (484..2147483647),
77 *
78 * msgFlags OCTET STRING (SIZE(1)),
79 * -- .... ...1 authFlag
80 * -- .... ..1. privFlag
81 * -- .... .1.. reportableFlag
82 * -- Please observe:
83 * -- .... ..00 is OK, means noAuthNoPriv
84 * -- .... ..01 is OK, means authNoPriv
85 * -- .... ..10 reserved, must NOT be used.
86 * -- .... ..11 is OK, means authPriv
87 *
88 * msgSecurityModel INTEGER (1..2147483647)
89 * }
90 * </BLOCKQUOTE>
91 * </PRE>
92 * <p><b>This API is a Sun Microsystems internal API and is subject
93 * to change without notice.</b></p>
94 * @since 1.5
95 */
96public class SnmpV3Message extends SnmpMsg {
97
98 /**
99 * Message identifier.
100 */
101 public int msgId = 0;
102
103 /**
104 * Message max size the pdu sender can deal with.
105 */
106 public int msgMaxSize = 0;
107 /**
108 * Message flags. Reportable flag and security level.</P>
109 *<PRE>
110 * -- .... ...1 authFlag
111 * -- .... ..1. privFlag
112 * -- .... .1.. reportableFlag
113 * -- Please observe:
114 * -- .... ..00 is OK, means noAuthNoPriv
115 * -- .... ..01 is OK, means authNoPriv
116 * -- .... ..10 reserved, must NOT be used.
117 * -- .... ..11 is OK, means authPriv
118 *</PRE>
119 */
120 public byte msgFlags = 0;
121 /**
122 * The security model the security sub system MUST use in order to deal with this pdu (eg: User based Security Model Id = 3).
123 */
124 public int msgSecurityModel = 0;
125 /**
126 * The unmarshalled security parameters.
127 */
128 public byte[] msgSecurityParameters = null;
129 /**
130 * The context engine Id in which the pdu must be handled (Generaly the local engine Id).
131 */
132 public byte[] contextEngineId = null;
133 /**
134 * The context name in which the OID has to be interpreted.
135 */
136 public byte[] contextName = null;
137 /** The encrypted form of the scoped pdu (Only relevant when dealing with privacy).
138 */
139 public byte[] encryptedPdu = null;
140
141 /**
142 * Constructor.
143 *
144 */
145 public SnmpV3Message() {
146 }
147 /**
148 * Encodes this message and puts the result in the specified byte array.
149 * For internal use only.
150 *
151 * @param outputBytes An array to receive the resulting encoding.
152 *
153 * @exception ArrayIndexOutOfBoundsException If the result does not fit
154 * into the specified array.
155 */
156 public int encodeMessage(byte[] outputBytes)
157 throws SnmpTooBigException {
158 int encodingLength = 0;
159 if (SNMP_LOGGER.isLoggable(Level.FINER)) {
160 SNMP_LOGGER.logp(Level.FINER, SnmpV3Message.class.getName(),
161 "encodeMessage",
162 "Can't encode directly V3Message! Need a SecuritySubSystem");
163 }
164 throw new IllegalArgumentException("Can't encode");
165 }
166
167 /**
168 * Decodes the specified bytes and initializes this message.
169 * For internal use only.
170 *
171 * @param inputBytes The bytes to be decoded.
172 *
173 * @exception SnmpStatusException If the specified bytes are not a valid encoding.
174 */
175 public void decodeMessage(byte[] inputBytes, int byteCount)
176 throws SnmpStatusException {
177
178 try {
179 BerDecoder bdec = new BerDecoder(inputBytes);
180 bdec.openSequence();
181 version = bdec.fetchInteger();
182 bdec.openSequence();
183 msgId = bdec.fetchInteger();
184 msgMaxSize = bdec.fetchInteger();
185 msgFlags = bdec.fetchOctetString()[0];
186 msgSecurityModel =bdec.fetchInteger();
187 bdec.closeSequence();
188 msgSecurityParameters = bdec.fetchOctetString();
189 if( (msgFlags & SnmpDefinitions.privMask) == 0 ) {
190 bdec.openSequence();
191 contextEngineId = bdec.fetchOctetString();
192 contextName = bdec.fetchOctetString();
193 data = bdec.fetchAny();
194 dataLength = data.length;
195 bdec.closeSequence();
196 }
197 else {
198 encryptedPdu = bdec.fetchOctetString();
199 }
200 bdec.closeSequence() ;
201 }
202 catch(BerException x) {
203 x.printStackTrace();
204 throw new SnmpStatusException("Invalid encoding") ;
205 }
206
207 if (SNMP_LOGGER.isLoggable(Level.FINER)) {
208 final StringBuilder strb = new StringBuilder()
209 .append("Unmarshalled message : \n")
210 .append("version : ").append(version)
211 .append("\n")
212 .append("msgId : ").append(msgId)
213 .append("\n")
214 .append("msgMaxSize : ").append(msgMaxSize)
215 .append("\n")
216 .append("msgFlags : ").append(msgFlags)
217 .append("\n")
218 .append("msgSecurityModel : ").append(msgSecurityModel)
219 .append("\n")
220 .append("contextEngineId : ").append(contextEngineId == null ? null :
221 SnmpEngineId.createEngineId(contextEngineId))
222 .append("\n")
223 .append("contextName : ").append(contextName)
224 .append("\n")
225 .append("data : ").append(data)
226 .append("\n")
227 .append("dat len : ").append((data == null) ? 0 : data.length)
228 .append("\n")
229 .append("encryptedPdu : ").append(encryptedPdu)
230 .append("\n");
231 SNMP_LOGGER.logp(Level.FINER, SnmpV3Message.class.getName(),
232 "decodeMessage", strb.toString());
233 }
234 }
235
236 /**
237 * Returns the associated request Id.
238 * @param data The flat message.
239 * @return The request Id.
240 */
241 public int getRequestId(byte[] data) throws SnmpStatusException {
242 BerDecoder bdec = null;
243 int msgId = 0;
244 try {
245 bdec = new BerDecoder(data);
246 bdec.openSequence();
247 bdec.fetchInteger();
248 bdec.openSequence();
249 msgId = bdec.fetchInteger();
250 }catch(BerException x) {
251 throw new SnmpStatusException("Invalid encoding") ;
252 }
253 try {
254 bdec.closeSequence();
255 }
256 catch(BerException x) {
257 }
258
259 return msgId;
260 }
261
262 /**
263 * Initializes this message with the specified <CODE>pdu</CODE>.
264 * <P>
265 * This method initializes the data field with an array of
266 * <CODE>maxDataLength</CODE> bytes. It encodes the <CODE>pdu</CODE>.
267 * The resulting encoding is stored in the data field
268 * and the length of the encoding is stored in <CODE>dataLength</CODE>.
269 * <p>
270 * If the encoding length exceeds <CODE>maxDataLength</CODE>,
271 * the method throws an exception.
272 *
273 * @param p The PDU to be encoded.
274 * @param maxDataLength The maximum length permitted for the data field.
275 *
276 * @exception SnmpStatusException If the specified <CODE>pdu</CODE>
277 * is not valid.
278 * @exception SnmpTooBigException If the resulting encoding does not fit
279 * into <CODE>maxDataLength</CODE> bytes.
280 * @exception ArrayIndexOutOfBoundsException If the encoding exceeds
281 * <CODE>maxDataLength</CODE>.
282 */
283 public void encodeSnmpPdu(SnmpPdu p,
284 int maxDataLength)
285 throws SnmpStatusException, SnmpTooBigException {
286
287 SnmpScopedPduPacket pdu = (SnmpScopedPduPacket) p;
288
289 if (SNMP_LOGGER.isLoggable(Level.FINER)) {
290 final StringBuilder strb = new StringBuilder()
291 .append("PDU to marshall: \n")
292 .append("security parameters : ").append(pdu.securityParameters)
293 .append("\n")
294 .append("type : ").append(pdu.type)
295 .append("\n")
296 .append("version : ").append(pdu.version)
297 .append("\n")
298 .append("requestId : ").append(pdu.requestId)
299 .append("\n")
300 .append("msgId : ").append(pdu.msgId)
301 .append("\n")
302 .append("msgMaxSize : ").append(pdu.msgMaxSize)
303 .append("\n")
304 .append("msgFlags : ").append(pdu.msgFlags)
305 .append("\n")
306 .append("msgSecurityModel : ").append(pdu.msgSecurityModel)
307 .append("\n")
308 .append("contextEngineId : ").append(pdu.contextEngineId)
309 .append("\n")
310 .append("contextName : ").append(pdu.contextName)
311 .append("\n");
312 SNMP_LOGGER.logp(Level.FINER, SnmpV3Message.class.getName(),
313 "encodeSnmpPdu", strb.toString());
314 }
315
316 version = pdu.version;
317 address = pdu.address;
318 port = pdu.port;
319 msgId = pdu.msgId;
320 msgMaxSize = pdu.msgMaxSize;
321 msgFlags = pdu.msgFlags;
322 msgSecurityModel = pdu.msgSecurityModel;
323
324 contextEngineId = pdu.contextEngineId;
325 contextName = pdu.contextName;
326
327 securityParameters = pdu.securityParameters;
328
329 //
330 // Allocate the array to receive the encoding.
331 //
332 data = new byte[maxDataLength];
333
334 //
335 // Encode the pdu
336 // Reminder: BerEncoder does backward encoding !
337 //
338
339 try {
340 BerEncoder benc = new BerEncoder(data) ;
341 benc.openSequence() ;
342 encodeVarBindList(benc, pdu.varBindList) ;
343
344 switch(pdu.type) {
345
346 case pduGetRequestPdu :
347 case pduGetNextRequestPdu :
348 case pduInformRequestPdu :
349 case pduGetResponsePdu :
350 case pduSetRequestPdu :
351 case pduV2TrapPdu :
352 case pduReportPdu :
353 SnmpPduRequestType reqPdu = (SnmpPduRequestType) pdu;
354 benc.putInteger(reqPdu.getErrorIndex());
355 benc.putInteger(reqPdu.getErrorStatus());
356 benc.putInteger(pdu.requestId);
357 break;
358
359 case pduGetBulkRequestPdu :
360 SnmpPduBulkType bulkPdu = (SnmpPduBulkType) pdu;
361 benc.putInteger(bulkPdu.getMaxRepetitions());
362 benc.putInteger(bulkPdu.getNonRepeaters());
363 benc.putInteger(pdu.requestId);
364 break ;
365
366 default:
367 throw new SnmpStatusException("Invalid pdu type " + String.valueOf(pdu.type)) ;
368 }
369 benc.closeSequence(pdu.type) ;
370 dataLength = benc.trim() ;
371 }
372 catch(ArrayIndexOutOfBoundsException x) {
373 throw new SnmpTooBigException() ;
374 }
375 }
376
377
378 /**
379 * Gets the PDU encoded in this message.
380 * <P>
381 * This method decodes the data field and returns the resulting PDU.
382 *
383 * @return The resulting PDU.
384 * @exception SnmpStatusException If the encoding is not valid.
385 */
386
387 public SnmpPdu decodeSnmpPdu()
388 throws SnmpStatusException {
389
390 SnmpScopedPduPacket pdu = null;
391
392 BerDecoder bdec = new BerDecoder(data) ;
393 try {
394 int type = bdec.getTag() ;
395 bdec.openSequence(type) ;
396 switch(type) {
397
398 case pduGetRequestPdu :
399 case pduGetNextRequestPdu :
400 case pduInformRequestPdu :
401 case pduGetResponsePdu :
402 case pduSetRequestPdu :
403 case pduV2TrapPdu :
404 case pduReportPdu :
405 SnmpScopedPduRequest reqPdu = new SnmpScopedPduRequest() ;
406 reqPdu.requestId = bdec.fetchInteger() ;
407 reqPdu.setErrorStatus(bdec.fetchInteger());
408 reqPdu.setErrorIndex(bdec.fetchInteger());
409 pdu = reqPdu ;
410 break ;
411
412 case pduGetBulkRequestPdu :
413 SnmpScopedPduBulk bulkPdu = new SnmpScopedPduBulk() ;
414 bulkPdu.requestId = bdec.fetchInteger() ;
415 bulkPdu.setNonRepeaters(bdec.fetchInteger());
416 bulkPdu.setMaxRepetitions(bdec.fetchInteger());
417 pdu = bulkPdu ;
418 break ;
419 default:
420 throw new SnmpStatusException(snmpRspWrongEncoding) ;
421 }
422 pdu.type = type;
423 pdu.varBindList = decodeVarBindList(bdec);
424 bdec.closeSequence() ;
425 } catch(BerException e) {
426 if (SNMP_LOGGER.isLoggable(Level.FINEST)) {
427 SNMP_LOGGER.logp(Level.FINEST, SnmpV3Message.class.getName(),
428 "decodeSnmpPdu", "BerException", e);
429 }
430 throw new SnmpStatusException(snmpRspWrongEncoding);
431 }
432
433 //
434 // The easy work.
435 //
436 pdu.address = address;
437 pdu.port = port;
438 pdu.msgFlags = msgFlags;
439 pdu.version = version;
440 pdu.msgId = msgId;
441 pdu.msgMaxSize = msgMaxSize;
442 pdu.msgSecurityModel = msgSecurityModel;
443 pdu.contextEngineId = contextEngineId;
444 pdu.contextName = contextName;
445
446 pdu.securityParameters = securityParameters;
447
448 if (SNMP_LOGGER.isLoggable(Level.FINER)) {
449 final StringBuilder strb = new StringBuilder()
450 .append("Unmarshalled PDU : \n")
451 .append("type : ").append(pdu.type)
452 .append("\n")
453 .append("version : ").append(pdu.version)
454 .append("\n")
455 .append("requestId : ").append(pdu.requestId)
456 .append("\n")
457 .append("msgId : ").append(pdu.msgId)
458 .append("\n")
459 .append("msgMaxSize : ").append(pdu.msgMaxSize)
460 .append("\n")
461 .append("msgFlags : ").append(pdu.msgFlags)
462 .append("\n")
463 .append("msgSecurityModel : ").append(pdu.msgSecurityModel)
464 .append("\n")
465 .append("contextEngineId : ").append(pdu.contextEngineId)
466 .append("\n")
467 .append("contextName : ").append(pdu.contextName)
468 .append("\n");
469 SNMP_LOGGER.logp(Level.FINER, SnmpV3Message.class.getName(),
470 "decodeSnmpPdu", strb.toString());
471 }
472 return pdu ;
473 }
474
475 /**
476 * Dumps this message in a string.
477 *
478 * @return The string containing the dump.
479 */
480 public String printMessage() {
481 StringBuffer sb = new StringBuffer();
482 sb.append("msgId : " + msgId + "\n");
483 sb.append("msgMaxSize : " + msgMaxSize + "\n");
484 sb.append("msgFlags : " + msgFlags + "\n");
485 sb.append("msgSecurityModel : " + msgSecurityModel + "\n");
486
487 if (contextEngineId == null) {
488 sb.append("contextEngineId : null");
489 }
490 else {
491 sb.append("contextEngineId : {\n");
492 sb.append(dumpHexBuffer(contextEngineId,
493 0,
494 contextEngineId.length));
495 sb.append("\n}\n");
496 }
497
498 if (contextName == null) {
499 sb.append("contextName : null");
500 }
501 else {
502 sb.append("contextName : {\n");
503 sb.append(dumpHexBuffer(contextName,
504 0,
505 contextName.length));
506 sb.append("\n}\n");
507 }
508 return sb.append(super.printMessage()).toString();
509 }
510
511}