1 /* 2 * Copyright (c) 2001, 2006, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.jmx.snmp; 26 27 // java imports 28 // 29 import java.util.Vector; 30 import java.util.logging.Level; 31 import java.net.InetAddress; 32 33 // import debug stuff 34 // 35 import static com.sun.jmx.defaults.JmxProperties.SNMP_LOGGER; 36 import com.sun.jmx.snmp.internal.SnmpMsgProcessingSubSystem; 37 import com.sun.jmx.snmp.internal.SnmpSecurityModel; 38 import com.sun.jmx.snmp.internal.SnmpDecryptedPdu; 39 import com.sun.jmx.snmp.internal.SnmpSecurityCache; 40 41 import com.sun.jmx.snmp.SnmpMsg; 42 import com.sun.jmx.snmp.SnmpPdu; 43 import com.sun.jmx.snmp.SnmpStatusException; 44 import com.sun.jmx.snmp.SnmpTooBigException; 45 import com.sun.jmx.snmp.SnmpScopedPduBulk; 46 import com.sun.jmx.snmp.BerException; 47 import com.sun.jmx.snmp.SnmpScopedPduRequest; 48 import com.sun.jmx.snmp.BerDecoder; 49 import com.sun.jmx.snmp.SnmpDefinitions; 50 import com.sun.jmx.snmp.SnmpEngineId; 51 import com.sun.jmx.snmp.SnmpScopedPduPacket; 52 import com.sun.jmx.snmp.BerEncoder; 53 import com.sun.jmx.snmp.SnmpPduRequestType; 54 import 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 */ 96 public 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 StringBuilder sb = new StringBuilder(); 482 sb.append("msgId : ").append(msgId).append('\n'); 483 sb.append("msgMaxSize : ").append(msgMaxSize).append('\n'); 484 sb.append("msgFlags : ").append(msgFlags).append('\n'); 485 sb.append("msgSecurityModel : ").append(msgSecurityModel).append('\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 }